background daemon genericization
[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(register 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     register 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 #ifdef AFS_DISCON_ENV
440         /*
441          * In disconnected mode, type 2 can return 0 because it doesn't
442          * make any sense to allocate a dcache we can never fill
443          */
444          if (tdc == NULL)
445              return;
446 #endif /* AFS_DISCON_ENV */
447
448         ObtainSharedLock(&tdc->mflock, 651);
449         if (!(tdc->mflags & DFFetchReq)) {
450             /* ask the daemon to do the work */
451             UpgradeSToWLock(&tdc->mflock, 652);
452             tdc->mflags |= DFFetchReq;  /* guaranteed to be cleared by BKG or GetDCache */
453             /* last parm (1) tells bkg daemon to do an afs_PutDCache when it is done,
454              * since we don't want to wait for it to finish before doing so ourselves.
455              */
456             bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
457                             (afs_size_t) offset, (afs_size_t) 1, tdc,
458                             (void *)0, (void *)0);
459             if (!bp) {
460                 /* Bkg table full; just abort non-important prefetching to avoid deadlocks */
461                 tdc->mflags &= ~DFFetchReq;
462                 ReleaseWriteLock(&tdc->mflock);
463                 afs_PutDCache(tdc);
464
465                 /*
466                  * DCLOCKXXX: This is a little sketchy, since someone else
467                  * could have already started a prefetch..  In practice,
468                  * this probably doesn't matter; at most it would cause an
469                  * extra slot in the BKG table to be used up when someone
470                  * prefetches this for the second time.
471                  */
472                 ObtainReadLock(&adc->lock);
473                 ObtainWriteLock(&adc->mflock, 664);
474                 adc->mflags &= ~DFNextStarted;
475                 ReleaseWriteLock(&adc->mflock);
476                 ReleaseReadLock(&adc->lock);
477             } else {
478                 ReleaseWriteLock(&tdc->mflock);
479             }
480         } else {
481             ReleaseSharedLock(&tdc->mflock);
482             afs_PutDCache(tdc);
483         }
484     } else {
485         ReleaseSharedLock(&adc->mflock);
486         ReleaseReadLock(&adc->lock);
487     }
488 }
489
490 int
491 afs_UFSRead(register struct vcache *avc, struct uio *auio,
492             afs_ucred_t *acred, daddr_t albn, struct buf **abpp,
493             int noLock)
494 {
495     afs_size_t totalLength;
496     afs_size_t transferLength;
497     afs_size_t filePos;
498     afs_size_t offset, len, tlen;
499     afs_int32 trimlen;
500     struct dcache *tdc = 0;
501     afs_int32 error;
502 #ifdef AFS_DARWIN80_ENV
503     uio_t tuiop=NULL;
504 #else
505     struct uio tuio;
506     struct uio *tuiop = &tuio;
507     struct iovec *tvec;
508 #endif
509     struct osi_file *tfile;
510     afs_int32 code;
511     int trybusy = 1;
512     struct vrequest treq;
513
514     AFS_STATCNT(afs_UFSRead);
515     if (avc && avc->vc_error)
516         return EIO;
517
518     AFS_DISCON_LOCK();
519     
520     /* check that we have the latest status info in the vnode cache */
521     if ((code = afs_InitReq(&treq, acred)))
522         return code;
523     if (!noLock) {
524         if (!avc)
525             osi_Panic("null avc in afs_UFSRead");
526         else {
527             code = afs_VerifyVCache(avc, &treq);
528             if (code) {
529                 code = afs_CheckCode(code, &treq, 11);  /* failed to get it */
530                 AFS_DISCON_UNLOCK();
531                 return code;
532             }
533         }
534     }
535 #ifndef AFS_VM_RDWR_ENV
536     if (AFS_NFSXLATORREQ(acred)) {
537         if (!afs_AccessOK
538             (avc, PRSFS_READ, &treq,
539              CHECK_MODE_BITS | CMB_ALLOW_EXEC_AS_READ)) {
540             AFS_DISCON_UNLOCK();
541             return afs_CheckCode(EACCES, &treq, 12);
542         }
543     }
544 #endif
545
546 #ifndef AFS_DARWIN80_ENV
547     tvec = (struct iovec *)osi_AllocSmallSpace(sizeof(struct iovec));
548 #endif
549     totalLength = AFS_UIO_RESID(auio);
550     filePos = AFS_UIO_OFFSET(auio);
551     afs_Trace4(afs_iclSetp, CM_TRACE_READ, ICL_TYPE_POINTER, avc,
552                ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(filePos), ICL_TYPE_INT32,
553                totalLength, ICL_TYPE_OFFSET,
554                ICL_HANDLE_OFFSET(avc->f.m.Length));
555     error = 0;
556     transferLength = 0;
557     if (!noLock)
558         ObtainReadLock(&avc->lock);
559 #if     defined(AFS_TEXT_ENV) && !defined(AFS_VM_RDWR_ENV)
560     if (avc->flushDV.high == AFS_MAXDV && avc->flushDV.low == AFS_MAXDV) {
561         hset(avc->flushDV, avc->f.m.DataVersion);
562     }
563 #endif
564
565     if (filePos >= avc->f.m.Length) {
566         if (len > AFS_ZEROS)
567             len = sizeof(afs_zeros);    /* and in 0 buffer */
568         len = 0;
569 #ifdef AFS_DARWIN80_ENV
570         trimlen = len;
571         tuiop = afsio_darwin_partialcopy(auio, trimlen);
572 #else
573         afsio_copy(auio, &tuio, tvec);
574         trimlen = len;
575         afsio_trim(&tuio, trimlen);
576 #endif
577         AFS_UIOMOVE(afs_zeros, trimlen, UIO_READ, tuiop, code);
578     }
579
580     while (avc->f.m.Length > 0 && totalLength > 0) {
581         /* read all of the cached info */
582         if (filePos >= avc->f.m.Length)
583             break;              /* all done */
584         if (noLock) {
585             if (tdc) {
586                 ReleaseReadLock(&tdc->lock);
587                 afs_PutDCache(tdc);
588             }
589             tdc = afs_FindDCache(avc, filePos);
590             if (tdc) {
591                 ObtainReadLock(&tdc->lock);
592                 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
593                 len = tdc->validPos - filePos;
594             }
595         } else {
596             /* a tricky question: does the presence of the DFFetching flag
597              * mean that we're fetching the latest version of the file?  No.
598              * The server could update the file as soon as the fetch responsible
599              * for the setting of the DFFetching flag completes.
600              * 
601              * However, the presence of the DFFetching flag (visible under
602              * a dcache read lock since it is set and cleared only under a
603              * dcache write lock) means that we're fetching as good a version
604              * as was known to this client at the time of the last call to
605              * afs_VerifyVCache, since the latter updates the stat cache's
606              * m.DataVersion field under a vcache write lock, and from the
607              * time that the DFFetching flag goes on in afs_GetDCache (before
608              * the fetch starts), to the time it goes off (after the fetch
609              * completes), afs_GetDCache keeps at least a read lock on the
610              * vcache entry.
611              * 
612              * This means that if the DFFetching flag is set, we can use that
613              * data for any reads that must come from the current version of
614              * the file (current == m.DataVersion).
615              * 
616              * Another way of looking at this same point is this: if we're
617              * fetching some data and then try do an afs_VerifyVCache, the
618              * VerifyVCache operation will not complete until after the
619              * DFFetching flag is turned off and the dcache entry's f.versionNo
620              * field is updated.
621              * 
622              * Note, by the way, that if DFFetching is set,
623              * m.DataVersion > f.versionNo (the latter is not updated until
624              * after the fetch completes).
625              */
626             if (tdc) {
627                 ReleaseReadLock(&tdc->lock);
628                 afs_PutDCache(tdc);     /* before reusing tdc */
629             }
630             tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 2);
631 #ifdef AFS_DISCON_ENV
632             if (!tdc) {
633                 printf("Network down in afs_read");
634                 error = ENETDOWN;
635                 break;
636             }
637 #endif /* AFS_DISCON_ENV */
638
639             ObtainReadLock(&tdc->lock);
640             /* now, first try to start transfer, if we'll need the data.  If
641              * data already coming, we don't need to do this, obviously.  Type
642              * 2 requests never return a null dcache entry, btw. */
643             if (!(tdc->dflags & DFFetching)
644                 && !hsame(avc->f.m.DataVersion, tdc->f.versionNo)) {
645                 /* have cache entry, it is not coming in now, and we'll need new data */
646               tagain:
647                 if (trybusy && !afs_BBusy()) {
648                     struct brequest *bp;
649                     /* daemon is not busy */
650                     ObtainSharedLock(&tdc->mflock, 667);
651                     if (!(tdc->mflags & DFFetchReq)) {
652                         UpgradeSToWLock(&tdc->mflock, 668);
653                         tdc->mflags |= DFFetchReq;
654                         bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
655                                         (afs_size_t) filePos, (afs_size_t) 0,
656                                         tdc, (void *)0, (void *)0);
657                         if (!bp) {
658                             /* Bkg table full; retry deadlocks */
659                             tdc->mflags &= ~DFFetchReq;
660                             trybusy = 0;        /* Avoid bkg daemon since they're too busy */
661                             ReleaseWriteLock(&tdc->mflock);
662                             goto tagain;
663                         }
664                         ConvertWToSLock(&tdc->mflock);
665                     }
666                     code = 0;
667                     ConvertSToRLock(&tdc->mflock);
668                     while (!code && tdc->mflags & DFFetchReq) {
669                         afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT,
670                                    ICL_TYPE_STRING, __FILE__, ICL_TYPE_INT32,
671                                    __LINE__, ICL_TYPE_POINTER, tdc,
672                                    ICL_TYPE_INT32, tdc->dflags);
673                         /* don't need waiting flag on this one */
674                         ReleaseReadLock(&tdc->mflock);
675                         ReleaseReadLock(&tdc->lock);
676                         ReleaseReadLock(&avc->lock);
677                         code = afs_osi_SleepSig(&tdc->validPos);
678                         ObtainReadLock(&avc->lock);
679                         ObtainReadLock(&tdc->lock);
680                         ObtainReadLock(&tdc->mflock);
681                     }
682                     ReleaseReadLock(&tdc->mflock);
683                     if (code) {
684                         error = code;
685                         break;
686                     }
687                 }
688             }
689             /* now data may have started flowing in (if DFFetching is on).  If
690              * data is now streaming in, then wait for some interesting stuff.
691              */
692             code = 0;
693             while (!code && (tdc->dflags & DFFetching)
694                    && tdc->validPos <= filePos) {
695                 /* too early: wait for DFFetching flag to vanish,
696                  * or data to appear */
697                 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
698                            __FILE__, ICL_TYPE_INT32, __LINE__,
699                            ICL_TYPE_POINTER, tdc, ICL_TYPE_INT32,
700                            tdc->dflags);
701                 ReleaseReadLock(&tdc->lock);
702                 ReleaseReadLock(&avc->lock);
703                 code = afs_osi_SleepSig(&tdc->validPos);
704                 ObtainReadLock(&avc->lock);
705                 ObtainReadLock(&tdc->lock);
706             }
707             if (code) {
708                 error = code;
709                 break;
710             }
711             /* fetching flag gone, data is here, or we never tried
712              * (BBusy for instance) */
713             if (tdc->dflags & DFFetching) {
714                 /* still fetching, some new data is here:
715                  * compute length and offset */
716                 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
717                 len = tdc->validPos - filePos;
718             } else {
719                 /* no longer fetching, verify data version (avoid new
720                  * GetDCache call) */
721                 if (hsame(avc->f.m.DataVersion, tdc->f.versionNo)
722                     && ((len = tdc->validPos - filePos) > 0)) {
723                     offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
724                 } else {
725                     /* don't have current data, so get it below */
726                     afs_Trace3(afs_iclSetp, CM_TRACE_VERSIONNO,
727                                ICL_TYPE_INT64, ICL_HANDLE_OFFSET(filePos),
728                                ICL_TYPE_HYPER, &avc->f.m.DataVersion,
729                                ICL_TYPE_HYPER, &tdc->f.versionNo);
730                     ReleaseReadLock(&tdc->lock);
731                     afs_PutDCache(tdc);
732                     tdc = NULL;
733                 }
734             }
735
736             if (!tdc) {
737                 /* If we get, it was not possible to start the 
738                  * background daemon. With flag == 1 afs_GetDCache
739                  * does the FetchData rpc synchronously.
740                  */
741                 ReleaseReadLock(&avc->lock);
742                 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 1);
743                 ObtainReadLock(&avc->lock);
744                 if (tdc)
745                     ObtainReadLock(&tdc->lock);
746             }
747         }
748
749         if (!tdc) {
750             error = EIO;
751             break;
752         }
753         len = tdc->validPos - filePos;
754         afs_Trace3(afs_iclSetp, CM_TRACE_VNODEREAD, ICL_TYPE_POINTER, tdc,
755                    ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(offset),
756                    ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(len));
757         if (len > totalLength)
758             len = totalLength;  /* will read len bytes */
759         if (len <= 0) {         /* shouldn't get here if DFFetching is on */
760             afs_Trace4(afs_iclSetp, CM_TRACE_VNODEREAD2, ICL_TYPE_POINTER,
761                        tdc, ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(tdc->validPos),
762                        ICL_TYPE_INT32, tdc->f.chunkBytes, ICL_TYPE_INT32,
763                        tdc->dflags);
764             /* read past the end of a chunk, may not be at next chunk yet, and yet
765              * also not at eof, so may have to supply fake zeros */
766             len = AFS_CHUNKTOSIZE(tdc->f.chunk) - offset;       /* bytes left in chunk addr space */
767             if (len > totalLength)
768                 len = totalLength;      /* and still within xfr request */
769             tlen = avc->f.m.Length - offset;    /* and still within file */
770             if (len > tlen)
771                 len = tlen;
772             if (len > AFS_ZEROS)
773                 len = sizeof(afs_zeros);        /* and in 0 buffer */
774 #ifdef AFS_DARWIN80_ENV
775             trimlen = len;
776             tuiop = afsio_darwin_partialcopy(auio, trimlen);
777 #else
778             afsio_copy(auio, &tuio, tvec);
779             trimlen = len;
780             afsio_trim(&tuio, trimlen);
781 #endif
782             AFS_UIOMOVE(afs_zeros, trimlen, UIO_READ, tuiop, code);
783             if (code) {
784                 error = code;
785                 break;
786             }
787         } else {
788             /* get the data from the file */
789             tfile = (struct osi_file *)osi_UFSOpen(&tdc->f.inode);
790 #ifdef AFS_DARWIN80_ENV
791             trimlen = len;
792             tuiop = afsio_darwin_partialcopy(auio, trimlen);
793             uio_setoffset(tuiop, offset);
794 #else
795             /* mung uio structure to be right for this transfer */
796             afsio_copy(auio, &tuio, tvec);
797             trimlen = len;
798             afsio_trim(&tuio, trimlen);
799             tuio.afsio_offset = offset;
800 #endif
801
802 #if defined(AFS_AIX41_ENV)
803             AFS_GUNLOCK();
804             code =
805                 VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, &tuio, NULL, NULL,
806                           NULL, afs_osi_credp);
807             AFS_GLOCK();
808 #elif defined(AFS_AIX32_ENV)
809             code =
810                 VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, &tuio, NULL, NULL);
811             /* Flush all JFS pages now for big performance gain in big file cases
812              * If we do something like this, must check to be sure that AFS file 
813              * isn't mmapped... see afs_gn_map() for why.
814              */
815 /*
816           if (tfile->vnode->v_gnode && tfile->vnode->v_gnode->gn_seg) {
817  many different ways to do similar things:
818    so far, the best performing one is #2, but #1 might match it if we
819    straighten out the confusion regarding which pages to flush.  It 
820    really does matter.
821    1.       vm_flushp(tfile->vnode->v_gnode->gn_seg, 0, len/PAGESIZE - 1);
822    2.       vm_releasep(tfile->vnode->v_gnode->gn_seg, offset/PAGESIZE, 
823                         (len + PAGESIZE-1)/PAGESIZE);
824    3.       vms_inactive(tfile->vnode->v_gnode->gn_seg) Doesn't work correctly
825    4.       vms_delete(tfile->vnode->v_gnode->gn_seg) probably also fails
826             tfile->vnode->v_gnode->gn_seg = NULL;
827    5.       deletep
828    6.       ipgrlse
829    7.       ifreeseg
830           Unfortunately, this seems to cause frequent "cache corruption" episodes.
831             vm_releasep(tfile->vnode->v_gnode->gn_seg, offset/PAGESIZE, 
832                         (len + PAGESIZE-1)/PAGESIZE);
833           }     
834 */
835 #elif defined(AFS_AIX_ENV)
836             code =
837                 VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, (off_t) & offset,
838                           &tuio, NULL, NULL, -1);
839 #elif defined(AFS_SUN5_ENV)
840             AFS_GUNLOCK();
841 #ifdef AFS_SUN510_ENV
842             {
843                 caller_context_t ct;
844
845                 VOP_RWLOCK(tfile->vnode, 0, &ct);
846                 code = VOP_READ(tfile->vnode, &tuio, 0, afs_osi_credp, &ct);
847                 VOP_RWUNLOCK(tfile->vnode, 0, &ct);
848             }
849 #else
850             VOP_RWLOCK(tfile->vnode, 0);
851             code = VOP_READ(tfile->vnode, &tuio, 0, afs_osi_credp);
852             VOP_RWUNLOCK(tfile->vnode, 0);
853 #endif
854             AFS_GLOCK();
855 #elif defined(AFS_SGI_ENV)
856             AFS_GUNLOCK();
857             AFS_VOP_RWLOCK(tfile->vnode, VRWLOCK_READ);
858             AFS_VOP_READ(tfile->vnode, &tuio, IO_ISLOCKED, afs_osi_credp,
859                          code);
860             AFS_VOP_RWUNLOCK(tfile->vnode, VRWLOCK_READ);
861             AFS_GLOCK();
862 #elif defined(AFS_HPUX100_ENV)
863             AFS_GUNLOCK();
864             code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, afs_osi_credp);
865             AFS_GLOCK();
866 #elif defined(AFS_LINUX20_ENV)
867             AFS_GUNLOCK();
868             code = osi_rdwr(tfile, &tuio, UIO_READ);
869             AFS_GLOCK();
870 #elif defined(AFS_DARWIN80_ENV)
871             AFS_GUNLOCK();
872             code = VNOP_READ(tfile->vnode, tuiop, 0, afs_osi_ctxtp);
873             AFS_GLOCK();
874 #elif defined(AFS_DARWIN_ENV)
875             AFS_GUNLOCK();
876             VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, current_proc());
877             code = VOP_READ(tfile->vnode, &tuio, 0, afs_osi_credp);
878             VOP_UNLOCK(tfile->vnode, 0, current_proc());
879             AFS_GLOCK();
880 #elif defined(AFS_FBSD80_ENV)
881             AFS_GUNLOCK();
882             VOP_LOCK(tfile->vnode, LK_EXCLUSIVE);
883             code = VOP_READ(tfile->vnode, &tuio, 0, afs_osi_credp);
884             VOP_UNLOCK(tfile->vnode, 0);
885             AFS_GLOCK();
886 #elif defined(AFS_FBSD50_ENV)
887             AFS_GUNLOCK();
888             VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, curthread);
889             code = VOP_READ(tfile->vnode, &tuio, 0, afs_osi_credp);
890             VOP_UNLOCK(tfile->vnode, 0, curthread);
891             AFS_GLOCK();
892 #elif defined(AFS_XBSD_ENV)
893             AFS_GUNLOCK();
894             VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, curproc);
895             code = VOP_READ(tfile->vnode, &tuio, 0, afs_osi_credp);
896             VOP_UNLOCK(tfile->vnode, 0, curproc);
897             AFS_GLOCK();
898 #else
899             code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, afs_osi_credp);
900 #endif
901             osi_UFSClose(tfile);
902
903             if (code) {
904                 error = code;
905                 break;
906             }
907         }
908         /* otherwise we've read some, fixup length, etc and continue with next seg */
909         len = len - AFS_UIO_RESID(tuiop);       /* compute amount really transferred */
910         trimlen = len;
911         afsio_skip(auio, trimlen);      /* update input uio structure */
912         totalLength -= len;
913         transferLength += len;
914         filePos += len;
915         if (len <= 0)
916             break;              /* surprise eof */
917 #ifdef AFS_DARWIN80_ENV
918         if (tuiop) {
919             uio_free(tuiop);
920             tuiop = 0;
921         }
922 #endif
923     }
924
925     /* if we make it here with tdc non-zero, then it is the last chunk we
926      * dealt with, and we have to release it when we're done.  We hold on
927      * to it in case we need to do a prefetch, obviously.
928      */
929     if (tdc) {
930         ReleaseReadLock(&tdc->lock);
931 #if !defined(AFS_VM_RDWR_ENV)
932         /* try to queue prefetch, if needed */
933         if (!noLock) {
934             if (!(tdc->mflags & DFNextStarted))
935                 afs_PrefetchChunk(avc, tdc, acred, &treq);
936         }
937 #endif
938         afs_PutDCache(tdc);
939     }
940     if (!noLock)
941         ReleaseReadLock(&avc->lock);
942
943 #ifdef AFS_DARWIN80_ENV
944     if (tuiop)
945        uio_free(tuiop);
946 #else
947     osi_FreeSmallSpace(tvec);
948 #endif
949     AFS_DISCON_UNLOCK();
950     error = afs_CheckCode(error, &treq, 13);
951     return error;
952 }