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