2 * Copyright 2000, International Business Machines Corporation and others.
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
18 #include <afsconfig.h>
19 #include "afs/param.h"
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"
33 extern char afs_zeros[AFS_ZEROS];
36 afs_int32 nihints; /* # of above actually in-use */
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 */
47 /* Forward declarations */
48 void afs_PrefetchChunk(struct vcache *avc, struct dcache *adc,
49 struct AFS_UCRED *acred, struct vrequest *areq);
52 afs_MemRead(register struct vcache *avc, struct uio *auio,
53 struct AFS_UCRED *acred, daddr_t albn, struct buf **abpp,
56 afs_size_t totalLength;
57 afs_size_t transferLength;
59 afs_size_t offset, len, tlen;
61 struct dcache *tdc = 0;
62 afs_int32 error, trybusy = 1;
63 #ifdef AFS_DARWIN80_ENV
67 struct uio *tuiop = &tuio;
73 AFS_STATCNT(afs_MemRead);
77 /* check that we have the latest status info in the vnode cache */
78 if ((code = afs_InitReq(&treq, acred)))
81 code = afs_VerifyVCache(avc, &treq);
83 code = afs_CheckCode(code, &treq, 8); /* failed to get it */
87 #ifndef AFS_VM_RDWR_ENV
88 if (AFS_NFSXLATORREQ(acred)) {
90 (avc, PRSFS_READ, &treq,
91 CHECK_MODE_BITS | CMB_ALLOW_EXEC_AS_READ)) {
92 return afs_CheckCode(EACCES, &treq, 9);
97 #ifndef AFS_DARWIN80_ENV
98 tvec = (struct iovec *)osi_AllocSmallSpace(sizeof(struct iovec));
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));
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);
120 if (filePos >= avc->m.Length) {
122 len = sizeof(afs_zeros); /* and in 0 buffer */
124 #ifdef AFS_DARWIN80_ENV
126 tuiop = afsio_darwin_partialcopy(auio, trimlen);
128 afsio_copy(auio, &tuio, tvec);
130 afsio_trim(&tuio, trimlen);
132 AFS_UIOMOVE(afs_zeros, trimlen, UIO_READ, tuiop, code);
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 */
141 ReleaseReadLock(&tdc->lock);
144 tdc = afs_FindDCache(avc, filePos);
146 ObtainReadLock(&tdc->lock);
147 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
148 len = tdc->f.chunkBytes - offset;
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.
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
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).
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
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).
182 ReleaseReadLock(&tdc->lock);
183 afs_PutDCache(tdc); /* before reusing tdc */
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.
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 */
196 if (trybusy && !afs_BBusy()) {
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,
208 tdc->mflags &= ~DFFetchReq;
209 trybusy = 0; /* Avoid bkg daemon since they're too busy */
210 ReleaseWriteLock(&tdc->mflock);
213 ConvertWToSLock(&tdc->mflock);
214 /* don't use bp pointer! */
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);
232 ReleaseReadLock(&tdc->mflock);
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.
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,
251 ReleaseReadLock(&tdc->lock);
252 ReleaseReadLock(&avc->lock);
253 code = afs_osi_SleepSig(&tdc->validPos);
254 ObtainReadLock(&avc->lock);
255 ObtainReadLock(&tdc->lock);
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;
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);
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);
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.
291 ReleaseReadLock(&avc->lock);
292 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 1);
293 ObtainReadLock(&avc->lock);
295 ObtainReadLock(&tdc->lock);
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));
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 */
325 len = sizeof(afs_zeros); /* and in 0 buffer */
326 #ifdef AFS_DARWIN80_ENV
328 tuiop = afsio_darwin_partialcopy(auio, trimlen);
330 afsio_copy(auio, &tuio, tvec);
332 afsio_trim(&tuio, trimlen);
334 AFS_UIOMOVE(afs_zeros, trimlen, UIO_READ, tuiop, code);
340 /* get the data from the mem cache */
342 /* mung uio structure to be right for this transfer */
343 #ifdef AFS_DARWIN80_ENV
345 tuiop = afsio_darwin_partialcopy(auio, trimlen);
346 uio_setoffset(tuiop, offset);
348 afsio_copy(auio, &tuio, tvec);
350 afsio_trim(&tuio, trimlen);
351 tuio.afsio_offset = offset;
354 code = afs_MemReadUIO(tdc->f.inode, tuiop);
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 */
364 afsio_skip(auio, trimlen); /* update input uio structure */
366 transferLength += len;
370 break; /* surprise eof */
371 #ifdef AFS_DARWIN80_ENV
377 } /* the whole while loop */
382 * tdc->lock(R) if tdc
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.
390 ReleaseReadLock(&tdc->lock);
391 /* try to queue prefetch, if needed */
393 #ifndef AFS_VM_RDWR_ENV
399 afs_PrefetchChunk(avc, tdc, acred, &treq);
404 ReleaseReadLock(&avc->lock);
405 #ifdef AFS_DARWIN80_ENV
409 osi_FreeSmallSpace(tvec);
411 error = afs_CheckCode(error, &treq, 10);
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.
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.
425 afs_PrefetchChunk(struct vcache *avc, struct dcache *adc,
426 struct AFS_UCRED *acred, struct vrequest *areq)
428 register struct dcache *tdc;
430 afs_size_t j1, j2; /* junk vbls for GetDCache to trash */
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)
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);
445 tdc = afs_GetDCache(avc, offset, areq, &j1, &j2, 2); /* type 2 never returns 0 */
446 #ifdef AFS_DISCON_ENV
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
453 #endif /* AFS_DISCON_ENV */
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.
463 bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
464 (afs_size_t) offset, (afs_size_t) 1, tdc);
466 /* Bkg table full; just abort non-important prefetching to avoid deadlocks */
467 tdc->mflags &= ~DFFetchReq;
468 ReleaseWriteLock(&tdc->mflock);
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.
478 ObtainReadLock(&adc->lock);
479 ObtainWriteLock(&adc->mflock, 664);
480 adc->mflags &= ~DFNextStarted;
481 ReleaseWriteLock(&adc->mflock);
482 ReleaseReadLock(&adc->lock);
484 ReleaseWriteLock(&tdc->mflock);
487 ReleaseSharedLock(&tdc->mflock);
491 ReleaseSharedLock(&adc->mflock);
492 ReleaseReadLock(&adc->lock);
497 afs_UFSRead(register struct vcache *avc, struct uio *auio,
498 struct AFS_UCRED *acred, daddr_t albn, struct buf **abpp,
501 afs_size_t totalLength;
502 afs_size_t transferLength;
504 afs_size_t offset, len, tlen;
506 struct dcache *tdc = 0;
508 #ifdef AFS_DARWIN80_ENV
512 struct uio *tuiop = &tuio;
515 struct osi_file *tfile;
518 struct vrequest treq;
520 AFS_STATCNT(afs_UFSRead);
521 if (avc && avc->vc_error)
526 /* check that we have the latest status info in the vnode cache */
527 if ((code = afs_InitReq(&treq, acred)))
531 osi_Panic("null avc in afs_UFSRead");
533 code = afs_VerifyVCache(avc, &treq);
535 code = afs_CheckCode(code, &treq, 11); /* failed to get it */
541 #ifndef AFS_VM_RDWR_ENV
542 if (AFS_NFSXLATORREQ(acred)) {
544 (avc, PRSFS_READ, &treq,
545 CHECK_MODE_BITS | CMB_ALLOW_EXEC_AS_READ)) {
547 return afs_CheckCode(EACCES, &treq, 12);
552 #ifndef AFS_DARWIN80_ENV
553 tvec = (struct iovec *)osi_AllocSmallSpace(sizeof(struct iovec));
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));
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);
571 if (filePos >= avc->m.Length) {
573 len = sizeof(afs_zeros); /* and in 0 buffer */
575 #ifdef AFS_DARWIN80_ENV
577 tuiop = afsio_darwin_partialcopy(auio, trimlen);
579 afsio_copy(auio, &tuio, tvec);
581 afsio_trim(&tuio, trimlen);
583 AFS_UIOMOVE(afs_zeros, trimlen, UIO_READ, tuiop, code);
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 */
592 ReleaseReadLock(&tdc->lock);
595 tdc = afs_FindDCache(avc, filePos);
597 ObtainReadLock(&tdc->lock);
598 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
599 len = tdc->validPos - filePos;
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.
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
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).
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
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).
633 ReleaseReadLock(&tdc->lock);
634 afs_PutDCache(tdc); /* before reusing tdc */
636 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 2);
637 #ifdef AFS_DISCON_ENV
639 /*printf("Network down in afs_read");*/
643 #endif /* AFS_DISCON_ENV */
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 */
653 if (trybusy && !afs_BBusy()) {
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,
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);
670 ConvertWToSLock(&tdc->mflock);
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);
688 ReleaseReadLock(&tdc->mflock);
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.
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,
707 ReleaseReadLock(&tdc->lock);
708 ReleaseReadLock(&avc->lock);
709 code = afs_osi_SleepSig(&tdc->validPos);
710 ObtainReadLock(&avc->lock);
711 ObtainReadLock(&tdc->lock);
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;
725 /* no longer fetching, verify data version (avoid new
727 if (hsame(avc->m.DataVersion, tdc->f.versionNo)
728 && ((len = tdc->validPos - filePos) > 0)) {
729 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
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);
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.
747 ReleaseReadLock(&avc->lock);
748 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 1);
749 ObtainReadLock(&avc->lock);
751 ObtainReadLock(&tdc->lock);
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,
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 */
779 len = sizeof(afs_zeros); /* and in 0 buffer */
780 #ifdef AFS_DARWIN80_ENV
782 tuiop = afsio_darwin_partialcopy(auio, trimlen);
784 afsio_copy(auio, &tuio, tvec);
786 afsio_trim(&tuio, trimlen);
788 AFS_UIOMOVE(afs_zeros, trimlen, UIO_READ, tuiop, code);
794 /* get the data from the file */
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);
801 tdc->ihint = tfile = 0;
810 tfile = (struct osi_file *)osi_UFSOpen(tdc->f.inode);
811 #ifdef AFS_DARWIN80_ENV
813 tuiop = afsio_darwin_partialcopy(auio, trimlen);
814 uio_setoffset(tuiop, offset);
816 /* mung uio structure to be right for this transfer */
817 afsio_copy(auio, &tuio, tvec);
819 afsio_trim(&tuio, trimlen);
820 tuio.afsio_offset = offset;
823 #if defined(AFS_AIX41_ENV)
826 VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, &tuio, NULL, NULL,
827 NULL, afs_osi_credp);
829 #elif defined(AFS_AIX32_ENV)
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.
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
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;
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);
856 #elif defined(AFS_AIX_ENV)
858 VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, (off_t) & offset,
859 &tuio, NULL, NULL, -1);
860 #elif defined(AFS_SUN5_ENV)
862 #ifdef AFS_SUN510_ENV
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);
871 VOP_RWLOCK(tfile->vnode, 0);
872 code = VOP_READ(tfile->vnode, &tuio, 0, afs_osi_credp);
873 VOP_RWUNLOCK(tfile->vnode, 0);
876 #elif defined(AFS_SGI_ENV)
878 AFS_VOP_RWLOCK(tfile->vnode, VRWLOCK_READ);
879 AFS_VOP_READ(tfile->vnode, &tuio, IO_ISLOCKED, afs_osi_credp,
881 AFS_VOP_RWUNLOCK(tfile->vnode, VRWLOCK_READ);
883 #elif defined(AFS_OSF_ENV)
884 tuio.uio_rw = UIO_READ;
886 VOP_READ(tfile->vnode, &tuio, 0, afs_osi_credp, code);
888 #elif defined(AFS_HPUX100_ENV)
890 code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, afs_osi_credp);
892 #elif defined(AFS_LINUX20_ENV)
894 code = osi_rdwr(tfile, &tuio, UIO_READ);
896 #elif defined(AFS_DARWIN80_ENV)
898 code = VNOP_READ(tfile->vnode, tuiop, 0, afs_osi_ctxtp);
900 #elif defined(AFS_DARWIN_ENV)
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());
906 #elif defined(AFS_FBSD80_ENV)
908 VOP_LOCK(tfile->vnode, LK_EXCLUSIVE);
909 code = VOP_READ(tfile->vnode, &tuio, 0, afs_osi_credp);
910 VOP_UNLOCK(tfile->vnode, 0);
912 #elif defined(AFS_FBSD50_ENV)
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);
918 #elif defined(AFS_XBSD_ENV)
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);
925 code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, afs_osi_credp);
929 if (!tdc->ihint && nihints < maxIHint) {
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 */
944 afsio_skip(auio, trimlen); /* update input uio structure */
946 transferLength += len;
949 break; /* surprise eof */
950 #ifdef AFS_DARWIN80_ENV
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.
963 ReleaseReadLock(&tdc->lock);
964 #if !defined(AFS_VM_RDWR_ENV)
965 /* try to queue prefetch, if needed */
967 if (!(tdc->mflags & DFNextStarted))
968 afs_PrefetchChunk(avc, tdc, acred, &treq);
974 ReleaseReadLock(&avc->lock);
976 #ifdef AFS_DARWIN80_ENV
980 osi_FreeSmallSpace(tvec);
983 error = afs_CheckCode(error, &treq, 13);