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