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