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