bkg-daemon-dont-break-64bit-pointers-and-handle-requests-in-order-20011102
[openafs.git] / src / afs / VNOPS / afs_vnop_read.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11  * Implements:
12  * afs_MemRead
13  * afs_PrefetchChunk
14  * afs_UFSReadFast
15  * afs_UFSRead
16  * 
17  */
18
19 #include <afsconfig.h>
20 #include "../afs/param.h"
21
22 RCSID("$Header$");
23
24 #include "../afs/sysincludes.h" /* Standard vendor system headers */
25 #include "../afs/afsincludes.h" /* Afs-based standard headers */
26 #include "../afs/afs_stats.h" /* statistics */
27 #include "../afs/afs_cbqueue.h"
28 #include "../afs/nfsclient.h"
29 #include "../afs/afs_osidnlc.h"
30
31
32 extern char afs_zeros[AFS_ZEROS];
33
34 afs_int32 maxIHint;
35 afs_int32 nihints;                           /* # of above actually in-use */
36 afs_int32 usedihint;
37
38
39 /* Imported variables */
40 extern afs_rwlock_t afs_xdcache;
41 extern unsigned char *afs_indexFlags;
42 extern afs_hyper_t *afs_indexTimes;          /* Dcache entry Access times */
43 extern afs_hyper_t afs_indexCounter;         /* Fake time for marking index */
44
45
46 /* Forward declarations */
47 void afs_PrefetchChunk(struct vcache *avc, struct dcache *adc,
48                               struct AFS_UCRED *acred, struct vrequest *areq);
49
50 afs_MemRead(avc, auio, acred, albn, abpp, noLock)
51     register struct vcache *avc;
52     struct uio *auio;
53     struct AFS_UCRED *acred;
54     daddr_t albn;
55     int noLock;
56     struct buf **abpp; 
57 {
58     afs_size_t totalLength;
59     afs_size_t transferLength;
60     afs_size_t filePos;
61     afs_size_t offset, len, tlen;
62     afs_int32 trimlen;
63     struct dcache *tdc=0;
64     afs_int32 error, trybusy=1;
65     struct uio tuio;
66     struct iovec *tvec;
67     char *tfile;
68     afs_int32 code;
69     struct vrequest treq;
70
71     AFS_STATCNT(afs_MemRead);
72     if (avc->vc_error)
73         return EIO;
74
75     /* check that we have the latest status info in the vnode cache */
76     if (code = afs_InitReq(&treq, acred)) return code;
77     if (!noLock) {
78         code = afs_VerifyVCache(avc, &treq);
79         if (code) {
80           code = afs_CheckCode(code, &treq, 8); /* failed to get it */
81           return code;
82         }
83     }
84
85 #ifndef AFS_VM_RDWR_ENV
86     if (AFS_NFSXLATORREQ(acred)) {
87         if (!afs_AccessOK(avc, PRSFS_READ, &treq,
88                           CHECK_MODE_BITS|CMB_ALLOW_EXEC_AS_READ)) {
89             return afs_CheckCode(EACCES, &treq, 9);
90         }
91     }
92 #endif
93
94     tvec = (struct iovec *) osi_AllocSmallSpace(sizeof(struct iovec));
95     totalLength = auio->afsio_resid;
96     filePos = auio->afsio_offset;
97     afs_Trace4(afs_iclSetp, CM_TRACE_READ, ICL_TYPE_POINTER, avc, 
98                 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(filePos),
99                 ICL_TYPE_INT32, totalLength,
100                 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length));
101     error = 0;
102     transferLength = 0;
103     if (!noLock)
104         ObtainReadLock(&avc->lock);
105 #if     defined(AFS_TEXT_ENV) && !defined(AFS_VM_RDWR_ENV)
106     if (avc->flushDV.high == AFS_MAXDV && avc->flushDV.low == AFS_MAXDV) {
107         hset(avc->flushDV, avc->m.DataVersion);
108     }
109 #endif
110     while (totalLength > 0) {
111         /* read all of the cached info */
112         if (filePos >= avc->m.Length) break;    /* all done */
113         if (noLock) {
114             if (tdc) afs_PutDCache(tdc);
115             tdc = afs_FindDCache(avc, filePos);
116             if (tdc) {
117                 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
118                 len = tdc->f.chunkBytes - offset;
119             }
120         } else {
121             /* a tricky question: does the presence of the DFFetching flag
122                mean that we're fetching the latest version of the file?  No.
123                The server could update the file as soon as the fetch responsible
124                for the setting of the DFFetching flag completes.
125             
126                However, the presence of the DFFetching flag (visible under a
127                read lock since it is set and cleared only under a write lock)
128                means that we're fetching as good a version as was known to this
129                client at the time of the last call to afs_VerifyVCache, since
130                the latter updates the stat cache's m.DataVersion field under a
131                write lock, and from the time that the DFFetching flag goes on
132                (before the fetch starts), to the time it goes off (after the
133                fetch completes), afs_GetDCache keeps at least a read lock
134                (actually it keeps an S lock) on the cache entry.
135             
136                This means that if the DFFetching flag is set, we can use that
137                data for any reads that must come from the current version of
138                the file (current == m.DataVersion).
139              
140                Another way of looking at this same point is this: if we're
141                fetching some data and then try do an afs_VerifyVCache, the
142                VerifyVCache operation will not complete until after the
143                DFFetching flag is turned off and the dcache entry's f.versionNo
144                field is updated.
145              
146                Note, by the way, that if DFFetching is set,
147                m.DataVersion > f.versionNo (the latter is not updated until
148                after the fetch completes).
149              */
150             if (tdc) afs_PutDCache(tdc);        /* before reusing tdc */
151             tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 2);
152             /* now, first try to start transfer, if we'll need the data.  If
153              * data already coming, we don't need to do this, obviously.  Type
154              * 2 requests never return a null dcache entry, btw.
155              */
156             if (!(tdc->flags & DFFetching)
157                 && !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
158                 /* have cache entry, it is not coming in now,
159                  * and we'll need new data */
160 tagain:
161                 if (trybusy && !afs_BBusy()) {
162                     struct brequest *bp;
163                     /* daemon is not busy */
164                     if (!(tdc->flags & DFFetchReq)) {
165                         /* start the daemon (may already be running, however) */
166                         tdc->flags |= DFFetchReq;
167                         bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
168                                         (afs_size_t)filePos, (afs_size_t) 0,
169                                         tdc);
170                         if (!bp) {
171                             tdc->flags &= ~DFFetchReq;
172                             trybusy = 0;        /* Avoid bkg daemon since they're too busy */
173                             goto tagain;
174                         }
175                         /* don't use bp pointer! */
176                     }
177                     while (tdc->flags & DFFetchReq) {
178                         /* don't need waiting flag on this one */
179                         ReleaseReadLock(&avc->lock);
180                         afs_osi_Sleep(&tdc->validPos);
181                         ObtainReadLock(&avc->lock);
182                     }
183                 }
184             }
185             /* now data may have started flowing in (if DFFetching is on).  If
186              * data is now streaming in, then wait for some interesting stuff. */
187             while ((tdc->flags & DFFetching) && tdc->validPos <= filePos) {
188                 /* too early: wait for DFFetching flag to vanish, or data to appear */
189                 tdc->flags |= DFWaiting;
190                 ReleaseReadLock(&avc->lock);
191                 afs_osi_Sleep(&tdc->validPos);
192                 ObtainReadLock(&avc->lock);
193             }
194             /* fetching flag gone, data is here, or we never tried (BBusy for instance) */
195             if (tdc->flags & DFFetching) {
196                 /* still fetching, some new data is here: compute length and offset */
197                 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
198                 len = tdc->validPos - filePos;
199             }
200             else {
201                 /* no longer fetching, verify data version (avoid new GetDCache call) */
202                 if (hsame(avc->m.DataVersion, tdc->f.versionNo)) {
203                     offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
204                     len = tdc->f.chunkBytes - offset;
205                 }
206                 else {
207                     /* don't have current data, so get it below */
208                     afs_PutDCache(tdc);
209                     tdc = (struct dcache *) 0;
210                 }
211             }
212
213             if (!tdc) {
214                 ReleaseReadLock(&avc->lock);
215                 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 1);
216                 ObtainReadLock(&avc->lock);
217             }
218         }
219
220         if (!tdc) {
221             error = EIO;
222             break;
223         }
224         if (len > totalLength) len = totalLength;   /* will read len bytes */
225         if (len <= 0) { /* shouldn't get here if DFFetching is on */
226             /* read past the end of a chunk, may not be at next chunk yet, and yet
227                 also not at eof, so may have to supply fake zeros */
228             len = AFS_CHUNKTOSIZE(tdc->f.chunk) - offset; /* bytes left in chunk addr space */
229             if (len > totalLength) len = totalLength;   /* and still within xfr request */
230             tlen = avc->m.Length - offset; /* and still within file */ 
231             if (len > tlen) len = tlen;
232             if (len > AFS_ZEROS) len = sizeof(afs_zeros);   /* and in 0 buffer */
233             afsio_copy(auio, &tuio, tvec);
234             trimlen = len;
235             afsio_trim(&tuio, trimlen);
236             AFS_UIOMOVE(afs_zeros, trimlen, UIO_READ, &tuio, code);
237             if (code) {
238                 error = code;
239                 break;
240             }
241         }
242         else {
243             /* get the data from the mem cache */
244
245             /* mung uio structure to be right for this transfer */
246             afsio_copy(auio, &tuio, tvec);
247             trimlen = len;
248             afsio_trim(&tuio, trimlen);
249             tuio.afsio_offset = offset;
250
251             code = afs_MemReadUIO(tdc->f.inode, &tuio);
252
253             if (code) {
254                 error = code;
255                 break;
256             }
257         }
258         /* otherwise we've read some, fixup length, etc and continue with next seg */
259         len = len - tuio.afsio_resid; /* compute amount really transferred */
260         trimlen = len;
261         afsio_skip(auio, trimlen);          /* update input uio structure */
262         totalLength -= len;
263         transferLength += len;
264         filePos += len;
265
266         if (len <= 0) break;    /* surprise eof */
267     }   /* the whole while loop */
268
269     /* if we make it here with tdc non-zero, then it is the last chunk we
270      * dealt with, and we have to release it when we're done.  We hold on
271      * to it in case we need to do a prefetch.
272      */
273     if (tdc) {
274 #ifndef AFS_VM_RDWR_ENV
275         /* try to queue prefetch, if needed */
276         if (!(tdc->flags & DFNextStarted) && !noLock) {
277             afs_PrefetchChunk(avc, tdc, acred, &treq);
278         }
279 #endif
280         afs_PutDCache(tdc);
281     }
282     if (!noLock)
283         ReleaseReadLock(&avc->lock);
284     osi_FreeSmallSpace(tvec);
285     error = afs_CheckCode(error, &treq, 10);
286     return error;
287 }
288
289 /* called with the dcache entry triggering the fetch, the vcache entry involved,
290  * and a vrequest for the read call.  Marks the dcache entry as having already
291  * triggered a prefetch, starts the prefetch going and sets the DFFetchReq
292  * flag in the prefetched block, so that the next call to read knows to wait
293  * for the daemon to start doing things.
294  *
295  * This function must be called with the vnode at least read-locked
296  * because it plays around with dcache entries.
297  */
298 void afs_PrefetchChunk(struct vcache *avc, struct dcache *adc,
299                               struct AFS_UCRED *acred, struct vrequest *areq)
300 {
301     register struct dcache *tdc;
302     afs_size_t offset;
303     afs_size_t j1, j2;  /* junk vbls for GetDCache to trash */
304
305     offset = adc->f.chunk+1;            /* next chunk we'll need */
306     offset = AFS_CHUNKTOBASE(offset);   /* base of next chunk */
307     if (offset < avc->m.Length && !afs_BBusy()) {
308         struct brequest *bp;
309         adc->flags |= DFNextStarted;    /* we've tried to prefetch for this guy */
310         tdc = afs_GetDCache(avc, offset, areq, &j1, &j2, 2);    /* type 2 never returns 0 */
311         if (!(tdc->flags & DFFetchReq)) {
312             /* ask the daemon to do the work */
313             tdc->flags |= DFFetchReq;   /* guaranteed to be cleared by BKG or GetDCache */
314             /* last parm (1) tells bkg daemon to do an afs_PutDCache when it is done,
315              * since we don't want to wait for it to finish before doing so ourselves.
316              */
317 #ifdef  AFS_SUN5_ENVX
318             mutex_exit(&tdc->lock);
319 #endif
320              bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
321                                 (afs_size_t) offset, (afs_size_t) 1, tdc);
322             if (!bp) {
323                 /* Bkg table full; just abort non-important prefetching to avoid deadlocks */
324                 tdc->flags &= ~(DFNextStarted | DFFetchReq);
325                 afs_PutDCache(tdc);
326                 return;
327             }
328         }
329         else
330             afs_PutDCache(tdc);
331     }
332 }
333
334
335 /* if the vcache is up-to-date, and the request fits entirely into the chunk
336  * that the hint here references, then we just use it quickly, otherwise we
337  * have to call the slow read.
338  *
339  * This could be generalized in several ways to take advantage of partial 
340  * state even when all the chips don't fall the right way.  For instance,
341  * if the hint is good and the first part of the read request can be 
342  * satisfied from the chunk, then just do the read.  After the read has
343  * completed, check to see if there's more. (Chances are there won't be.)
344  * If there is more, then just call afs_UFSReadSlow and let it do the rest.
345  *
346  * For the time being, I'm ignoring quick.f, but it should be used at
347  * some future date.
348  * do this in the future avc->quick.f = tfile; but I think it
349  * has to be done under a write lock, but don't want to wait on the
350  * write lock
351  */
352     /* everywhere that a dcache can be freed (look for NULLIDX) 
353      * probably does it under a write lock on xdcache.  Need to invalidate
354      * stamp there, too.  
355      * Also need to worry about DFFetching, and IFFree, I think. */
356 static struct dcache *savedc = 0;
357
358 afs_UFSReadFast(avc, auio, acred, albn, abpp, noLock)
359     register struct vcache *avc;
360     struct uio *auio;
361     struct AFS_UCRED *acred;
362     int noLock;
363     daddr_t albn;
364     struct buf **abpp; 
365 {
366     struct vrequest treq;
367     int offDiff;
368     struct dcache *tdc;
369     struct vnode *vp;
370     struct osi_file *tfile;
371     afs_int32 code = 0;
372
373     if (!noLock)
374         ObtainReadLock(&avc->lock);  
375     ObtainReadLock(&afs_xdcache);
376
377     if ((avc->states & CStatd)                                /* up to date */
378         && (tdc = avc->quick.dc) && (tdc->index != NULLIDX) 
379         && !(afs_indexFlags[tdc->index] & IFFree))   {
380
381         tdc->refCount++;
382         ReleaseReadLock(&afs_xdcache);
383
384         if ((tdc->stamp == avc->quick.stamp)                /* hint matches */
385             && ((offDiff = (auio->afsio_offset - avc->quick.minLoc)) >= 0)
386             && (tdc->f.chunkBytes >= auio->afsio_resid + offDiff)
387             && !(tdc->flags & DFFetching)) { /* fits in chunk */
388
389             auio->afsio_offset -= avc->quick.minLoc;
390
391             afs_Trace4(afs_iclSetp, CM_TRACE_READFAST, ICL_TYPE_POINTER, avc,
392                         ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(auio->afsio_offset),
393                         ICL_TYPE_INT32, auio->afsio_resid,
394                         ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length));
395
396             tfile = (struct osi_file *)osi_UFSOpen(tdc->f.inode);
397
398 #ifdef  AFS_AIX_ENV
399 #ifdef  AFS_AIX41_ENV
400             AFS_GUNLOCK();
401             code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, auio, NULL, NULL, NULL, &afs_osi_cred);
402             AFS_GLOCK();
403 #else
404 #ifdef AFS_AIX32_ENV
405             code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, auio, NULL, NULL);
406 #else
407             code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, (off_t)&auio->afsio_offset, auio, NULL, NULL, -1);
408 #endif
409 #endif
410 #else
411 #ifdef  AFS_SUN5_ENV
412             AFS_GUNLOCK();
413             VOP_RWLOCK(tfile->vnode, 0);
414             code = VOP_READ(tfile->vnode, auio, 0, &afs_osi_cred);
415             VOP_RWUNLOCK(tfile->vnode, 0);
416             AFS_GLOCK();
417 #else
418 #if defined(AFS_SGI_ENV)
419             AFS_GUNLOCK();
420             AFS_VOP_RWLOCK(tfile->vnode, VRWLOCK_READ);
421             AFS_VOP_READ(tfile->vnode, auio, IO_ISLOCKED, &afs_osi_cred, code);
422             AFS_VOP_RWUNLOCK(tfile->vnode, VRWLOCK_READ);
423             AFS_GLOCK();
424 #else
425 #ifdef  AFS_OSF_ENV
426             auio->uio_rw = UIO_READ;
427             AFS_GUNLOCK();
428             VOP_READ(tfile->vnode, auio, 0, &afs_osi_cred, code);
429             AFS_GLOCK();
430 #else   /* AFS_OSF_ENV */
431 #if defined(AFS_HPUX100_ENV)
432             AFS_GUNLOCK();
433             code = VOP_RDWR(tfile->vnode, auio, UIO_READ, 0, &afs_osi_cred);
434             AFS_GLOCK();
435 #else
436 #if defined(AFS_LINUX20_ENV)
437             AFS_GUNLOCK();
438             code = osi_file_uio_rdwr(tfile, auio, UIO_READ);
439             AFS_GLOCK();
440 #else
441 #if defined(AFS_DARWIN_ENV)
442             AFS_GUNLOCK();
443             VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, current_proc());
444             code = VOP_READ(tfile->vnode, auio, 0, &afs_osi_cred);
445             VOP_UNLOCK(tfile->vnode, 0, current_proc());
446             AFS_GLOCK();
447 #else
448             code = VOP_RDWR(tfile->vnode, auio, UIO_READ, 0, &afs_osi_cred);
449 #endif
450 #endif
451 #endif
452 #endif
453 #endif
454 #endif
455 #endif
456             auio->afsio_offset += avc->quick.minLoc;
457             osi_UFSClose(tfile);
458             /* Fix up LRU info */
459             hset(afs_indexTimes[tdc->index], afs_indexCounter);
460             hadd32(afs_indexCounter, 1);
461
462             if (!noLock) {
463 #ifndef AFS_VM_RDWR_ENV
464                 if (!(code = afs_InitReq(&treq, acred))&& (!(tdc->flags & DFNextStarted)))
465                     afs_PrefetchChunk(avc, tdc, acred, &treq);
466 #endif
467                 ReleaseReadLock(&avc->lock);
468             }
469             tdc->refCount--;
470             return (code);
471         }
472         if (!tdc->f.chunkBytes) {   /* debugging f.chunkBytes == 0 problem */
473             savedc = tdc;
474         }
475         tdc->refCount--;
476     } else {
477         ReleaseReadLock(&afs_xdcache);
478     }
479
480     /* come here if fast path doesn't work for some reason or other */
481     if (!noLock)
482         ReleaseReadLock(&avc->lock);
483     return afs_UFSRead(avc, auio, acred, albn, abpp, noLock);
484 }
485
486 afs_UFSRead(avc, auio, acred, albn, abpp, noLock)
487     struct vcache *avc;
488     struct uio *auio;
489     struct AFS_UCRED *acred;
490     daddr_t albn;
491     int noLock;
492     struct buf **abpp; 
493 {
494     afs_size_t totalLength;
495     afs_size_t transferLength;
496     afs_size_t filePos;
497     afs_size_t offset, len, tlen;
498     afs_int32 trimlen;
499     struct dcache *tdc=0;
500     afs_int32 error;
501     struct uio tuio;
502     struct iovec *tvec;
503     struct osi_file *tfile;
504     afs_int32 code;
505     int munlocked, trybusy=1;
506     struct vnode *vp;
507     struct vrequest treq;
508
509     AFS_STATCNT(afs_UFSRead);
510     if (avc->vc_error)
511         return EIO;
512
513     /* check that we have the latest status info in the vnode cache */
514     if (code = afs_InitReq(&treq, acred)) return code;
515     if (!noLock) {
516       if (!avc) 
517         osi_Panic ("null avc in afs_UFSRead");
518       else {
519         code = afs_VerifyVCache(avc, &treq);
520         if (code) {
521           code = afs_CheckCode(code, &treq, 11); /* failed to get it */
522           return code;
523         }
524       }
525     }
526
527 #ifndef AFS_VM_RDWR_ENV
528     if (AFS_NFSXLATORREQ(acred)) {
529         if (!afs_AccessOK(avc, PRSFS_READ, &treq,
530                           CHECK_MODE_BITS|CMB_ALLOW_EXEC_AS_READ)) {
531             return afs_CheckCode(EACCES, &treq, 12);
532         }
533     }
534 #endif
535
536     tvec = (struct iovec *) osi_AllocSmallSpace(sizeof(struct iovec));
537     totalLength = auio->afsio_resid;
538     filePos = auio->afsio_offset;
539     afs_Trace4(afs_iclSetp, CM_TRACE_READ, ICL_TYPE_POINTER, avc, 
540                 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(filePos),
541                 ICL_TYPE_INT32, totalLength,
542                 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length));
543     error = 0;
544     transferLength = 0;
545     if (!noLock)
546         ObtainReadLock(&avc->lock);
547 #if     defined(AFS_TEXT_ENV) && !defined(AFS_VM_RDWR_ENV)
548     if (avc->flushDV.high == AFS_MAXDV && avc->flushDV.low == AFS_MAXDV) {
549         hset(avc->flushDV, avc->m.DataVersion);
550     }
551 #endif
552     
553     while (totalLength > 0) {
554         /* read all of the cached info */
555         if (filePos >= avc->m.Length) break;    /* all done */
556         if (noLock) {
557             if (tdc) afs_PutDCache(tdc);
558             tdc = afs_FindDCache(avc, filePos);
559             if (tdc) {
560                 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
561                 len = tdc->f.chunkBytes - offset;
562             }
563         } else {
564             /* a tricky question: does the presence of the DFFetching flag
565                mean that we're fetching the latest version of the file?  No.
566                The server could update the file as soon as the fetch responsible
567                for the setting of the DFFetching flag completes.
568             
569                However, the presence of the DFFetching flag (visible under a
570                read lock since it is set and cleared only under a write lock)
571                means that we're fetching as good a version as was known to this
572                client at the time of the last call to afs_VerifyVCache, since
573                the latter updates the stat cache's m.DataVersion field under a
574                write lock, and from the time that the DFFetching flag goes on
575                (before the fetch starts), to the time it goes off (after the
576                fetch completes), afs_GetDCache keeps at least a read lock
577                (actually it keeps an S lock) on the cache entry.
578             
579                This means that if the DFFetching flag is set, we can use that
580                data for any reads that must come from the current version of
581                the file (current == m.DataVersion).
582              
583                Another way of looking at this same point is this: if we're
584                fetching some data and then try do an afs_VerifyVCache, the
585                VerifyVCache operation will not complete until after the
586                DFFetching flag is turned off and the dcache entry's f.versionNo
587                field is updated.
588              
589                Note, by the way, that if DFFetching is set,
590                m.DataVersion > f.versionNo (the latter is not updated until
591                after the fetch completes).
592              */
593             if (tdc) afs_PutDCache(tdc);        /* before reusing tdc */
594             munlocked = 0;
595             tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 2);
596             if (tdc == savedc) {
597                 savedc = 0;
598             }
599             /* now, first try to start transfer, if we'll need the data.  If
600              * data already coming, we don't need to do this, obviously.  Type
601              * 2 requests never return a null dcache entry, btw. */
602             if (!(tdc->flags & DFFetching)
603                 && !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
604                 /* have cache entry, it is not coming in now, and we'll need new data */
605 tagain:
606                 if (trybusy && !afs_BBusy()) {
607                     struct brequest *bp;
608                     /* daemon is not busy */
609                     if (!(tdc->flags & DFFetchReq)) {
610                         tdc->flags |= DFFetchReq;
611 #ifdef  AFS_SUN5_ENVX
612                         mutex_exit(&tdc->lock);
613                         munlocked = 1;
614 #endif
615                         bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
616                                         (afs_size_t)filePos, (afs_size_t) 0,
617                                         tdc);
618                         if (!bp) {
619                             /* Bkg table full; retry deadlocks */
620                             tdc->flags &= ~DFFetchReq;
621                             trybusy = 0;        /* Avoid bkg daemon since they're too busy */
622                             goto tagain;
623                         }
624                     }
625                     while (tdc->flags & DFFetchReq) {
626                         /* don't need waiting flag on this one */
627                         ReleaseReadLock(&avc->lock);
628                         afs_osi_Sleep(&tdc->validPos);
629                         ObtainReadLock(&avc->lock);
630                     }
631                 }
632             }
633             /* now data may have started flowing in (if DFFetching is on).  If
634              * data is now streaming in, then wait for some interesting stuff. */
635             while ((tdc->flags & DFFetching) && tdc->validPos <= filePos) {
636                 /* too early: wait for DFFetching flag to vanish, or data to appear */
637                 tdc->flags |= DFWaiting;
638                 ReleaseReadLock(&avc->lock);
639                 afs_osi_Sleep(&tdc->validPos);
640                 ObtainReadLock(&avc->lock);
641             }
642             /* fetching flag gone, data is here, or we never tried (BBusy for instance) */
643             if (tdc->flags & DFFetching) {
644                 /* still fetching, some new data is here: compute length and offset */
645                 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
646                 len = tdc->validPos - filePos;
647             }
648             else {
649                 /* no longer fetching, verify data version (avoid new GetDCache call) */
650                 if (hsame(avc->m.DataVersion, tdc->f.versionNo)) {
651                     offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
652                     len = tdc->f.chunkBytes - offset;
653                 }
654                 else {
655                     /* don't have current data, so get it below */
656                     afs_PutDCache(tdc);
657                     tdc = (struct dcache *) 0;
658                 }
659             }
660
661             if (!tdc) {
662                 ReleaseReadLock(&avc->lock);
663                 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 1);
664                 ObtainReadLock(&avc->lock);
665             }
666         }
667
668         if (!tdc) {
669             error = EIO;
670             break;
671         }
672         if (len > totalLength) len = totalLength;   /* will read len bytes */
673         if (len <= 0) { /* shouldn't get here if DFFetching is on */
674             /* read past the end of a chunk, may not be at next chunk yet, and yet
675                 also not at eof, so may have to supply fake zeros */
676             len = AFS_CHUNKTOSIZE(tdc->f.chunk) - offset; /* bytes left in chunk addr space */
677             if (len > totalLength) len = totalLength;   /* and still within xfr request */
678             tlen = avc->m.Length - offset; /* and still within file */
679             if (len > tlen) len = tlen;
680             if (len > AFS_ZEROS) len = sizeof(afs_zeros);   /* and in 0 buffer */
681             afsio_copy(auio, &tuio, tvec);
682             trimlen = len;
683             afsio_trim(&tuio, trimlen);
684             AFS_UIOMOVE(afs_zeros, trimlen, UIO_READ, &tuio, code);
685             if (code) {
686                 error = code;
687                 break;
688             }
689         }
690         else {
691             /* get the data from the file */
692 #ifdef IHINT
693           if (tfile = tdc->ihint) {
694              if (tdc->f.inode != tfile->inum){ 
695                     afs_warn( "afs_UFSRead: %x hint mismatch tdc %d inum %d\n",
696                         tdc, tdc->f.inode, tfile->inum );
697                     osi_UFSClose(tfile);
698                     tdc->ihint = tfile = 0;
699                     nihints--;
700                   }
701            }
702           if (tfile != 0) {
703             usedihint++;
704           }
705           else
706 #endif /* IHINT */
707
708             tfile = (struct osi_file *)osi_UFSOpen(tdc->f.inode);
709             /* mung uio structure to be right for this transfer */
710             afsio_copy(auio, &tuio, tvec);
711             trimlen = len;
712             afsio_trim(&tuio, trimlen);
713             tuio.afsio_offset = offset;
714 #ifdef  AFS_AIX_ENV
715 #ifdef  AFS_AIX41_ENV
716           AFS_GUNLOCK();
717           code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, &tuio, NULL, NULL,
718                            NULL, &afs_osi_cred);
719           AFS_GLOCK();
720 #else
721 #ifdef AFS_AIX32_ENV
722             code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, &tuio, NULL, NULL);
723           /* Flush all JFS pages now for big performance gain in big file cases
724            * If we do something like this, must check to be sure that AFS file 
725            * isn't mmapped... see afs_gn_map() for why.
726           */
727 /*
728           if (tfile->vnode->v_gnode && tfile->vnode->v_gnode->gn_seg) {
729  many different ways to do similar things:
730    so far, the best performing one is #2, but #1 might match it if we
731    straighten out the confusion regarding which pages to flush.  It 
732    really does matter.
733    1.       vm_flushp(tfile->vnode->v_gnode->gn_seg, 0, len/PAGESIZE - 1);
734    2.       vm_releasep(tfile->vnode->v_gnode->gn_seg, offset/PAGESIZE, 
735                         (len + PAGESIZE-1)/PAGESIZE);
736    3.       vms_inactive(tfile->vnode->v_gnode->gn_seg) Doesn't work correctly
737    4.       vms_delete(tfile->vnode->v_gnode->gn_seg) probably also fails
738             tfile->vnode->v_gnode->gn_seg = NULL;
739    5.       deletep
740    6.       ipgrlse
741    7.       ifreeseg
742           Unfortunately, this seems to cause frequent "cache corruption" episodes.
743             vm_releasep(tfile->vnode->v_gnode->gn_seg, offset/PAGESIZE, 
744                         (len + PAGESIZE-1)/PAGESIZE);
745           }     
746 */
747 #else
748             code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, (off_t)&offset, &tuio, NULL, NULL, -1);
749 #endif
750 #endif
751 #else
752 #ifdef  AFS_SUN5_ENV
753           AFS_GUNLOCK();
754             VOP_RWLOCK(tfile->vnode, 0);
755             code = VOP_READ(tfile->vnode, &tuio, 0, &afs_osi_cred);
756             VOP_RWUNLOCK(tfile->vnode, 0);
757           AFS_GLOCK();
758 #else
759 #if defined(AFS_SGI_ENV)
760             AFS_GUNLOCK();
761             AFS_VOP_RWLOCK(tfile->vnode, VRWLOCK_READ);
762             AFS_VOP_READ(tfile->vnode, &tuio, IO_ISLOCKED, &afs_osi_cred,
763                          code);
764             AFS_VOP_RWUNLOCK(tfile->vnode, VRWLOCK_READ);
765             AFS_GLOCK();
766 #else
767 #ifdef  AFS_OSF_ENV
768             tuio.uio_rw = UIO_READ;
769             AFS_GUNLOCK();
770             VOP_READ(tfile->vnode, &tuio, 0, &afs_osi_cred, code);
771             AFS_GLOCK();
772 #else   /* AFS_OSF_ENV */
773 #ifdef AFS_SUN_ENV
774             code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, &afs_osi_cred);
775 #else
776 #if     defined(AFS_HPUX100_ENV)
777             AFS_GUNLOCK();
778             code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, &afs_osi_cred);
779             AFS_GLOCK();
780 #else
781 #if defined(AFS_LINUX20_ENV)
782             AFS_GUNLOCK();
783             code = osi_file_uio_rdwr(tfile, &tuio, UIO_READ);
784             AFS_GLOCK();
785 #else
786 #if defined(AFS_DARWIN_ENV)
787             AFS_GUNLOCK();
788             VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, current_proc());
789             code = VOP_READ(tfile->vnode, &tuio, 0, &afs_osi_cred);
790             VOP_UNLOCK(tfile->vnode, 0, current_proc());
791             AFS_GLOCK();
792 #else
793             code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, &afs_osi_cred);
794 #endif
795 #endif
796 #endif
797 #endif
798 #endif
799 #endif
800 #endif
801 #endif
802
803 #ifdef IHINT
804              if (!tdc->ihint && nihints < maxIHint) {
805                tdc->ihint = tfile;
806                nihints++;
807              }
808              else
809 #endif /* IHINT */
810                osi_UFSClose(tfile);
811
812             if (code) {
813                 error = code;
814                 break;
815             }
816         }
817         /* otherwise we've read some, fixup length, etc and continue with next seg */
818         len = len - tuio.afsio_resid; /* compute amount really transferred */
819         trimlen = len;
820         afsio_skip(auio, trimlen);          /* update input uio structure */
821         totalLength -= len;
822         transferLength += len;
823         filePos += len;
824         if (len <= 0) break;    /* surprise eof */
825     }
826
827     /* if we make it here with tdc non-zero, then it is the last chunk we
828      * dealt with, and we have to release it when we're done.  We hold on
829      * to it in case we need to do a prefetch, obviously.
830      */
831     if (tdc) {
832 #ifndef AFS_VM_RDWR_ENV
833         /* try to queue prefetch, if needed */
834         if (!(tdc->flags & DFNextStarted) && !noLock) {
835             afs_PrefetchChunk(avc, tdc, acred, &treq);
836         }
837 #endif
838         afs_PutDCache(tdc);
839     }
840     if (!noLock)
841         ReleaseReadLock(&avc->lock);
842
843     osi_FreeSmallSpace(tvec);
844     error = afs_CheckCode(error, &treq, 13);
845     return error;
846 }