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