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