initial-darwin-support-20010327
[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_UFSReadFast
15  * afs_UFSRead
16  * 
17  */
18
19 #include "../afs/param.h"       /* Should be always first */
20 #include "../afs/sysincludes.h" /* Standard vendor system headers */
21 #include "../afs/afsincludes.h" /* Afs-based standard headers */
22 #include "../afs/afs_stats.h" /* statistics */
23 #include "../afs/afs_cbqueue.h"
24 #include "../afs/nfsclient.h"
25 #include "../afs/afs_osidnlc.h"
26
27
28 extern char afs_zeros[AFS_ZEROS];
29
30 afs_int32 maxIHint;
31 afs_int32 nihints;                           /* # of above actually in-use */
32 afs_int32 usedihint;
33
34
35 /* Imported variables */
36 extern afs_rwlock_t afs_xdcache;
37 extern unsigned char *afs_indexFlags;
38 extern afs_hyper_t *afs_indexTimes;          /* Dcache entry Access times */
39 extern afs_hyper_t afs_indexCounter;         /* Fake time for marking index */
40
41
42 /* Forward declarations */
43 void afs_PrefetchChunk(struct vcache *avc, struct dcache *adc,
44                               struct AFS_UCRED *acred, struct vrequest *areq);
45
46 afs_MemRead(avc, auio, acred, albn, abpp, noLock)
47     register struct vcache *avc;
48     struct uio *auio;
49     struct AFS_UCRED *acred;
50     daddr_t albn;
51     int noLock;
52     struct buf **abpp; {
53     afs_int32 totalLength;
54     afs_int32 transferLength;
55     afs_int32 filePos;
56     struct dcache *tdc=0;
57     afs_int32 offset, len, error, trybusy=1;
58     struct uio tuio;
59     struct iovec *tvec;
60     char *tfile;
61     afs_int32 code;
62     struct vrequest treq;
63
64     AFS_STATCNT(afs_MemRead);
65     if (avc->vc_error)
66         return EIO;
67
68     /* check that we have the latest status info in the vnode cache */
69     if (code = afs_InitReq(&treq, acred)) return code;
70     if (!noLock) {
71         code = afs_VerifyVCache(avc, &treq);
72         if (code) {
73           code = afs_CheckCode(code, &treq, 8); /* failed to get it */
74           return code;
75         }
76     }
77
78 #ifndef AFS_VM_RDWR_ENV
79     if (AFS_NFSXLATORREQ(acred)) {
80         if (!afs_AccessOK(avc, PRSFS_READ, &treq,
81                           CHECK_MODE_BITS|CMB_ALLOW_EXEC_AS_READ)) {
82             return afs_CheckCode(EACCES, &treq, 9);
83         }
84     }
85 #endif
86
87     tvec = (struct iovec *) osi_AllocSmallSpace(sizeof(struct iovec));
88     totalLength = auio->afsio_resid;
89     filePos = auio->afsio_offset;
90     afs_Trace4(afs_iclSetp, CM_TRACE_READ, ICL_TYPE_POINTER, avc, 
91                ICL_TYPE_INT32, filePos, ICL_TYPE_INT32, totalLength,
92                ICL_TYPE_INT32, avc->m.Length);
93     error = 0;
94     transferLength = 0;
95     if (!noLock)
96         ObtainReadLock(&avc->lock);
97 #if     defined(AFS_TEXT_ENV) && !defined(AFS_VM_RDWR_ENV)
98     if (avc->flushDV.high == AFS_MAXDV && avc->flushDV.low == AFS_MAXDV) {
99         hset(avc->flushDV, avc->m.DataVersion);
100     }
101 #endif
102     while (totalLength > 0) {
103         /* read all of the cached info */
104         if (filePos >= avc->m.Length) break;    /* all done */
105         if (noLock) {
106             if (tdc) afs_PutDCache(tdc);
107             tdc = afs_FindDCache(avc, filePos);
108             if (tdc) {
109                 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
110                 len = tdc->f.chunkBytes - offset;
111             }
112         } else {
113             /* a tricky question: does the presence of the DFFetching flag
114                mean that we're fetching the latest version of the file?  No.
115                The server could update the file as soon as the fetch responsible
116                for the setting of the DFFetching flag completes.
117             
118                However, the presence of the DFFetching flag (visible under a
119                read lock since it is set and cleared only under a write lock)
120                means that we're fetching as good a version as was known to this
121                client at the time of the last call to afs_VerifyVCache, since
122                the latter updates the stat cache's m.DataVersion field under a
123                write lock, and from the time that the DFFetching flag goes on
124                (before the fetch starts), to the time it goes off (after the
125                fetch completes), afs_GetDCache keeps at least a read lock
126                (actually it keeps an S lock) on the cache entry.
127             
128                This means that if the DFFetching flag is set, we can use that
129                data for any reads that must come from the current version of
130                the file (current == m.DataVersion).
131              
132                Another way of looking at this same point is this: if we're
133                fetching some data and then try do an afs_VerifyVCache, the
134                VerifyVCache operation will not complete until after the
135                DFFetching flag is turned off and the dcache entry's f.versionNo
136                field is updated.
137              
138                Note, by the way, that if DFFetching is set,
139                m.DataVersion > f.versionNo (the latter is not updated until
140                after the fetch completes).
141              */
142             if (tdc) afs_PutDCache(tdc);        /* before reusing tdc */
143             tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 2);
144             /* now, first try to start transfer, if we'll need the data.  If
145              * data already coming, we don't need to do this, obviously.  Type
146              * 2 requests never return a null dcache entry, btw.
147              */
148             if (!(tdc->flags & DFFetching)
149                 && !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
150                 /* have cache entry, it is not coming in now,
151                  * and we'll need new data */
152 tagain:
153                 if (trybusy && !afs_BBusy()) {
154                     struct brequest *bp;
155                     /* daemon is not busy */
156                     if (!(tdc->flags & DFFetchReq)) {
157                         /* start the daemon (may already be running, however) */
158                         tdc->flags |= DFFetchReq;
159                         bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
160                                         (long)filePos, (long) tdc, 0L, 0L);
161                         if (!bp) {
162                             tdc->flags &= ~DFFetchReq;
163                             trybusy = 0;        /* Avoid bkg daemon since they're too busy */
164                             goto tagain;
165                         }
166                         /* don't use bp pointer! */
167                     }
168                     while (tdc->flags & DFFetchReq) {
169                         /* don't need waiting flag on this one */
170                         ReleaseReadLock(&avc->lock);
171                         afs_osi_Sleep(&tdc->validPos);
172                         ObtainReadLock(&avc->lock);
173                     }
174                 }
175             }
176             /* now data may have started flowing in (if DFFetching is on).  If
177              * data is now streaming in, then wait for some interesting stuff. */
178             while ((tdc->flags & DFFetching) && tdc->validPos <= filePos) {
179                 /* too early: wait for DFFetching flag to vanish, or data to appear */
180                 tdc->flags |= DFWaiting;
181                 ReleaseReadLock(&avc->lock);
182                 afs_osi_Sleep(&tdc->validPos);
183                 ObtainReadLock(&avc->lock);
184             }
185             /* fetching flag gone, data is here, or we never tried (BBusy for instance) */
186             if (tdc->flags & DFFetching) {
187                 /* still fetching, some new data is here: compute length and offset */
188                 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
189                 len = tdc->validPos - filePos;
190             }
191             else {
192                 /* no longer fetching, verify data version (avoid new GetDCache call) */
193                 if (hsame(avc->m.DataVersion, tdc->f.versionNo)) {
194                     offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
195                     len = tdc->f.chunkBytes - offset;
196                 }
197                 else {
198                     /* don't have current data, so get it below */
199                     afs_PutDCache(tdc);
200                     tdc = (struct dcache *) 0;
201                 }
202             }
203
204             if (!tdc) {
205                 ReleaseReadLock(&avc->lock);
206                 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 1);
207                 ObtainReadLock(&avc->lock);
208             }
209         }
210
211         if (!tdc) {
212             error = EIO;
213             break;
214         }
215         if (len > totalLength) len = totalLength;   /* will read len bytes */
216         if (len <= 0) { /* shouldn't get here if DFFetching is on */
217             /* read past the end of a chunk, may not be at next chunk yet, and yet
218                 also not at eof, so may have to supply fake zeros */
219             len = AFS_CHUNKTOSIZE(tdc->f.chunk) - offset; /* bytes left in chunk addr space */
220             if (len > totalLength) len = totalLength;   /* and still within xfr request */
221             code = avc->m.Length - offset; /* and still within file */
222             if (len > code) len = code;
223             if (len > AFS_ZEROS) len = sizeof(afs_zeros);   /* and in 0 buffer */
224             afsio_copy(auio, &tuio, tvec);
225             afsio_trim(&tuio, len);
226             AFS_UIOMOVE(afs_zeros, len, UIO_READ, &tuio, code);
227             if (code) {
228                 error = code;
229                 break;
230             }
231         }
232         else {
233             /* get the data from the mem cache */
234
235             /* mung uio structure to be right for this transfer */
236             afsio_copy(auio, &tuio, tvec);
237             afsio_trim(&tuio, len);
238             tuio.afsio_offset = offset;
239
240             code = afs_MemReadUIO(tdc->f.inode, &tuio);
241
242             if (code) {
243                 error = code;
244                 break;
245             }
246         }
247         /* otherwise we've read some, fixup length, etc and continue with next seg */
248         len = len - tuio.afsio_resid; /* compute amount really transferred */
249         afsio_skip(auio, len);      /* update input uio structure */
250         totalLength -= len;
251         transferLength += len;
252         filePos += len;
253
254         if (len <= 0) break;    /* surprise eof */
255     }   /* the whole while loop */
256
257     /* if we make it here with tdc non-zero, then it is the last chunk we
258      * dealt with, and we have to release it when we're done.  We hold on
259      * to it in case we need to do a prefetch.
260      */
261     if (tdc) {
262 #ifndef AFS_VM_RDWR_ENV
263         /* try to queue prefetch, if needed */
264         if (!(tdc->flags & DFNextStarted) && !noLock) {
265             afs_PrefetchChunk(avc, tdc, acred, &treq);
266         }
267 #endif
268         afs_PutDCache(tdc);
269     }
270     if (!noLock)
271         ReleaseReadLock(&avc->lock);
272     osi_FreeSmallSpace(tvec);
273     error = afs_CheckCode(error, &treq, 10);
274     return error;
275 }
276
277 /* called with the dcache entry triggering the fetch, the vcache entry involved,
278  * and a vrequest for the read call.  Marks the dcache entry as having already
279  * triggered a prefetch, starts the prefetch going and sets the DFFetchReq
280  * flag in the prefetched block, so that the next call to read knows to wait
281  * for the daemon to start doing things.
282  *
283  * This function must be called with the vnode at least read-locked
284  * because it plays around with dcache entries.
285  */
286 void afs_PrefetchChunk(struct vcache *avc, struct dcache *adc,
287                               struct AFS_UCRED *acred, struct vrequest *areq)
288 {
289     register struct dcache *tdc;
290     register afs_int32 offset;
291     afs_int32 j1, j2;   /* junk vbls for GetDCache to trash */
292
293     offset = adc->f.chunk+1;            /* next chunk we'll need */
294     offset = AFS_CHUNKTOBASE(offset);   /* base of next chunk */
295     if (offset < avc->m.Length && !afs_BBusy()) {
296         struct brequest *bp;
297         adc->flags |= DFNextStarted;    /* we've tried to prefetch for this guy */
298         tdc = afs_GetDCache(avc, offset, areq, &j1, &j2, 2);    /* type 2 never returns 0 */
299         if (!(tdc->flags & DFFetchReq)) {
300             /* ask the daemon to do the work */
301             tdc->flags |= DFFetchReq;   /* guaranteed to be cleared by BKG or GetDCache */
302             /* last parm (1) tells bkg daemon to do an afs_PutDCache when it is done,
303              * since we don't want to wait for it to finish before doing so ourselves.
304              */
305 #ifdef  AFS_SUN5_ENVX
306             mutex_exit(&tdc->lock);
307 #endif
308             bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred, (long)offset,
309                             (long) tdc, 1L, 0L, 0L);
310             if (!bp) {
311                 /* Bkg table full; just abort non-important prefetching to avoid deadlocks */
312                 tdc->flags &= ~(DFNextStarted | DFFetchReq);
313                 afs_PutDCache(tdc);
314                 return;
315             }
316         }
317         else
318             afs_PutDCache(tdc);
319     }
320 }
321
322
323 /* if the vcache is up-to-date, and the request fits entirely into the chunk
324  * that the hint here references, then we just use it quickly, otherwise we
325  * have to call the slow read.
326  *
327  * This could be generalized in several ways to take advantage of partial 
328  * state even when all the chips don't fall the right way.  For instance,
329  * if the hint is good and the first part of the read request can be 
330  * satisfied from the chunk, then just do the read.  After the read has
331  * completed, check to see if there's more. (Chances are there won't be.)
332  * If there is more, then just call afs_UFSReadSlow and let it do the rest.
333  *
334  * For the time being, I'm ignoring quick.f, but it should be used at
335  * some future date.
336  * do this in the future avc->quick.f = tfile; but I think it
337  * has to be done under a write lock, but don't want to wait on the
338  * write lock
339  */
340     /* everywhere that a dcache can be freed (look for NULLIDX) 
341      * probably does it under a write lock on xdcache.  Need to invalidate
342      * stamp there, too.  
343      * Also need to worry about DFFetching, and IFFree, I think. */
344 static struct dcache *savedc = 0;
345
346 afs_UFSReadFast(avc, auio, acred, albn, abpp, noLock)
347     register struct vcache *avc;
348     struct uio *auio;
349     struct AFS_UCRED *acred;
350     int noLock;
351     daddr_t albn;
352     struct buf **abpp; {
353     struct vrequest treq;
354     int offDiff;
355     struct dcache *tdc;
356     struct vnode *vp;
357     struct osi_file *tfile;
358     afs_int32 code = 0;
359
360     if (!noLock)
361         ObtainReadLock(&avc->lock);  
362     ObtainReadLock(&afs_xdcache);
363
364     if ((avc->states & CStatd)                                /* up to date */
365         && (tdc = avc->quick.dc) && (tdc->index != NULLIDX) 
366         && !(afs_indexFlags[tdc->index] & IFFree))   {
367
368         tdc->refCount++;
369         ReleaseReadLock(&afs_xdcache);
370
371         if ((tdc->stamp == avc->quick.stamp)                /* hint matches */
372             && ((offDiff = (auio->afsio_offset - avc->quick.minLoc)) >= 0)
373             && (tdc->f.chunkBytes >= auio->afsio_resid + offDiff)
374             && !(tdc->flags & DFFetching)) { /* fits in chunk */
375
376             auio->afsio_offset -= avc->quick.minLoc;
377
378             tfile = (struct osi_file *)osi_UFSOpen(tdc->f.inode);
379
380 #ifdef  AFS_AIX_ENV
381 #ifdef  AFS_AIX41_ENV
382             AFS_GUNLOCK();
383             code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, auio, NULL, NULL, NULL, &afs_osi_cred);
384             AFS_GLOCK();
385 #else
386 #ifdef AFS_AIX32_ENV
387             code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, auio, NULL, NULL);
388 #else
389             code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, (off_t)&auio->afsio_offset, auio, NULL, NULL, -1);
390 #endif
391 #endif
392 #else
393 #ifdef  AFS_SUN5_ENV
394             AFS_GUNLOCK();
395             VOP_RWLOCK(tfile->vnode, 0);
396             code = VOP_READ(tfile->vnode, auio, 0, &afs_osi_cred);
397             VOP_RWUNLOCK(tfile->vnode, 0);
398             AFS_GLOCK();
399 #else
400 #if defined(AFS_SGI_ENV)
401             AFS_GUNLOCK();
402             AFS_VOP_RWLOCK(tfile->vnode, VRWLOCK_READ);
403             AFS_VOP_READ(tfile->vnode, auio, IO_ISLOCKED, &afs_osi_cred, code);
404             AFS_VOP_RWUNLOCK(tfile->vnode, VRWLOCK_READ);
405             AFS_GLOCK();
406 #else
407 #ifdef  AFS_OSF_ENV
408             auio->uio_rw = UIO_READ;
409             AFS_GUNLOCK();
410             VOP_READ(tfile->vnode, auio, 0, &afs_osi_cred, code);
411             AFS_GLOCK();
412 #else   /* AFS_OSF_ENV */
413 #if defined(AFS_HPUX100_ENV)
414             AFS_GUNLOCK();
415             code = VOP_RDWR(tfile->vnode, auio, UIO_READ, 0, &afs_osi_cred);
416             AFS_GLOCK();
417 #else
418 #if defined(AFS_LINUX20_ENV)
419             AFS_GUNLOCK();
420             code = osi_file_uio_rdwr(tfile, auio, UIO_READ);
421             AFS_GLOCK();
422 #else
423 #if defined(AFS_DARWIN_ENV)
424             AFS_GUNLOCK();
425             VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, current_proc());
426             code = VOP_READ(tfile->vnode, auio, 0, &afs_osi_cred);
427             VOP_UNLOCK(tfile->vnode, 0, current_proc());
428             AFS_GLOCK();
429 #else
430             code = VOP_RDWR(tfile->vnode, auio, UIO_READ, 0, &afs_osi_cred);
431 #endif
432 #endif
433 #endif
434 #endif
435 #endif
436 #endif
437 #endif
438             auio->afsio_offset += avc->quick.minLoc;
439             osi_UFSClose(tfile);
440             /* Fix up LRU info */
441             hset(afs_indexTimes[tdc->index], afs_indexCounter);
442             hadd32(afs_indexCounter, 1);
443
444             if (!noLock) {
445 #ifndef AFS_VM_RDWR_ENV
446                 if (!(code = afs_InitReq(&treq, acred))&& (!(tdc->flags & DFNextStarted)))
447                     afs_PrefetchChunk(avc, tdc, acred, &treq);
448 #endif
449                 ReleaseReadLock(&avc->lock);
450             }
451             tdc->refCount--;
452             return (code);
453         }
454         if (!tdc->f.chunkBytes) {   /* debugging f.chunkBytes == 0 problem */
455             savedc = tdc;
456         }
457         tdc->refCount--;
458     } else {
459         ReleaseReadLock(&afs_xdcache);
460     }
461
462     /* come here if fast path doesn't work for some reason or other */
463     if (!noLock)
464         ReleaseReadLock(&avc->lock);
465     return afs_UFSRead(avc, auio, acred, albn, abpp, noLock);
466 }
467
468 afs_UFSRead(avc, auio, acred, albn, abpp, noLock)
469     struct vcache *avc;
470     struct uio *auio;
471     struct AFS_UCRED *acred;
472     daddr_t albn;
473     int noLock;
474     struct buf **abpp; {
475     afs_int32 totalLength;
476     afs_int32 transferLength;
477     afs_int32 filePos;
478     struct dcache *tdc=0;
479     afs_int32 offset, len, error;
480     struct uio tuio;
481     struct iovec *tvec;
482     struct osi_file *tfile;
483     afs_int32 code;
484     int munlocked, trybusy=1;
485     struct vnode *vp;
486     struct vrequest treq;
487
488     AFS_STATCNT(afs_UFSRead);
489     if (avc->vc_error)
490         return EIO;
491
492     /* check that we have the latest status info in the vnode cache */
493     if (code = afs_InitReq(&treq, acred)) return code;
494     if (!noLock) {
495       if (!avc) 
496         osi_Panic ("null avc in afs_UFSRead");
497       else {
498         code = afs_VerifyVCache(avc, &treq);
499         if (code) {
500           code = afs_CheckCode(code, &treq, 11); /* failed to get it */
501           return code;
502         }
503       }
504     }
505
506 #ifndef AFS_VM_RDWR_ENV
507     if (AFS_NFSXLATORREQ(acred)) {
508         if (!afs_AccessOK(avc, PRSFS_READ, &treq,
509                           CHECK_MODE_BITS|CMB_ALLOW_EXEC_AS_READ)) {
510             return afs_CheckCode(EACCES, &treq, 12);
511         }
512     }
513 #endif
514
515     tvec = (struct iovec *) osi_AllocSmallSpace(sizeof(struct iovec));
516     totalLength = auio->afsio_resid;
517     filePos = auio->afsio_offset;
518     afs_Trace4(afs_iclSetp, CM_TRACE_READ, ICL_TYPE_POINTER, avc, 
519                ICL_TYPE_INT32, filePos, ICL_TYPE_INT32, totalLength,
520                ICL_TYPE_INT32, avc->m.Length);
521     error = 0;
522     transferLength = 0;
523     if (!noLock)
524         ObtainReadLock(&avc->lock);
525 #if     defined(AFS_TEXT_ENV) && !defined(AFS_VM_RDWR_ENV)
526     if (avc->flushDV.high == AFS_MAXDV && avc->flushDV.low == AFS_MAXDV) {
527         hset(avc->flushDV, avc->m.DataVersion);
528     }
529 #endif
530     
531     while (totalLength > 0) {
532         /* read all of the cached info */
533         if (filePos >= avc->m.Length) break;    /* all done */
534         if (noLock) {
535             if (tdc) afs_PutDCache(tdc);
536             tdc = afs_FindDCache(avc, filePos);
537             if (tdc) {
538                 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
539                 len = tdc->f.chunkBytes - offset;
540             }
541         } else {
542             /* a tricky question: does the presence of the DFFetching flag
543                mean that we're fetching the latest version of the file?  No.
544                The server could update the file as soon as the fetch responsible
545                for the setting of the DFFetching flag completes.
546             
547                However, the presence of the DFFetching flag (visible under a
548                read lock since it is set and cleared only under a write lock)
549                means that we're fetching as good a version as was known to this
550                client at the time of the last call to afs_VerifyVCache, since
551                the latter updates the stat cache's m.DataVersion field under a
552                write lock, and from the time that the DFFetching flag goes on
553                (before the fetch starts), to the time it goes off (after the
554                fetch completes), afs_GetDCache keeps at least a read lock
555                (actually it keeps an S lock) on the cache entry.
556             
557                This means that if the DFFetching flag is set, we can use that
558                data for any reads that must come from the current version of
559                the file (current == m.DataVersion).
560              
561                Another way of looking at this same point is this: if we're
562                fetching some data and then try do an afs_VerifyVCache, the
563                VerifyVCache operation will not complete until after the
564                DFFetching flag is turned off and the dcache entry's f.versionNo
565                field is updated.
566              
567                Note, by the way, that if DFFetching is set,
568                m.DataVersion > f.versionNo (the latter is not updated until
569                after the fetch completes).
570              */
571             if (tdc) afs_PutDCache(tdc);        /* before reusing tdc */
572             munlocked = 0;
573             tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 2);
574             if (tdc == savedc) {
575                 savedc = 0;
576             }
577             /* now, first try to start transfer, if we'll need the data.  If
578              * data already coming, we don't need to do this, obviously.  Type
579              * 2 requests never return a null dcache entry, btw. */
580             if (!(tdc->flags & DFFetching)
581                 && !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
582                 /* have cache entry, it is not coming in now, and we'll need new data */
583 tagain:
584                 if (trybusy && !afs_BBusy()) {
585                     struct brequest *bp;
586                     /* daemon is not busy */
587                     if (!(tdc->flags & DFFetchReq)) {
588                         tdc->flags |= DFFetchReq;
589 #ifdef  AFS_SUN5_ENVX
590                         mutex_exit(&tdc->lock);
591                         munlocked = 1;
592 #endif
593                         bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
594                                         (long)filePos, (long) tdc, 0L, 0L);
595                         if (!bp) {
596                             /* Bkg table full; retry deadlocks */
597                             tdc->flags &= ~DFFetchReq;
598                             trybusy = 0;        /* Avoid bkg daemon since they're too busy */
599                             goto tagain;
600                         }
601                     }
602                     while (tdc->flags & DFFetchReq) {
603                         /* don't need waiting flag on this one */
604                         ReleaseReadLock(&avc->lock);
605                         afs_osi_Sleep(&tdc->validPos);
606                         ObtainReadLock(&avc->lock);
607                     }
608                 }
609             }
610             /* now data may have started flowing in (if DFFetching is on).  If
611              * data is now streaming in, then wait for some interesting stuff. */
612             while ((tdc->flags & DFFetching) && tdc->validPos <= filePos) {
613                 /* too early: wait for DFFetching flag to vanish, or data to appear */
614                 tdc->flags |= DFWaiting;
615                 ReleaseReadLock(&avc->lock);
616                 afs_osi_Sleep(&tdc->validPos);
617                 ObtainReadLock(&avc->lock);
618             }
619             /* fetching flag gone, data is here, or we never tried (BBusy for instance) */
620             if (tdc->flags & DFFetching) {
621                 /* still fetching, some new data is here: compute length and offset */
622                 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
623                 len = tdc->validPos - filePos;
624             }
625             else {
626                 /* no longer fetching, verify data version (avoid new GetDCache call) */
627                 if (hsame(avc->m.DataVersion, tdc->f.versionNo)) {
628                     offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
629                     len = tdc->f.chunkBytes - offset;
630                 }
631                 else {
632                     /* don't have current data, so get it below */
633                     afs_PutDCache(tdc);
634                     tdc = (struct dcache *) 0;
635                 }
636             }
637
638             if (!tdc) {
639                 ReleaseReadLock(&avc->lock);
640                 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 1);
641                 ObtainReadLock(&avc->lock);
642             }
643         }
644
645         if (!tdc) {
646             error = EIO;
647             break;
648         }
649         if (len > totalLength) len = totalLength;   /* will read len bytes */
650         if (len <= 0) { /* shouldn't get here if DFFetching is on */
651             /* read past the end of a chunk, may not be at next chunk yet, and yet
652                 also not at eof, so may have to supply fake zeros */
653             len = AFS_CHUNKTOSIZE(tdc->f.chunk) - offset; /* bytes left in chunk addr space */
654             if (len > totalLength) len = totalLength;   /* and still within xfr request */
655             code = avc->m.Length - offset; /* and still within file */
656             if (len > code) len = code;
657             if (len > AFS_ZEROS) len = sizeof(afs_zeros);   /* and in 0 buffer */
658             afsio_copy(auio, &tuio, tvec);
659             afsio_trim(&tuio, len);
660             AFS_UIOMOVE(afs_zeros, len, UIO_READ, &tuio, code);
661             if (code) {
662                 error = code;
663                 break;
664             }
665         }
666         else {
667             /* get the data from the file */
668 #ifdef IHINT
669           if (tfile = tdc->ihint) {
670              if (tdc->f.inode != tfile->inum){ 
671                     afs_warn( "afs_UFSRead: %x hint mismatch tdc %d inum %d\n",
672                         tdc, tdc->f.inode, tfile->inum );
673                     osi_UFSClose(tfile);
674                     tdc->ihint = tfile = 0;
675                     nihints--;
676                   }
677            }
678           if (tfile != 0) {
679             usedihint++;
680           }
681           else
682 #endif /* IHINT */
683
684             tfile = (struct osi_file *)osi_UFSOpen(tdc->f.inode);
685             /* mung uio structure to be right for this transfer */
686             afsio_copy(auio, &tuio, tvec);
687             afsio_trim(&tuio, len);
688             tuio.afsio_offset = offset;
689 #ifdef  AFS_AIX_ENV
690 #ifdef  AFS_AIX41_ENV
691           AFS_GUNLOCK();
692           code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, &tuio, NULL, NULL,
693                            NULL, &afs_osi_cred);
694           AFS_GLOCK();
695 #else
696 #ifdef AFS_AIX32_ENV
697             code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, &tuio, NULL, NULL);
698           /* Flush all JFS pages now for big performance gain in big file cases
699            * If we do something like this, must check to be sure that AFS file 
700            * isn't mmapped... see afs_gn_map() for why.
701           */
702 /*
703           if (tfile->vnode->v_gnode && tfile->vnode->v_gnode->gn_seg) {
704  many different ways to do similar things:
705    so far, the best performing one is #2, but #1 might match it if we
706    straighten out the confusion regarding which pages to flush.  It 
707    really does matter.
708    1.       vm_flushp(tfile->vnode->v_gnode->gn_seg, 0, len/PAGESIZE - 1);
709    2.       vm_releasep(tfile->vnode->v_gnode->gn_seg, offset/PAGESIZE, 
710                         (len + PAGESIZE-1)/PAGESIZE);
711    3.       vms_inactive(tfile->vnode->v_gnode->gn_seg) Doesn't work correctly
712    4.       vms_delete(tfile->vnode->v_gnode->gn_seg) probably also fails
713             tfile->vnode->v_gnode->gn_seg = NULL;
714    5.       deletep
715    6.       ipgrlse
716    7.       ifreeseg
717           Unfortunately, this seems to cause frequent "cache corruption" episodes.
718             vm_releasep(tfile->vnode->v_gnode->gn_seg, offset/PAGESIZE, 
719                         (len + PAGESIZE-1)/PAGESIZE);
720           }     
721 */
722 #else
723             code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, (off_t)&offset, &tuio, NULL, NULL, -1);
724 #endif
725 #endif
726 #else
727 #ifdef  AFS_SUN5_ENV
728           AFS_GUNLOCK();
729             VOP_RWLOCK(tfile->vnode, 0);
730             code = VOP_READ(tfile->vnode, &tuio, 0, &afs_osi_cred);
731             VOP_RWUNLOCK(tfile->vnode, 0);
732           AFS_GLOCK();
733 #else
734 #if defined(AFS_SGI_ENV)
735             AFS_GUNLOCK();
736             AFS_VOP_RWLOCK(tfile->vnode, VRWLOCK_READ);
737             AFS_VOP_READ(tfile->vnode, &tuio, IO_ISLOCKED, &afs_osi_cred,
738                          code);
739             AFS_VOP_RWUNLOCK(tfile->vnode, VRWLOCK_READ);
740             AFS_GLOCK();
741 #else
742 #ifdef  AFS_OSF_ENV
743             tuio.uio_rw = UIO_READ;
744             AFS_GUNLOCK();
745             VOP_READ(tfile->vnode, &tuio, 0, &afs_osi_cred, code);
746             AFS_GLOCK();
747 #else   /* AFS_OSF_ENV */
748 #ifdef AFS_SUN_ENV
749             code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, &afs_osi_cred);
750 #else
751 #if     defined(AFS_HPUX100_ENV)
752             AFS_GUNLOCK();
753             code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, &afs_osi_cred);
754             AFS_GLOCK();
755 #else
756 #if defined(AFS_LINUX20_ENV)
757             AFS_GUNLOCK();
758             code = osi_file_uio_rdwr(tfile, &tuio, UIO_READ);
759             AFS_GLOCK();
760 #else
761 #if defined(AFS_DARWIN_ENV)
762             AFS_GUNLOCK();
763             VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, current_proc());
764             code = VOP_READ(tfile->vnode, &tuio, 0, &afs_osi_cred);
765             VOP_UNLOCK(tfile->vnode, 0, current_proc());
766             AFS_GLOCK();
767 #else
768             code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, &afs_osi_cred);
769 #endif
770 #endif
771 #endif
772 #endif
773 #endif
774 #endif
775 #endif
776 #endif
777
778 #ifdef IHINT
779              if (!tdc->ihint && nihints < maxIHint) {
780                tdc->ihint = tfile;
781                nihints++;
782              }
783              else
784 #endif /* IHINT */
785                osi_UFSClose(tfile);
786
787             if (code) {
788                 error = code;
789                 break;
790             }
791         }
792         /* otherwise we've read some, fixup length, etc and continue with next seg */
793         len = len - tuio.afsio_resid; /* compute amount really transferred */
794         afsio_skip(auio, len);      /* update input uio structure */
795         totalLength -= len;
796         transferLength += len;
797         filePos += len;
798         if (len <= 0) break;    /* surprise eof */
799     }
800
801     /* if we make it here with tdc non-zero, then it is the last chunk we
802      * dealt with, and we have to release it when we're done.  We hold on
803      * to it in case we need to do a prefetch, obviously.
804      */
805     if (tdc) {
806 #ifndef AFS_VM_RDWR_ENV
807         /* try to queue prefetch, if needed */
808         if (!(tdc->flags & DFNextStarted) && !noLock) {
809             afs_PrefetchChunk(avc, tdc, acred, &treq);
810         }
811 #endif
812         afs_PutDCache(tdc);
813     }
814     if (!noLock)
815         ReleaseReadLock(&avc->lock);
816
817     osi_FreeSmallSpace(tvec);
818     error = afs_CheckCode(error, &treq, 13);
819     return error;
820 }