aix-51-support-20030701
[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 #ifdef  AFS_AIX_ENV
712 #ifdef  AFS_AIX41_ENV
713           AFS_GUNLOCK();
714           code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, &tuio, NULL, NULL,
715                            NULL, &afs_osi_cred);
716           AFS_GLOCK();
717 #else
718 #ifdef AFS_AIX32_ENV
719             code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, &tuio, NULL, NULL);
720           /* Flush all JFS pages now for big performance gain in big file cases
721            * If we do something like this, must check to be sure that AFS file 
722            * isn't mmapped... see afs_gn_map() for why.
723           */
724 /*
725           if (tfile->vnode->v_gnode && tfile->vnode->v_gnode->gn_seg) {
726  many different ways to do similar things:
727    so far, the best performing one is #2, but #1 might match it if we
728    straighten out the confusion regarding which pages to flush.  It 
729    really does matter.
730    1.       vm_flushp(tfile->vnode->v_gnode->gn_seg, 0, len/PAGESIZE - 1);
731    2.       vm_releasep(tfile->vnode->v_gnode->gn_seg, offset/PAGESIZE, 
732                         (len + PAGESIZE-1)/PAGESIZE);
733    3.       vms_inactive(tfile->vnode->v_gnode->gn_seg) Doesn't work correctly
734    4.       vms_delete(tfile->vnode->v_gnode->gn_seg) probably also fails
735             tfile->vnode->v_gnode->gn_seg = NULL;
736    5.       deletep
737    6.       ipgrlse
738    7.       ifreeseg
739           Unfortunately, this seems to cause frequent "cache corruption" episodes.
740             vm_releasep(tfile->vnode->v_gnode->gn_seg, offset/PAGESIZE, 
741                         (len + PAGESIZE-1)/PAGESIZE);
742           }     
743 */
744 #else
745             code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, (off_t)&offset, &tuio, NULL, NULL, -1);
746 #endif
747 #endif
748 #else
749 #ifdef  AFS_SUN5_ENV
750           AFS_GUNLOCK();
751             VOP_RWLOCK(tfile->vnode, 0);
752             code = VOP_READ(tfile->vnode, &tuio, 0, &afs_osi_cred);
753             VOP_RWUNLOCK(tfile->vnode, 0);
754           AFS_GLOCK();
755 #else
756 #if defined(AFS_SGI_ENV)
757             AFS_GUNLOCK();
758             AFS_VOP_RWLOCK(tfile->vnode, VRWLOCK_READ);
759             AFS_VOP_READ(tfile->vnode, &tuio, IO_ISLOCKED, &afs_osi_cred,
760                          code);
761             AFS_VOP_RWUNLOCK(tfile->vnode, VRWLOCK_READ);
762             AFS_GLOCK();
763 #else
764 #ifdef  AFS_OSF_ENV
765             tuio.uio_rw = UIO_READ;
766             AFS_GUNLOCK();
767             VOP_READ(tfile->vnode, &tuio, 0, &afs_osi_cred, code);
768             AFS_GLOCK();
769 #else   /* AFS_OSF_ENV */
770 #ifdef AFS_SUN_ENV
771             code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, &afs_osi_cred);
772 #else
773 #if     defined(AFS_HPUX100_ENV)
774             AFS_GUNLOCK();
775             code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, &afs_osi_cred);
776             AFS_GLOCK();
777 #else
778 #if defined(AFS_LINUX20_ENV)
779             AFS_GUNLOCK();
780             code = osi_file_uio_rdwr(tfile, &tuio, UIO_READ);
781             AFS_GLOCK();
782 #else
783 #if defined(AFS_DARWIN_ENV)
784             AFS_GUNLOCK();
785             VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, current_proc());
786             code = VOP_READ(tfile->vnode, &tuio, 0, &afs_osi_cred);
787             VOP_UNLOCK(tfile->vnode, 0, current_proc());
788             AFS_GLOCK();
789 #else
790 #if defined(AFS_XBSD_ENV)
791             AFS_GUNLOCK();
792             VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, curproc);
793             code = VOP_READ(tfile->vnode, &tuio, 0, &afs_osi_cred);
794             VOP_UNLOCK(tfile->vnode, 0, curproc);
795             AFS_GLOCK();
796 #else
797             code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, &afs_osi_cred);
798 #endif
799 #endif
800 #endif
801 #endif
802 #endif
803 #endif
804 #endif
805 #endif
806 #endif
807
808 #ifdef IHINT
809              if (!tdc->ihint && nihints < maxIHint) {
810                tdc->ihint = tfile;
811                nihints++;
812              }
813              else
814 #endif /* IHINT */
815                osi_UFSClose(tfile);
816
817             if (code) {
818                 error = code;
819                 break;
820             }
821         }
822         /* otherwise we've read some, fixup length, etc and continue with next seg */
823         len = len - tuio.afsio_resid; /* compute amount really transferred */
824         trimlen = len;
825         afsio_skip(auio, trimlen);          /* update input uio structure */
826         totalLength -= len;
827         transferLength += len;
828         filePos += len;
829         if (len <= 0) break;    /* surprise eof */
830     }
831
832     /* if we make it here with tdc non-zero, then it is the last chunk we
833      * dealt with, and we have to release it when we're done.  We hold on
834      * to it in case we need to do a prefetch, obviously.
835      */
836     if (tdc) {
837         ReleaseReadLock(&tdc->lock);
838 #if !defined(AFS_VM_RDWR_ENV)
839         /* try to queue prefetch, if needed */
840         if (!noLock) {
841             if (!(tdc->mflags & DFNextStarted))
842                 afs_PrefetchChunk(avc, tdc, acred, &treq);
843         }
844 #endif
845         afs_PutDCache(tdc);
846     }
847     if (!noLock)
848         ReleaseReadLock(&avc->lock);
849
850     osi_FreeSmallSpace(tvec);
851     error = afs_CheckCode(error, &treq, 13);
852     return error;
853 }