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