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