ufsread-save-the-oops-for-where-we-expect-it-20020624
[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
111     /*
112      * Locks held:
113      * avc->lock(R)
114      */
115     while (totalLength > 0) {
116         /* read all of the cached info */
117         if (filePos >= avc->m.Length) break;    /* all done */
118         if (noLock) {
119             if (tdc) {
120                 ReleaseReadLock(&tdc->lock);
121                 afs_PutDCache(tdc);
122             }
123             tdc = afs_FindDCache(avc, filePos);
124             if (tdc) {
125                 ObtainReadLock(&tdc->lock);
126                 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
127                 len = tdc->f.chunkBytes - offset;
128             }
129         } else {
130             /* a tricky question: does the presence of the DFFetching flag
131                mean that we're fetching the latest version of the file?  No.
132                The server could update the file as soon as the fetch responsible
133                for the setting of the DFFetching flag completes.
134             
135                However, the presence of the DFFetching flag (visible under
136                a dcache read lock since it is set and cleared only under a
137                dcache write lock) means that we're fetching as good a version
138                as was known to this client at the time of the last call to
139                afs_VerifyVCache, since the latter updates the stat cache's
140                m.DataVersion field under a vcache write lock, and from the
141                time that the DFFetching flag goes on in afs_GetDCache (before
142                the fetch starts), to the time it goes off (after the fetch
143                completes), afs_GetDCache keeps at least a read lock on the
144                vcache entry.
145             
146                This means that if the DFFetching flag is set, we can use that
147                data for any reads that must come from the current version of
148                the file (current == m.DataVersion).
149              
150                Another way of looking at this same point is this: if we're
151                fetching some data and then try do an afs_VerifyVCache, the
152                VerifyVCache operation will not complete until after the
153                DFFetching flag is turned off and the dcache entry's f.versionNo
154                field is updated.
155              
156                Note, by the way, that if DFFetching is set,
157                m.DataVersion > f.versionNo (the latter is not updated until
158                after the fetch completes).
159              */
160             if (tdc) {
161                 ReleaseReadLock(&tdc->lock);
162                 afs_PutDCache(tdc);     /* before reusing tdc */
163             }
164             tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 2);
165             ObtainReadLock(&tdc->lock);
166             /* now, first try to start transfer, if we'll need the data.  If
167              * data already coming, we don't need to do this, obviously.  Type
168              * 2 requests never return a null dcache entry, btw.
169              */
170             if (!(tdc->dflags & DFFetching)
171                 && !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
172                 /* have cache entry, it is not coming in now,
173                  * and we'll need new data */
174 tagain:
175                 if (trybusy && !afs_BBusy()) {
176                     struct brequest *bp;
177                     /* daemon is not busy */
178                     ObtainSharedLock(&tdc->mflock, 665);
179                     if (!(tdc->mflags & DFFetchReq)) {
180                         /* start the daemon (may already be running, however) */
181                         UpgradeSToWLock(&tdc->mflock, 666);
182                         tdc->mflags |= DFFetchReq;
183                         bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
184                                         (afs_size_t)filePos, (afs_size_t) 0,
185                                         tdc);
186                         if (!bp) {
187                             tdc->mflags &= ~DFFetchReq;
188                             trybusy = 0;        /* Avoid bkg daemon since they're too busy */
189                             ReleaseWriteLock(&tdc->mflock);
190                             goto tagain;
191                         }
192                         ConvertWToSLock(&tdc->mflock);
193                         /* don't use bp pointer! */
194                     }
195                     code = 0;
196                     ConvertSToRLock(&tdc->mflock);
197                     while (!code && tdc->mflags & DFFetchReq) {
198                         /* don't need waiting flag on this one */
199                         ReleaseReadLock(&tdc->mflock);
200                         ReleaseReadLock(&tdc->lock);
201                         ReleaseReadLock(&avc->lock);
202                         code = afs_osi_SleepSig(&tdc->validPos);
203                         ObtainReadLock(&avc->lock);
204                         ObtainReadLock(&tdc->lock);
205                         ObtainReadLock(&tdc->mflock);
206                     }
207                     ReleaseReadLock(&tdc->mflock);
208                     if (code) {
209                         error = code;
210                         break;
211                     }
212                 }
213             }
214             /* now data may have started flowing in (if DFFetching is on).  If
215              * data is now streaming in, then wait for some interesting stuff.
216              */
217             code = 0;
218             while (!code && (tdc->dflags & DFFetching) &&
219                    tdc->validPos <= filePos) {
220                 /* too early: wait for DFFetching flag to vanish,
221                  * or data to appear */
222                 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT,
223                                 ICL_TYPE_STRING, __FILE__,
224                                 ICL_TYPE_INT32, __LINE__,
225                                 ICL_TYPE_POINTER, tdc,
226                                 ICL_TYPE_INT32, tdc->dflags);
227                 ReleaseReadLock(&tdc->lock);
228                 ReleaseReadLock(&avc->lock);
229                 code = afs_osi_SleepSig(&tdc->validPos);
230                 ObtainReadLock(&avc->lock);
231                 ObtainReadLock(&tdc->lock);
232             }
233             if (code) {
234                 error = code;
235                 break;
236             }
237             /* fetching flag gone, data is here, or we never tried (BBusy for instance) */
238             if (tdc->dflags & DFFetching) {
239                 /* still fetching, some new data is here: compute length and offset */
240                 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
241                 len = tdc->validPos - filePos;
242             }
243             else {
244                 /* no longer fetching, verify data version (avoid new GetDCache call) */
245                 if (hsame(avc->m.DataVersion, tdc->f.versionNo)) {
246                     offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
247                     len = tdc->f.chunkBytes - offset;
248                 }
249                 else {
250                     /* don't have current data, so get it below */
251                     ReleaseReadLock(&tdc->lock);
252                     afs_PutDCache(tdc);
253                     tdc = (struct dcache *) 0;
254                 }
255             }
256
257             if (!tdc) {
258                 ReleaseReadLock(&avc->lock);
259                 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 1);
260                 ObtainReadLock(&avc->lock);
261                 if (tdc) ObtainReadLock(&tdc->lock);
262             }
263         }
264
265         if (!tdc) {
266             error = EIO;
267             break;
268         }
269
270         /*
271          * Locks held:
272          * avc->lock(R)
273          * tdc->lock(R)
274          */
275
276         if (len > totalLength) len = totalLength;   /* will read len bytes */
277         if (len <= 0) { /* shouldn't get here if DFFetching is on */
278             /* read past the end of a chunk, may not be at next chunk yet, and yet
279                 also not at eof, so may have to supply fake zeros */
280             len = AFS_CHUNKTOSIZE(tdc->f.chunk) - offset; /* bytes left in chunk addr space */
281             if (len > totalLength) len = totalLength;   /* and still within xfr request */
282             tlen = avc->m.Length - offset; /* and still within file */ 
283             if (len > tlen) len = tlen;
284             if (len > AFS_ZEROS) len = sizeof(afs_zeros);   /* and in 0 buffer */
285             afsio_copy(auio, &tuio, tvec);
286             trimlen = len;
287             afsio_trim(&tuio, trimlen);
288             AFS_UIOMOVE(afs_zeros, trimlen, UIO_READ, &tuio, code);
289             if (code) {
290                 error = code;
291                 break;
292             }
293         }
294         else {
295             /* get the data from the mem cache */
296
297             /* mung uio structure to be right for this transfer */
298             afsio_copy(auio, &tuio, tvec);
299             trimlen = len;
300             afsio_trim(&tuio, trimlen);
301             tuio.afsio_offset = offset;
302
303             code = afs_MemReadUIO(tdc->f.inode, &tuio);
304
305             if (code) {
306                 error = code;
307                 break;
308             }
309         }
310         /* otherwise we've read some, fixup length, etc and continue with next seg */
311         len = len - tuio.afsio_resid; /* compute amount really transferred */
312         trimlen = len;
313         afsio_skip(auio, trimlen);          /* update input uio structure */
314         totalLength -= len;
315         transferLength += len;
316         filePos += len;
317
318         if (len <= 0) break;    /* surprise eof */
319     }   /* the whole while loop */
320
321     /*
322      * Locks held:
323      * avc->lock(R)
324      * tdc->lock(R) if tdc
325      */
326
327     /* if we make it here with tdc non-zero, then it is the last chunk we
328      * dealt with, and we have to release it when we're done.  We hold on
329      * to it in case we need to do a prefetch.
330      */
331     if (tdc) {
332         ReleaseReadLock(&tdc->lock);
333 #ifndef AFS_VM_RDWR_ENV
334         /* try to queue prefetch, if needed */
335         if (!noLock) {
336             afs_PrefetchChunk(avc, tdc, acred, &treq);
337         }
338 #endif
339         afs_PutDCache(tdc);
340     }
341     if (!noLock)
342         ReleaseReadLock(&avc->lock);
343     osi_FreeSmallSpace(tvec);
344     error = afs_CheckCode(error, &treq, 10);
345     return error;
346 }
347
348 /* called with the dcache entry triggering the fetch, the vcache entry involved,
349  * and a vrequest for the read call.  Marks the dcache entry as having already
350  * triggered a prefetch, starts the prefetch going and sets the DFFetchReq
351  * flag in the prefetched block, so that the next call to read knows to wait
352  * for the daemon to start doing things.
353  *
354  * This function must be called with the vnode at least read-locked, and
355  * no locks on the dcache, because it plays around with dcache entries.
356  */
357 void afs_PrefetchChunk(struct vcache *avc, struct dcache *adc,
358                               struct AFS_UCRED *acred, struct vrequest *areq)
359 {
360     register struct dcache *tdc;
361     afs_size_t offset;
362     afs_size_t j1, j2;  /* junk vbls for GetDCache to trash */
363
364     offset = adc->f.chunk+1;            /* next chunk we'll need */
365     offset = AFS_CHUNKTOBASE(offset);   /* base of next chunk */
366     ObtainReadLock(&adc->lock);
367     ObtainSharedLock(&adc->mflock, 662);
368     if (offset < avc->m.Length && !(adc->mflags & DFNextStarted) && !afs_BBusy()) {
369         struct brequest *bp;
370
371         UpgradeSToWLock(&adc->mflock, 663);
372         adc->mflags |= DFNextStarted;   /* we've tried to prefetch for this guy */
373         ReleaseWriteLock(&adc->mflock);
374         ReleaseReadLock(&adc->lock);
375
376         tdc = afs_GetDCache(avc, offset, areq, &j1, &j2, 2);    /* type 2 never returns 0 */
377         ObtainSharedLock(&tdc->mflock, 651);
378         if (!(tdc->mflags & DFFetchReq)) {
379             /* ask the daemon to do the work */
380             UpgradeSToWLock(&tdc->mflock, 652);
381             tdc->mflags |= DFFetchReq;  /* guaranteed to be cleared by BKG or GetDCache */
382             /* last parm (1) tells bkg daemon to do an afs_PutDCache when it is done,
383              * since we don't want to wait for it to finish before doing so ourselves.
384              */
385             bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
386                             (afs_size_t) offset, (afs_size_t) 1, tdc);
387             if (!bp) {
388                 /* Bkg table full; just abort non-important prefetching to avoid deadlocks */
389                 tdc->mflags &= ~DFFetchReq;
390                 ReleaseWriteLock(&tdc->mflock);
391                 afs_PutDCache(tdc);
392
393                 /*
394                  * DCLOCKXXX: This is a little sketchy, since someone else
395                  * could have already started a prefetch..  In practice,
396                  * this probably doesn't matter; at most it would cause an
397                  * extra slot in the BKG table to be used up when someone
398                  * prefetches this for the second time.
399                  */
400                 ObtainReadLock(&adc->lock);
401                 ObtainWriteLock(&adc->mflock, 664);
402                 adc->mflags &= ~DFNextStarted;
403                 ReleaseWriteLock(&adc->mflock);
404                 ReleaseReadLock(&adc->lock);
405             } else {
406                 ReleaseWriteLock(&tdc->mflock);
407             }
408         } else {
409             ReleaseSharedLock(&tdc->mflock);
410             afs_PutDCache(tdc);
411         }
412     } else {
413         ReleaseSharedLock(&adc->mflock);
414         ReleaseReadLock(&adc->lock);
415     }
416 }
417
418
419 /* if the vcache is up-to-date, and the request fits entirely into the chunk
420  * that the hint here references, then we just use it quickly, otherwise we
421  * have to call the slow read.
422  *
423  * This could be generalized in several ways to take advantage of partial 
424  * state even when all the chips don't fall the right way.  For instance,
425  * if the hint is good and the first part of the read request can be 
426  * satisfied from the chunk, then just do the read.  After the read has
427  * completed, check to see if there's more. (Chances are there won't be.)
428  * If there is more, then just call afs_UFSReadSlow and let it do the rest.
429  *
430  * For the time being, I'm ignoring quick.f, but it should be used at
431  * some future date.
432  * do this in the future avc->quick.f = tfile; but I think it
433  * has to be done under a write lock, but don't want to wait on the
434  * write lock
435  */
436     /* everywhere that a dcache can be freed (look for NULLIDX) 
437      * probably does it under a write lock on xdcache.  Need to invalidate
438      * stamp there, too.  
439      * Also need to worry about DFFetching, and IFFree, I think. */
440 static struct dcache *savedc = 0;
441
442 afs_UFSReadFast(avc, auio, acred, albn, abpp, noLock)
443     register struct vcache *avc;
444     struct uio *auio;
445     struct AFS_UCRED *acred;
446     int noLock;
447     daddr_t albn;
448     struct buf **abpp; 
449 {
450     struct vrequest treq;
451     int offDiff;
452     struct dcache *tdc;
453     struct vnode *vp;
454     struct osi_file *tfile;
455     afs_int32 code = 0;
456
457     if (!noLock)
458         ObtainReadLock(&avc->lock);  
459     ObtainReadLock(&afs_xdcache);
460
461     if ((avc->states & CStatd)                                /* up to date */
462         && (tdc = avc->quick.dc) && (tdc->index != NULLIDX) 
463         && !(afs_indexFlags[tdc->index] & (IFFree | IFDiscarded)))   {
464
465         int readLocked = 0;
466
467         afs_RefDCache(tdc);
468         ReleaseReadLock(&afs_xdcache);
469         if (tdc->stamp == avc->quick.stamp) {
470             readLocked = 1;
471             ObtainReadLock(&tdc->lock);
472         }
473
474         if ((tdc->stamp == avc->quick.stamp)                /* hint matches */
475             && ((offDiff = (auio->afsio_offset - avc->quick.minLoc)) >= 0)
476             && (tdc->f.chunkBytes >= auio->afsio_resid + offDiff)
477             && !(tdc->dflags & DFFetching)) { /* fits in chunk */
478
479             auio->afsio_offset -= avc->quick.minLoc;
480
481             afs_Trace4(afs_iclSetp, CM_TRACE_READFAST, ICL_TYPE_POINTER, avc,
482                         ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(auio->afsio_offset),
483                         ICL_TYPE_INT32, auio->afsio_resid,
484                         ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length));
485
486             tfile = (struct osi_file *)osi_UFSOpen(tdc->f.inode);
487
488 #ifdef  AFS_AIX_ENV
489 #ifdef  AFS_AIX41_ENV
490             AFS_GUNLOCK();
491             code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, auio, NULL, NULL, NULL, &afs_osi_cred);
492             AFS_GLOCK();
493 #else
494 #ifdef AFS_AIX32_ENV
495             code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, auio, NULL, NULL);
496 #else
497             code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, (off_t)&auio->afsio_offset, auio, NULL, NULL, -1);
498 #endif
499 #endif
500 #else
501 #ifdef  AFS_SUN5_ENV
502             AFS_GUNLOCK();
503             VOP_RWLOCK(tfile->vnode, 0);
504             code = VOP_READ(tfile->vnode, auio, 0, &afs_osi_cred);
505             VOP_RWUNLOCK(tfile->vnode, 0);
506             AFS_GLOCK();
507 #else
508 #if defined(AFS_SGI_ENV)
509             AFS_GUNLOCK();
510             AFS_VOP_RWLOCK(tfile->vnode, VRWLOCK_READ);
511             AFS_VOP_READ(tfile->vnode, auio, IO_ISLOCKED, &afs_osi_cred, code);
512             AFS_VOP_RWUNLOCK(tfile->vnode, VRWLOCK_READ);
513             AFS_GLOCK();
514 #else
515 #ifdef  AFS_OSF_ENV
516             auio->uio_rw = UIO_READ;
517             AFS_GUNLOCK();
518             VOP_READ(tfile->vnode, auio, 0, &afs_osi_cred, code);
519             AFS_GLOCK();
520 #else   /* AFS_OSF_ENV */
521 #if defined(AFS_HPUX100_ENV)
522             AFS_GUNLOCK();
523             code = VOP_RDWR(tfile->vnode, auio, UIO_READ, 0, &afs_osi_cred);
524             AFS_GLOCK();
525 #else
526 #if defined(AFS_LINUX20_ENV)
527             AFS_GUNLOCK();
528             code = osi_file_uio_rdwr(tfile, auio, UIO_READ);
529             AFS_GLOCK();
530 #else
531 #if defined(AFS_DARWIN_ENV)
532             AFS_GUNLOCK();
533             VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, current_proc());
534             code = VOP_READ(tfile->vnode, auio, 0, &afs_osi_cred);
535             VOP_UNLOCK(tfile->vnode, 0, current_proc());
536             AFS_GLOCK();
537 #else
538 #if defined(AFS_FBSD_ENV)
539             AFS_GUNLOCK();
540             VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, curproc);
541             code = VOP_READ(tfile->vnode, auio, 0, &afs_osi_cred);
542             VOP_UNLOCK(tfile->vnode, 0, curproc);
543             AFS_GLOCK();
544 #else
545             code = VOP_RDWR(tfile->vnode, auio, UIO_READ, 0, &afs_osi_cred);
546 #endif
547 #endif
548 #endif
549 #endif
550 #endif
551 #endif
552 #endif
553 #endif
554             auio->afsio_offset += avc->quick.minLoc;
555             osi_UFSClose(tfile);
556             /* Fix up LRU info */
557             hset(afs_indexTimes[tdc->index], afs_indexCounter);
558             hadd32(afs_indexCounter, 1);
559
560             if (!noLock) {
561                 ReleaseReadLock(&avc->lock);
562 #ifndef AFS_VM_RDWR_ENV
563                 if (!(code = afs_InitReq(&treq, acred))) {
564                     if (!(tdc->mflags & DFNextStarted))
565                         afs_PrefetchChunk(avc, tdc, acred, &treq);
566                 }
567 #endif
568             }
569             if (readLocked) ReleaseReadLock(&tdc->lock);
570             afs_PutDCache(tdc);
571             return (code);
572         }
573         if (!tdc->f.chunkBytes) {   /* debugging f.chunkBytes == 0 problem */
574             savedc = tdc;
575         }
576         if (readLocked) ReleaseReadLock(&tdc->lock);
577         afs_PutDCache(tdc);
578     } else {
579         ReleaseReadLock(&afs_xdcache);
580     }
581
582     /* come here if fast path doesn't work for some reason or other */
583     if (!noLock)
584         ReleaseReadLock(&avc->lock);
585     return afs_UFSRead(avc, auio, acred, albn, abpp, noLock);
586 }
587
588 afs_UFSRead(avc, auio, acred, albn, abpp, noLock)
589     struct vcache *avc;
590     struct uio *auio;
591     struct AFS_UCRED *acred;
592     daddr_t albn;
593     int noLock;
594     struct buf **abpp; 
595 {
596     afs_size_t totalLength;
597     afs_size_t transferLength;
598     afs_size_t filePos;
599     afs_size_t offset, len, tlen;
600     afs_int32 trimlen;
601     struct dcache *tdc=0;
602     afs_int32 error;
603     struct uio tuio;
604     struct iovec *tvec;
605     struct osi_file *tfile;
606     afs_int32 code;
607     int trybusy=1;
608     struct vnode *vp;
609     struct vrequest treq;
610
611     AFS_STATCNT(afs_UFSRead);
612     if (avc && avc->vc_error)
613         return EIO;
614
615     /* check that we have the latest status info in the vnode cache */
616     if (code = afs_InitReq(&treq, acred)) return code;
617     if (!noLock) {
618       if (!avc) 
619         osi_Panic ("null avc in afs_UFSRead");
620       else {
621         code = afs_VerifyVCache(avc, &treq);
622         if (code) {
623           code = afs_CheckCode(code, &treq, 11); /* failed to get it */
624           return code;
625         }
626       }
627     }
628
629 #ifndef AFS_VM_RDWR_ENV
630     if (AFS_NFSXLATORREQ(acred)) {
631         if (!afs_AccessOK(avc, PRSFS_READ, &treq,
632                           CHECK_MODE_BITS|CMB_ALLOW_EXEC_AS_READ)) {
633             return afs_CheckCode(EACCES, &treq, 12);
634         }
635     }
636 #endif
637
638     tvec = (struct iovec *) osi_AllocSmallSpace(sizeof(struct iovec));
639     totalLength = auio->afsio_resid;
640     filePos = auio->afsio_offset;
641     afs_Trace4(afs_iclSetp, CM_TRACE_READ, ICL_TYPE_POINTER, avc, 
642                 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(filePos),
643                 ICL_TYPE_INT32, totalLength,
644                 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length));
645     error = 0;
646     transferLength = 0;
647     if (!noLock)
648         ObtainReadLock(&avc->lock);
649 #if     defined(AFS_TEXT_ENV) && !defined(AFS_VM_RDWR_ENV)
650     if (avc->flushDV.high == AFS_MAXDV && avc->flushDV.low == AFS_MAXDV) {
651         hset(avc->flushDV, avc->m.DataVersion);
652     }
653 #endif
654     
655     while (totalLength > 0) {
656         /* read all of the cached info */
657         if (filePos >= avc->m.Length) break;    /* all done */
658         if (noLock) {
659             if (tdc) {
660                 ReleaseReadLock(&tdc->lock);
661                 afs_PutDCache(tdc);
662             }
663             tdc = afs_FindDCache(avc, filePos);
664             if (tdc) {
665                 ObtainReadLock(&tdc->lock);
666                 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
667                 len = tdc->f.chunkBytes - offset;
668             }
669         } else {
670             /* a tricky question: does the presence of the DFFetching flag
671                mean that we're fetching the latest version of the file?  No.
672                The server could update the file as soon as the fetch responsible
673                for the setting of the DFFetching flag completes.
674             
675                However, the presence of the DFFetching flag (visible under
676                a dcache read lock since it is set and cleared only under a
677                dcache write lock) means that we're fetching as good a version
678                as was known to this client at the time of the last call to
679                afs_VerifyVCache, since the latter updates the stat cache's
680                m.DataVersion field under a vcache write lock, and from the
681                time that the DFFetching flag goes on in afs_GetDCache (before
682                the fetch starts), to the time it goes off (after the fetch
683                completes), afs_GetDCache keeps at least a read lock on the
684                vcache entry.
685             
686                This means that if the DFFetching flag is set, we can use that
687                data for any reads that must come from the current version of
688                the file (current == m.DataVersion).
689              
690                Another way of looking at this same point is this: if we're
691                fetching some data and then try do an afs_VerifyVCache, the
692                VerifyVCache operation will not complete until after the
693                DFFetching flag is turned off and the dcache entry's f.versionNo
694                field is updated.
695              
696                Note, by the way, that if DFFetching is set,
697                m.DataVersion > f.versionNo (the latter is not updated until
698                after the fetch completes).
699              */
700             if (tdc) {
701                 ReleaseReadLock(&tdc->lock);
702                 afs_PutDCache(tdc);     /* before reusing tdc */
703             }
704             tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 2);
705             ObtainReadLock(&tdc->lock);
706             if (tdc == savedc) {
707                 savedc = 0;
708             }
709             /* now, first try to start transfer, if we'll need the data.  If
710              * data already coming, we don't need to do this, obviously.  Type
711              * 2 requests never return a null dcache entry, btw. */
712             if (!(tdc->dflags & DFFetching)
713                 && !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
714                 /* have cache entry, it is not coming in now, and we'll need new data */
715 tagain:
716                 if (trybusy && !afs_BBusy()) {
717                     struct brequest *bp;
718                     /* daemon is not busy */
719                     ObtainSharedLock(&tdc->mflock, 667);
720                     if (!(tdc->mflags & DFFetchReq)) {
721                         UpgradeSToWLock(&tdc->mflock, 668);
722                         tdc->mflags |= DFFetchReq;
723                         bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
724                                         (afs_size_t) filePos, (afs_size_t) 0,
725                                         tdc);
726                         if (!bp) {
727                             /* Bkg table full; retry deadlocks */
728                             tdc->mflags &= ~DFFetchReq;
729                             trybusy = 0;        /* Avoid bkg daemon since they're too busy */
730                             ReleaseWriteLock(&tdc->mflock);
731                             goto tagain;
732                         }
733                         ConvertWToSLock(&tdc->mflock);
734                     }
735                     code = 0;
736                     ConvertSToRLock(&tdc->mflock);
737                     while (!code && tdc->mflags & DFFetchReq) {
738                         /* don't need waiting flag on this one */
739                         ReleaseReadLock(&tdc->mflock);
740                         ReleaseReadLock(&tdc->lock);
741                         ReleaseReadLock(&avc->lock);
742                         code = afs_osi_SleepSig(&tdc->validPos);
743                         ObtainReadLock(&avc->lock);
744                         ObtainReadLock(&tdc->lock);
745                         ObtainReadLock(&tdc->mflock);
746                     }
747                     ReleaseReadLock(&tdc->mflock);
748                     if (code) {
749                         error = code;
750                         break;
751                     }
752                 }
753             }
754             /* now data may have started flowing in (if DFFetching is on).  If
755              * data is now streaming in, then wait for some interesting stuff.
756              */
757             code = 0;
758             while (!code && (tdc->dflags & DFFetching) &&
759                    tdc->validPos <= filePos) {
760                 /* too early: wait for DFFetching flag to vanish,
761                  * or data to appear */
762                 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT,
763                                 ICL_TYPE_STRING, __FILE__,
764                                 ICL_TYPE_INT32, __LINE__,
765                                 ICL_TYPE_POINTER, tdc,
766                                 ICL_TYPE_INT32, tdc->dflags);
767                 ReleaseReadLock(&tdc->lock);
768                 ReleaseReadLock(&avc->lock);
769                 code = afs_osi_SleepSig(&tdc->validPos);
770                 ObtainReadLock(&avc->lock);
771                 ObtainReadLock(&tdc->lock);
772             }
773             if (code) {
774                 error = code;
775                 break;
776             }
777             /* fetching flag gone, data is here, or we never tried
778              * (BBusy for instance) */
779             if (tdc->dflags & DFFetching) {
780                 /* still fetching, some new data is here:
781                  * compute length and offset */
782                 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
783                 len = tdc->validPos - filePos;
784             }
785             else {
786                 /* no longer fetching, verify data version (avoid new
787                  * GetDCache call) */
788                 if (hsame(avc->m.DataVersion, tdc->f.versionNo)) {
789                     offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
790                     len = tdc->f.chunkBytes - offset;
791                 }
792                 else {
793                     /* don't have current data, so get it below */
794                     ReleaseReadLock(&tdc->lock);
795                     afs_PutDCache(tdc);
796                     tdc = (struct dcache *) 0;
797                 }
798             }
799
800             if (!tdc) {
801                 ReleaseReadLock(&avc->lock);
802                 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 1);
803                 ObtainReadLock(&avc->lock);
804                 if (tdc) ObtainReadLock(&tdc->lock);
805             }
806         }
807         
808         afs_Trace3(afs_iclSetp, CM_TRACE_VNODEREAD,
809                         ICL_TYPE_POINTER, tdc,
810                         ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(offset),
811                         ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(len));
812         if (!tdc) {
813             error = EIO;
814             break;
815         }
816         if (len > totalLength) len = totalLength;   /* will read len bytes */
817         if (len <= 0) { /* shouldn't get here if DFFetching is on */
818             /* read past the end of a chunk, may not be at next chunk yet, and yet
819                 also not at eof, so may have to supply fake zeros */
820             len = AFS_CHUNKTOSIZE(tdc->f.chunk) - offset; /* bytes left in chunk addr space */
821             if (len > totalLength) len = totalLength;   /* and still within xfr request */
822             tlen = avc->m.Length - offset; /* and still within file */
823             if (len > tlen) len = tlen;
824             if (len > AFS_ZEROS) len = sizeof(afs_zeros);   /* and in 0 buffer */
825             afsio_copy(auio, &tuio, tvec);
826             trimlen = len;
827             afsio_trim(&tuio, trimlen);
828             AFS_UIOMOVE(afs_zeros, trimlen, UIO_READ, &tuio, code);
829             if (code) {
830                 error = code;
831                 break;
832             }
833         }
834         else {
835             /* get the data from the file */
836 #ifdef IHINT
837           if (tfile = tdc->ihint) {
838              if (tdc->f.inode != tfile->inum){ 
839                     afs_warn( "afs_UFSRead: %x hint mismatch tdc %d inum %d\n",
840                         tdc, tdc->f.inode, tfile->inum );
841                     osi_UFSClose(tfile);
842                     tdc->ihint = tfile = 0;
843                     nihints--;
844                   }
845            }
846           if (tfile != 0) {
847             usedihint++;
848           }
849           else
850 #endif /* IHINT */
851
852             tfile = (struct osi_file *)osi_UFSOpen(tdc->f.inode);
853             /* mung uio structure to be right for this transfer */
854             afsio_copy(auio, &tuio, tvec);
855             trimlen = len;
856             afsio_trim(&tuio, trimlen);
857             tuio.afsio_offset = offset;
858 #ifdef  AFS_AIX_ENV
859 #ifdef  AFS_AIX41_ENV
860           AFS_GUNLOCK();
861           code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, &tuio, NULL, NULL,
862                            NULL, &afs_osi_cred);
863           AFS_GLOCK();
864 #else
865 #ifdef AFS_AIX32_ENV
866             code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, &tuio, NULL, NULL);
867           /* Flush all JFS pages now for big performance gain in big file cases
868            * If we do something like this, must check to be sure that AFS file 
869            * isn't mmapped... see afs_gn_map() for why.
870           */
871 /*
872           if (tfile->vnode->v_gnode && tfile->vnode->v_gnode->gn_seg) {
873  many different ways to do similar things:
874    so far, the best performing one is #2, but #1 might match it if we
875    straighten out the confusion regarding which pages to flush.  It 
876    really does matter.
877    1.       vm_flushp(tfile->vnode->v_gnode->gn_seg, 0, len/PAGESIZE - 1);
878    2.       vm_releasep(tfile->vnode->v_gnode->gn_seg, offset/PAGESIZE, 
879                         (len + PAGESIZE-1)/PAGESIZE);
880    3.       vms_inactive(tfile->vnode->v_gnode->gn_seg) Doesn't work correctly
881    4.       vms_delete(tfile->vnode->v_gnode->gn_seg) probably also fails
882             tfile->vnode->v_gnode->gn_seg = NULL;
883    5.       deletep
884    6.       ipgrlse
885    7.       ifreeseg
886           Unfortunately, this seems to cause frequent "cache corruption" episodes.
887             vm_releasep(tfile->vnode->v_gnode->gn_seg, offset/PAGESIZE, 
888                         (len + PAGESIZE-1)/PAGESIZE);
889           }     
890 */
891 #else
892             code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, (off_t)&offset, &tuio, NULL, NULL, -1);
893 #endif
894 #endif
895 #else
896 #ifdef  AFS_SUN5_ENV
897           AFS_GUNLOCK();
898             VOP_RWLOCK(tfile->vnode, 0);
899             code = VOP_READ(tfile->vnode, &tuio, 0, &afs_osi_cred);
900             VOP_RWUNLOCK(tfile->vnode, 0);
901           AFS_GLOCK();
902 #else
903 #if defined(AFS_SGI_ENV)
904             AFS_GUNLOCK();
905             AFS_VOP_RWLOCK(tfile->vnode, VRWLOCK_READ);
906             AFS_VOP_READ(tfile->vnode, &tuio, IO_ISLOCKED, &afs_osi_cred,
907                          code);
908             AFS_VOP_RWUNLOCK(tfile->vnode, VRWLOCK_READ);
909             AFS_GLOCK();
910 #else
911 #ifdef  AFS_OSF_ENV
912             tuio.uio_rw = UIO_READ;
913             AFS_GUNLOCK();
914             VOP_READ(tfile->vnode, &tuio, 0, &afs_osi_cred, code);
915             AFS_GLOCK();
916 #else   /* AFS_OSF_ENV */
917 #ifdef AFS_SUN_ENV
918             code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, &afs_osi_cred);
919 #else
920 #if     defined(AFS_HPUX100_ENV)
921             AFS_GUNLOCK();
922             code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, &afs_osi_cred);
923             AFS_GLOCK();
924 #else
925 #if defined(AFS_LINUX20_ENV)
926             AFS_GUNLOCK();
927             code = osi_file_uio_rdwr(tfile, &tuio, UIO_READ);
928             AFS_GLOCK();
929 #else
930 #if defined(AFS_DARWIN_ENV)
931             AFS_GUNLOCK();
932             VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, current_proc());
933             code = VOP_READ(tfile->vnode, &tuio, 0, &afs_osi_cred);
934             VOP_UNLOCK(tfile->vnode, 0, current_proc());
935             AFS_GLOCK();
936 #else
937 #if defined(AFS_FBSD_ENV)
938             AFS_GUNLOCK();
939             VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, curproc);
940             code = VOP_READ(tfile->vnode, auio, 0, &afs_osi_cred);
941             VOP_UNLOCK(tfile->vnode, 0, curproc);
942             AFS_GLOCK();
943 #else
944             code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, &afs_osi_cred);
945 #endif
946 #endif
947 #endif
948 #endif
949 #endif
950 #endif
951 #endif
952 #endif
953 #endif
954
955 #ifdef IHINT
956              if (!tdc->ihint && nihints < maxIHint) {
957                tdc->ihint = tfile;
958                nihints++;
959              }
960              else
961 #endif /* IHINT */
962                osi_UFSClose(tfile);
963
964             if (code) {
965                 error = code;
966                 break;
967             }
968         }
969         /* otherwise we've read some, fixup length, etc and continue with next seg */
970         len = len - tuio.afsio_resid; /* compute amount really transferred */
971         trimlen = len;
972         afsio_skip(auio, trimlen);          /* update input uio structure */
973         totalLength -= len;
974         transferLength += len;
975         filePos += len;
976         if (len <= 0) break;    /* surprise eof */
977     }
978
979     /* if we make it here with tdc non-zero, then it is the last chunk we
980      * dealt with, and we have to release it when we're done.  We hold on
981      * to it in case we need to do a prefetch, obviously.
982      */
983     if (tdc) {
984         ReleaseReadLock(&tdc->lock);
985 #ifndef AFS_VM_RDWR_ENV
986         /* try to queue prefetch, if needed */
987         if (!noLock) {
988             if (!(tdc->mflags & DFNextStarted))
989                 afs_PrefetchChunk(avc, tdc, acred, &treq);
990         }
991 #endif
992         afs_PutDCache(tdc);
993     }
994     if (!noLock)
995         ReleaseReadLock(&avc->lock);
996
997     osi_FreeSmallSpace(tvec);
998     error = afs_CheckCode(error, &treq, 13);
999     return error;
1000 }