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