First pass at better signal handling:
[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                 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             code = VOP_RDWR(tfile->vnode, auio, UIO_READ, 0, &afs_osi_cred);
539 #endif
540 #endif
541 #endif
542 #endif
543 #endif
544 #endif
545 #endif
546             auio->afsio_offset += avc->quick.minLoc;
547             osi_UFSClose(tfile);
548             /* Fix up LRU info */
549             hset(afs_indexTimes[tdc->index], afs_indexCounter);
550             hadd32(afs_indexCounter, 1);
551
552             if (!noLock) {
553                 ReleaseReadLock(&avc->lock);
554 #ifndef AFS_VM_RDWR_ENV
555                 if (!(code = afs_InitReq(&treq, acred))) {
556                     if (!(tdc->mflags & DFNextStarted))
557                         afs_PrefetchChunk(avc, tdc, acred, &treq);
558                 }
559 #endif
560             }
561             if (readLocked) ReleaseReadLock(&tdc->lock);
562             afs_PutDCache(tdc);
563             return (code);
564         }
565         if (!tdc->f.chunkBytes) {   /* debugging f.chunkBytes == 0 problem */
566             savedc = tdc;
567         }
568         if (readLocked) ReleaseReadLock(&tdc->lock);
569         afs_PutDCache(tdc);
570     } else {
571         ReleaseReadLock(&afs_xdcache);
572     }
573
574     /* come here if fast path doesn't work for some reason or other */
575     if (!noLock)
576         ReleaseReadLock(&avc->lock);
577     return afs_UFSRead(avc, auio, acred, albn, abpp, noLock);
578 }
579
580 afs_UFSRead(avc, auio, acred, albn, abpp, noLock)
581     struct vcache *avc;
582     struct uio *auio;
583     struct AFS_UCRED *acred;
584     daddr_t albn;
585     int noLock;
586     struct buf **abpp; 
587 {
588     afs_size_t totalLength;
589     afs_size_t transferLength;
590     afs_size_t filePos;
591     afs_size_t offset, len, tlen;
592     afs_int32 trimlen;
593     struct dcache *tdc=0;
594     afs_int32 error;
595     struct uio tuio;
596     struct iovec *tvec;
597     struct osi_file *tfile;
598     afs_int32 code;
599     int trybusy=1;
600     struct vnode *vp;
601     struct vrequest treq;
602
603     AFS_STATCNT(afs_UFSRead);
604     if (avc->vc_error)
605         return EIO;
606
607     /* check that we have the latest status info in the vnode cache */
608     if (code = afs_InitReq(&treq, acred)) return code;
609     if (!noLock) {
610       if (!avc) 
611         osi_Panic ("null avc in afs_UFSRead");
612       else {
613         code = afs_VerifyVCache(avc, &treq);
614         if (code) {
615           code = afs_CheckCode(code, &treq, 11); /* failed to get it */
616           return code;
617         }
618       }
619     }
620
621 #ifndef AFS_VM_RDWR_ENV
622     if (AFS_NFSXLATORREQ(acred)) {
623         if (!afs_AccessOK(avc, PRSFS_READ, &treq,
624                           CHECK_MODE_BITS|CMB_ALLOW_EXEC_AS_READ)) {
625             return afs_CheckCode(EACCES, &treq, 12);
626         }
627     }
628 #endif
629
630     tvec = (struct iovec *) osi_AllocSmallSpace(sizeof(struct iovec));
631     totalLength = auio->afsio_resid;
632     filePos = auio->afsio_offset;
633     afs_Trace4(afs_iclSetp, CM_TRACE_READ, ICL_TYPE_POINTER, avc, 
634                 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(filePos),
635                 ICL_TYPE_INT32, totalLength,
636                 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length));
637     error = 0;
638     transferLength = 0;
639     if (!noLock)
640         ObtainReadLock(&avc->lock);
641 #if     defined(AFS_TEXT_ENV) && !defined(AFS_VM_RDWR_ENV)
642     if (avc->flushDV.high == AFS_MAXDV && avc->flushDV.low == AFS_MAXDV) {
643         hset(avc->flushDV, avc->m.DataVersion);
644     }
645 #endif
646     
647     while (totalLength > 0) {
648         /* read all of the cached info */
649         if (filePos >= avc->m.Length) break;    /* all done */
650         if (noLock) {
651             if (tdc) {
652                 ReleaseReadLock(&tdc->lock);
653                 afs_PutDCache(tdc);
654             }
655             tdc = afs_FindDCache(avc, filePos);
656             if (tdc) {
657                 ObtainReadLock(&tdc->lock);
658                 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
659                 len = tdc->f.chunkBytes - offset;
660             }
661         } else {
662             /* a tricky question: does the presence of the DFFetching flag
663                mean that we're fetching the latest version of the file?  No.
664                The server could update the file as soon as the fetch responsible
665                for the setting of the DFFetching flag completes.
666             
667                However, the presence of the DFFetching flag (visible under
668                a dcache read lock since it is set and cleared only under a
669                dcache write lock) means that we're fetching as good a version
670                as was known to this client at the time of the last call to
671                afs_VerifyVCache, since the latter updates the stat cache's
672                m.DataVersion field under a vcache write lock, and from the
673                time that the DFFetching flag goes on in afs_GetDCache (before
674                the fetch starts), to the time it goes off (after the fetch
675                completes), afs_GetDCache keeps at least a read lock on the
676                vcache entry.
677             
678                This means that if the DFFetching flag is set, we can use that
679                data for any reads that must come from the current version of
680                the file (current == m.DataVersion).
681              
682                Another way of looking at this same point is this: if we're
683                fetching some data and then try do an afs_VerifyVCache, the
684                VerifyVCache operation will not complete until after the
685                DFFetching flag is turned off and the dcache entry's f.versionNo
686                field is updated.
687              
688                Note, by the way, that if DFFetching is set,
689                m.DataVersion > f.versionNo (the latter is not updated until
690                after the fetch completes).
691              */
692             if (tdc) {
693                 ReleaseReadLock(&tdc->lock);
694                 afs_PutDCache(tdc);     /* before reusing tdc */
695             }
696             tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 2);
697             ObtainReadLock(&tdc->lock);
698             if (tdc == savedc) {
699                 savedc = 0;
700             }
701             /* now, first try to start transfer, if we'll need the data.  If
702              * data already coming, we don't need to do this, obviously.  Type
703              * 2 requests never return a null dcache entry, btw. */
704             if (!(tdc->dflags & DFFetching)
705                 && !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
706                 /* have cache entry, it is not coming in now, and we'll need new data */
707 tagain:
708                 if (trybusy && !afs_BBusy()) {
709                     struct brequest *bp;
710                     /* daemon is not busy */
711                     ObtainSharedLock(&tdc->mflock, 667);
712                     if (!(tdc->mflags & DFFetchReq)) {
713                         UpgradeSToWLock(&tdc->mflock, 668);
714                         tdc->mflags |= DFFetchReq;
715                         bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
716                                         (afs_size_t) filePos, (afs_size_t) 0,
717                                         tdc);
718                         if (!bp) {
719                             /* Bkg table full; retry deadlocks */
720                             tdc->mflags &= ~DFFetchReq;
721                             trybusy = 0;        /* Avoid bkg daemon since they're too busy */
722                             ReleaseWriteLock(&tdc->mflock);
723                             goto tagain;
724                         }
725                         ConvertWToSLock(&tdc->mflock);
726                     }
727                     code = 0;
728                     ConvertSToRLock(&tdc->mflock);
729                     while (!code && tdc->mflags & DFFetchReq) {
730                         /* don't need waiting flag on this one */
731                         ReleaseReadLock(&tdc->mflock);
732                         ReleaseReadLock(&tdc->lock);
733                         ReleaseReadLock(&avc->lock);
734                         code = afs_osi_SleepSig(&tdc->validPos);
735                         ObtainReadLock(&avc->lock);
736                         ObtainReadLock(&tdc->lock);
737                         ObtainReadLock(&tdc->mflock);
738                     }
739                     ReleaseReadLock(&tdc->mflock);
740                     if (code) {
741                         error = code;
742                         break;
743                     }
744                 }
745             }
746             /* now data may have started flowing in (if DFFetching is on).  If
747              * data is now streaming in, then wait for some interesting stuff.
748              */
749             code = 0;
750             while (!code && (tdc->dflags & DFFetching) &&
751                    tdc->validPos <= filePos) {
752                 /* too early: wait for DFFetching flag to vanish,
753                  * or data to appear */
754                 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT,
755                                 ICL_TYPE_STRING, __FILE__,
756                                 ICL_TYPE_INT32, __LINE__,
757                                 ICL_TYPE_POINTER, tdc,
758                                 ICL_TYPE_INT32, tdc->dflags);
759                 ReleaseReadLock(&tdc->lock);
760                 ReleaseReadLock(&avc->lock);
761                 code = afs_osi_SleepSig(&tdc->validPos);
762                 ObtainReadLock(&avc->lock);
763                 ObtainReadLock(&tdc->lock);
764             }
765             if (code) {
766                 error = code;
767                 break;
768             }
769             /* fetching flag gone, data is here, or we never tried
770              * (BBusy for instance) */
771             if (tdc->dflags & DFFetching) {
772                 /* still fetching, some new data is here:
773                  * compute length and offset */
774                 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
775                 len = tdc->validPos - filePos;
776             }
777             else {
778                 /* no longer fetching, verify data version (avoid new
779                  * GetDCache call) */
780                 if (hsame(avc->m.DataVersion, tdc->f.versionNo)) {
781                     offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
782                     len = tdc->f.chunkBytes - offset;
783                 }
784                 else {
785                     /* don't have current data, so get it below */
786                     ReleaseReadLock(&tdc->lock);
787                     afs_PutDCache(tdc);
788                     tdc = (struct dcache *) 0;
789                 }
790             }
791
792             if (!tdc) {
793                 ReleaseReadLock(&avc->lock);
794                 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 1);
795                 ObtainReadLock(&avc->lock);
796                 ObtainReadLock(&tdc->lock);
797             }
798         }
799         
800         afs_Trace3(afs_iclSetp, CM_TRACE_VNODEREAD,
801                         ICL_TYPE_POINTER, tdc,
802                         ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(offset),
803                         ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(len));
804         if (!tdc) {
805             error = EIO;
806             break;
807         }
808         if (len > totalLength) len = totalLength;   /* will read len bytes */
809         if (len <= 0) { /* shouldn't get here if DFFetching is on */
810             /* read past the end of a chunk, may not be at next chunk yet, and yet
811                 also not at eof, so may have to supply fake zeros */
812             len = AFS_CHUNKTOSIZE(tdc->f.chunk) - offset; /* bytes left in chunk addr space */
813             if (len > totalLength) len = totalLength;   /* and still within xfr request */
814             tlen = avc->m.Length - offset; /* and still within file */
815             if (len > tlen) len = tlen;
816             if (len > AFS_ZEROS) len = sizeof(afs_zeros);   /* and in 0 buffer */
817             afsio_copy(auio, &tuio, tvec);
818             trimlen = len;
819             afsio_trim(&tuio, trimlen);
820             AFS_UIOMOVE(afs_zeros, trimlen, UIO_READ, &tuio, code);
821             if (code) {
822                 error = code;
823                 break;
824             }
825         }
826         else {
827             /* get the data from the file */
828 #ifdef IHINT
829           if (tfile = tdc->ihint) {
830              if (tdc->f.inode != tfile->inum){ 
831                     afs_warn( "afs_UFSRead: %x hint mismatch tdc %d inum %d\n",
832                         tdc, tdc->f.inode, tfile->inum );
833                     osi_UFSClose(tfile);
834                     tdc->ihint = tfile = 0;
835                     nihints--;
836                   }
837            }
838           if (tfile != 0) {
839             usedihint++;
840           }
841           else
842 #endif /* IHINT */
843
844             tfile = (struct osi_file *)osi_UFSOpen(tdc->f.inode);
845             /* mung uio structure to be right for this transfer */
846             afsio_copy(auio, &tuio, tvec);
847             trimlen = len;
848             afsio_trim(&tuio, trimlen);
849             tuio.afsio_offset = offset;
850 #ifdef  AFS_AIX_ENV
851 #ifdef  AFS_AIX41_ENV
852           AFS_GUNLOCK();
853           code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, &tuio, NULL, NULL,
854                            NULL, &afs_osi_cred);
855           AFS_GLOCK();
856 #else
857 #ifdef AFS_AIX32_ENV
858             code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, &tuio, NULL, NULL);
859           /* Flush all JFS pages now for big performance gain in big file cases
860            * If we do something like this, must check to be sure that AFS file 
861            * isn't mmapped... see afs_gn_map() for why.
862           */
863 /*
864           if (tfile->vnode->v_gnode && tfile->vnode->v_gnode->gn_seg) {
865  many different ways to do similar things:
866    so far, the best performing one is #2, but #1 might match it if we
867    straighten out the confusion regarding which pages to flush.  It 
868    really does matter.
869    1.       vm_flushp(tfile->vnode->v_gnode->gn_seg, 0, len/PAGESIZE - 1);
870    2.       vm_releasep(tfile->vnode->v_gnode->gn_seg, offset/PAGESIZE, 
871                         (len + PAGESIZE-1)/PAGESIZE);
872    3.       vms_inactive(tfile->vnode->v_gnode->gn_seg) Doesn't work correctly
873    4.       vms_delete(tfile->vnode->v_gnode->gn_seg) probably also fails
874             tfile->vnode->v_gnode->gn_seg = NULL;
875    5.       deletep
876    6.       ipgrlse
877    7.       ifreeseg
878           Unfortunately, this seems to cause frequent "cache corruption" episodes.
879             vm_releasep(tfile->vnode->v_gnode->gn_seg, offset/PAGESIZE, 
880                         (len + PAGESIZE-1)/PAGESIZE);
881           }     
882 */
883 #else
884             code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, (off_t)&offset, &tuio, NULL, NULL, -1);
885 #endif
886 #endif
887 #else
888 #ifdef  AFS_SUN5_ENV
889           AFS_GUNLOCK();
890             VOP_RWLOCK(tfile->vnode, 0);
891             code = VOP_READ(tfile->vnode, &tuio, 0, &afs_osi_cred);
892             VOP_RWUNLOCK(tfile->vnode, 0);
893           AFS_GLOCK();
894 #else
895 #if defined(AFS_SGI_ENV)
896             AFS_GUNLOCK();
897             AFS_VOP_RWLOCK(tfile->vnode, VRWLOCK_READ);
898             AFS_VOP_READ(tfile->vnode, &tuio, IO_ISLOCKED, &afs_osi_cred,
899                          code);
900             AFS_VOP_RWUNLOCK(tfile->vnode, VRWLOCK_READ);
901             AFS_GLOCK();
902 #else
903 #ifdef  AFS_OSF_ENV
904             tuio.uio_rw = UIO_READ;
905             AFS_GUNLOCK();
906             VOP_READ(tfile->vnode, &tuio, 0, &afs_osi_cred, code);
907             AFS_GLOCK();
908 #else   /* AFS_OSF_ENV */
909 #ifdef AFS_SUN_ENV
910             code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, &afs_osi_cred);
911 #else
912 #if     defined(AFS_HPUX100_ENV)
913             AFS_GUNLOCK();
914             code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, &afs_osi_cred);
915             AFS_GLOCK();
916 #else
917 #if defined(AFS_LINUX20_ENV)
918             AFS_GUNLOCK();
919             code = osi_file_uio_rdwr(tfile, &tuio, UIO_READ);
920             AFS_GLOCK();
921 #else
922 #if defined(AFS_DARWIN_ENV)
923             AFS_GUNLOCK();
924             VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, current_proc());
925             code = VOP_READ(tfile->vnode, &tuio, 0, &afs_osi_cred);
926             VOP_UNLOCK(tfile->vnode, 0, current_proc());
927             AFS_GLOCK();
928 #else
929             code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, &afs_osi_cred);
930 #endif
931 #endif
932 #endif
933 #endif
934 #endif
935 #endif
936 #endif
937 #endif
938
939 #ifdef IHINT
940              if (!tdc->ihint && nihints < maxIHint) {
941                tdc->ihint = tfile;
942                nihints++;
943              }
944              else
945 #endif /* IHINT */
946                osi_UFSClose(tfile);
947
948             if (code) {
949                 error = code;
950                 break;
951             }
952         }
953         /* otherwise we've read some, fixup length, etc and continue with next seg */
954         len = len - tuio.afsio_resid; /* compute amount really transferred */
955         trimlen = len;
956         afsio_skip(auio, trimlen);          /* update input uio structure */
957         totalLength -= len;
958         transferLength += len;
959         filePos += len;
960         if (len <= 0) break;    /* surprise eof */
961     }
962
963     /* if we make it here with tdc non-zero, then it is the last chunk we
964      * dealt with, and we have to release it when we're done.  We hold on
965      * to it in case we need to do a prefetch, obviously.
966      */
967     if (tdc) {
968         ReleaseReadLock(&tdc->lock);
969 #ifndef AFS_VM_RDWR_ENV
970         /* try to queue prefetch, if needed */
971         if (!noLock) {
972             if (!(tdc->mflags & DFNextStarted))
973                 afs_PrefetchChunk(avc, tdc, acred, &treq);
974         }
975 #endif
976         afs_PutDCache(tdc);
977     }
978     if (!noLock)
979         ReleaseReadLock(&avc->lock);
980
981     osi_FreeSmallSpace(tvec);
982     error = afs_CheckCode(error, &treq, 13);
983     return error;
984 }