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