Initial IBM OpenAFS 1.0 tree
[openafs.git] / src / afs / VNOPS / afs_vnop_read.c
1 /* Copyright (C) 1995, 1989, 1998 Transarc Corporation - All rights reserved */
2 /*
3  * For copyright information, see IPL which you accepted in order to
4  * download this software.
5  *
6  */
7
8 /*
9  * afs_vnop_read.c
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             code = VOP_RDWR(tfile->vnode, auio, UIO_READ, 0, &afs_osi_cred);
424 #endif
425 #endif
426 #endif
427 #endif
428 #endif
429 #endif
430             auio->afsio_offset += avc->quick.minLoc;
431             osi_UFSClose(tfile);
432             /* Fix up LRU info */
433             hset(afs_indexTimes[tdc->index], afs_indexCounter);
434             hadd32(afs_indexCounter, 1);
435
436             if (!noLock) {
437 #ifndef AFS_VM_RDWR_ENV
438                 if (!(code = afs_InitReq(&treq, acred))&& (!(tdc->flags & DFNextStarted)))
439                     afs_PrefetchChunk(avc, tdc, acred, &treq);
440 #endif
441                 ReleaseReadLock(&avc->lock);
442             }
443             tdc->refCount--;
444             return (code);
445         }
446         if (!tdc->f.chunkBytes) {   /* debugging f.chunkBytes == 0 problem */
447             savedc = tdc;
448         }
449         tdc->refCount--;
450     } else {
451         ReleaseReadLock(&afs_xdcache);
452     }
453
454     /* come here if fast path doesn't work for some reason or other */
455     if (!noLock)
456         ReleaseReadLock(&avc->lock);
457     return afs_UFSRead(avc, auio, acred, albn, abpp, noLock);
458 }
459
460 afs_UFSRead(avc, auio, acred, albn, abpp, noLock)
461     struct vcache *avc;
462     struct uio *auio;
463     struct AFS_UCRED *acred;
464     daddr_t albn;
465     int noLock;
466     struct buf **abpp; {
467     afs_int32 totalLength;
468     afs_int32 transferLength;
469     afs_int32 filePos;
470     struct dcache *tdc=0;
471     afs_int32 offset, len, error;
472     struct uio tuio;
473     struct iovec *tvec;
474     struct osi_file *tfile;
475     afs_int32 code;
476     int munlocked, trybusy=1;
477     struct vnode *vp;
478     struct vrequest treq;
479
480     AFS_STATCNT(afs_UFSRead);
481     if (avc->vc_error)
482         return EIO;
483
484     /* check that we have the latest status info in the vnode cache */
485     if (code = afs_InitReq(&treq, acred)) return code;
486     if (!noLock) {
487       if (!avc) 
488         osi_Panic ("null avc in afs_UFSRead");
489       else {
490         code = afs_VerifyVCache(avc, &treq);
491         if (code) {
492           code = afs_CheckCode(code, &treq, 11); /* failed to get it */
493           return code;
494         }
495       }
496     }
497
498 #ifndef AFS_VM_RDWR_ENV
499     if (AFS_NFSXLATORREQ(acred)) {
500         if (!afs_AccessOK(avc, PRSFS_READ, &treq,
501                           CHECK_MODE_BITS|CMB_ALLOW_EXEC_AS_READ)) {
502             return afs_CheckCode(EACCES, &treq, 12);
503         }
504     }
505 #endif
506
507     tvec = (struct iovec *) osi_AllocSmallSpace(sizeof(struct iovec));
508     totalLength = auio->afsio_resid;
509     filePos = auio->afsio_offset;
510     afs_Trace4(afs_iclSetp, CM_TRACE_READ, ICL_TYPE_POINTER, avc, 
511                ICL_TYPE_INT32, filePos, ICL_TYPE_INT32, totalLength,
512                ICL_TYPE_INT32, avc->m.Length);
513     error = 0;
514     transferLength = 0;
515     if (!noLock)
516         ObtainReadLock(&avc->lock);
517 #if     defined(AFS_TEXT_ENV) && !defined(AFS_VM_RDWR_ENV)
518     if (avc->flushDV.high == AFS_MAXDV && avc->flushDV.low == AFS_MAXDV) {
519         hset(avc->flushDV, avc->m.DataVersion);
520     }
521 #endif
522     
523     while (totalLength > 0) {
524         /* read all of the cached info */
525         if (filePos >= avc->m.Length) break;    /* all done */
526         if (noLock) {
527             if (tdc) afs_PutDCache(tdc);
528             tdc = afs_FindDCache(avc, filePos);
529             if (tdc) {
530                 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
531                 len = tdc->f.chunkBytes - offset;
532             }
533         } else {
534             /* a tricky question: does the presence of the DFFetching flag
535                mean that we're fetching the latest version of the file?  No.
536                The server could update the file as soon as the fetch responsible
537                for the setting of the DFFetching flag completes.
538             
539                However, the presence of the DFFetching flag (visible under a
540                read lock since it is set and cleared only under a write lock)
541                means that we're fetching as good a version as was known to this
542                client at the time of the last call to afs_VerifyVCache, since
543                the latter updates the stat cache's m.DataVersion field under a
544                write lock, and from the time that the DFFetching flag goes on
545                (before the fetch starts), to the time it goes off (after the
546                fetch completes), afs_GetDCache keeps at least a read lock
547                (actually it keeps an S lock) on the cache entry.
548             
549                This means that if the DFFetching flag is set, we can use that
550                data for any reads that must come from the current version of
551                the file (current == m.DataVersion).
552              
553                Another way of looking at this same point is this: if we're
554                fetching some data and then try do an afs_VerifyVCache, the
555                VerifyVCache operation will not complete until after the
556                DFFetching flag is turned off and the dcache entry's f.versionNo
557                field is updated.
558              
559                Note, by the way, that if DFFetching is set,
560                m.DataVersion > f.versionNo (the latter is not updated until
561                after the fetch completes).
562              */
563             if (tdc) afs_PutDCache(tdc);        /* before reusing tdc */
564             munlocked = 0;
565             tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 2);
566             if (tdc == savedc) {
567                 savedc = 0;
568             }
569             /* now, first try to start transfer, if we'll need the data.  If
570              * data already coming, we don't need to do this, obviously.  Type
571              * 2 requests never return a null dcache entry, btw. */
572             if (!(tdc->flags & DFFetching)
573                 && !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
574                 /* have cache entry, it is not coming in now, and we'll need new data */
575 tagain:
576                 if (trybusy && !afs_BBusy()) {
577                     struct brequest *bp;
578                     /* daemon is not busy */
579                     if (!(tdc->flags & DFFetchReq)) {
580                         tdc->flags |= DFFetchReq;
581 #ifdef  AFS_SUN5_ENVX
582                         mutex_exit(&tdc->lock);
583                         munlocked = 1;
584 #endif
585                         bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
586                                         (long)filePos, (long) tdc, 0L, 0L);
587                         if (!bp) {
588                             /* Bkg table full; retry deadlocks */
589                             tdc->flags &= ~DFFetchReq;
590                             trybusy = 0;        /* Avoid bkg daemon since they're too busy */
591                             goto tagain;
592                         }
593                     }
594                     while (tdc->flags & DFFetchReq) {
595                         /* don't need waiting flag on this one */
596                         ReleaseReadLock(&avc->lock);
597                         afs_osi_Sleep(&tdc->validPos);
598                         ObtainReadLock(&avc->lock);
599                     }
600                 }
601             }
602             /* now data may have started flowing in (if DFFetching is on).  If
603              * data is now streaming in, then wait for some interesting stuff. */
604             while ((tdc->flags & DFFetching) && tdc->validPos <= filePos) {
605                 /* too early: wait for DFFetching flag to vanish, or data to appear */
606                 tdc->flags |= DFWaiting;
607                 ReleaseReadLock(&avc->lock);
608                 afs_osi_Sleep(&tdc->validPos);
609                 ObtainReadLock(&avc->lock);
610             }
611             /* fetching flag gone, data is here, or we never tried (BBusy for instance) */
612             if (tdc->flags & DFFetching) {
613                 /* still fetching, some new data is here: compute length and offset */
614                 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
615                 len = tdc->validPos - filePos;
616             }
617             else {
618                 /* no longer fetching, verify data version (avoid new GetDCache call) */
619                 if (hsame(avc->m.DataVersion, tdc->f.versionNo)) {
620                     offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
621                     len = tdc->f.chunkBytes - offset;
622                 }
623                 else {
624                     /* don't have current data, so get it below */
625                     afs_PutDCache(tdc);
626                     tdc = (struct dcache *) 0;
627                 }
628             }
629
630             if (!tdc) {
631                 ReleaseReadLock(&avc->lock);
632                 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 1);
633                 ObtainReadLock(&avc->lock);
634             }
635         }
636
637         if (!tdc) {
638             error = EIO;
639             break;
640         }
641         if (len > totalLength) len = totalLength;   /* will read len bytes */
642         if (len <= 0) { /* shouldn't get here if DFFetching is on */
643             /* read past the end of a chunk, may not be at next chunk yet, and yet
644                 also not at eof, so may have to supply fake zeros */
645             len = AFS_CHUNKTOSIZE(tdc->f.chunk) - offset; /* bytes left in chunk addr space */
646             if (len > totalLength) len = totalLength;   /* and still within xfr request */
647             code = avc->m.Length - offset; /* and still within file */
648             if (len > code) len = code;
649             if (len > AFS_ZEROS) len = sizeof(afs_zeros);   /* and in 0 buffer */
650             afsio_copy(auio, &tuio, tvec);
651             afsio_trim(&tuio, len);
652             AFS_UIOMOVE(afs_zeros, len, UIO_READ, &tuio, code);
653             if (code) {
654                 error = code;
655                 break;
656             }
657         }
658         else {
659             /* get the data from the file */
660 #ifdef IHINT
661           if (tfile = tdc->ihint) {
662              if (tdc->f.inode != tfile->inum){ 
663                     afs_warn( "afs_UFSRead: %x hint mismatch tdc %d inum %d\n",
664                         tdc, tdc->f.inode, tfile->inum );
665                     osi_UFSClose(tfile);
666                     tdc->ihint = tfile = 0;
667                     nihints--;
668                   }
669            }
670           if (tfile != 0) {
671             usedihint++;
672           }
673           else
674 #endif /* IHINT */
675
676             tfile = (struct osi_file *)osi_UFSOpen(tdc->f.inode);
677             /* mung uio structure to be right for this transfer */
678             afsio_copy(auio, &tuio, tvec);
679             afsio_trim(&tuio, len);
680             tuio.afsio_offset = offset;
681 #ifdef  AFS_AIX_ENV
682 #ifdef  AFS_AIX41_ENV
683           AFS_GUNLOCK();
684           code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, &tuio, NULL, NULL,
685                            NULL, &afs_osi_cred);
686           AFS_GLOCK();
687 #else
688 #ifdef AFS_AIX32_ENV
689             code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, &tuio, NULL, NULL);
690           /* Flush all JFS pages now for big performance gain in big file cases
691            * If we do something like this, must check to be sure that AFS file 
692            * isn't mmapped... see afs_gn_map() for why.
693           */
694 /*
695           if (tfile->vnode->v_gnode && tfile->vnode->v_gnode->gn_seg) {
696  many different ways to do similar things:
697    so far, the best performing one is #2, but #1 might match it if we
698    straighten out the confusion regarding which pages to flush.  It 
699    really does matter.
700    1.       vm_flushp(tfile->vnode->v_gnode->gn_seg, 0, len/PAGESIZE - 1);
701    2.       vm_releasep(tfile->vnode->v_gnode->gn_seg, offset/PAGESIZE, 
702                         (len + PAGESIZE-1)/PAGESIZE);
703    3.       vms_inactive(tfile->vnode->v_gnode->gn_seg) Doesn't work correctly
704    4.       vms_delete(tfile->vnode->v_gnode->gn_seg) probably also fails
705             tfile->vnode->v_gnode->gn_seg = NULL;
706    5.       deletep
707    6.       ipgrlse
708    7.       ifreeseg
709           Unfortunately, this seems to cause frequent "cache corruption" episodes.
710             vm_releasep(tfile->vnode->v_gnode->gn_seg, offset/PAGESIZE, 
711                         (len + PAGESIZE-1)/PAGESIZE);
712           }     
713 */
714 #else
715             code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, (off_t)&offset, &tuio, NULL, NULL, -1);
716 #endif
717 #endif
718 #else
719 #ifdef  AFS_SUN5_ENV
720           AFS_GUNLOCK();
721             VOP_RWLOCK(tfile->vnode, 0);
722             code = VOP_READ(tfile->vnode, &tuio, 0, &afs_osi_cred);
723             VOP_RWUNLOCK(tfile->vnode, 0);
724           AFS_GLOCK();
725 #else
726 #if defined(AFS_SGI_ENV)
727             AFS_GUNLOCK();
728             AFS_VOP_RWLOCK(tfile->vnode, VRWLOCK_READ);
729             AFS_VOP_READ(tfile->vnode, &tuio, IO_ISLOCKED, &afs_osi_cred,
730                          code);
731             AFS_VOP_RWUNLOCK(tfile->vnode, VRWLOCK_READ);
732             AFS_GLOCK();
733 #else
734 #ifdef  AFS_OSF_ENV
735             tuio.uio_rw = UIO_READ;
736             AFS_GUNLOCK();
737             VOP_READ(tfile->vnode, &tuio, 0, &afs_osi_cred, code);
738             AFS_GLOCK();
739 #else   /* AFS_OSF_ENV */
740 #ifdef AFS_SUN_ENV
741             code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, &afs_osi_cred);
742 #else
743 #if     defined(AFS_HPUX100_ENV)
744             AFS_GUNLOCK();
745             code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, &afs_osi_cred);
746             AFS_GLOCK();
747 #else
748 #if defined(AFS_LINUX20_ENV)
749             AFS_GUNLOCK();
750             code = osi_file_uio_rdwr(tfile, &tuio, UIO_READ);
751             AFS_GLOCK();
752 #else
753             code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, &afs_osi_cred);
754 #endif
755 #endif
756 #endif
757 #endif
758 #endif
759 #endif
760 #endif
761
762 #ifdef IHINT
763              if (!tdc->ihint && nihints < maxIHint) {
764                tdc->ihint = tfile;
765                nihints++;
766              }
767              else
768 #endif /* IHINT */
769                osi_UFSClose(tfile);
770
771             if (code) {
772                 error = code;
773                 break;
774             }
775         }
776         /* otherwise we've read some, fixup length, etc and continue with next seg */
777         len = len - tuio.afsio_resid; /* compute amount really transferred */
778         afsio_skip(auio, len);      /* update input uio structure */
779         totalLength -= len;
780         transferLength += len;
781         filePos += len;
782         if (len <= 0) break;    /* surprise eof */
783     }
784
785     /* if we make it here with tdc non-zero, then it is the last chunk we
786      * dealt with, and we have to release it when we're done.  We hold on
787      * to it in case we need to do a prefetch, obviously.
788      */
789     if (tdc) {
790 #ifndef AFS_VM_RDWR_ENV
791         /* try to queue prefetch, if needed */
792         if (!(tdc->flags & DFNextStarted) && !noLock) {
793             afs_PrefetchChunk(avc, tdc, acred, &treq);
794         }
795 #endif
796         afs_PutDCache(tdc);
797     }
798     if (!noLock)
799         ReleaseReadLock(&avc->lock);
800
801     osi_FreeSmallSpace(tvec);
802     error = afs_CheckCode(error, &treq, 13);
803     return error;
804 }