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