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"
22 #include "afs/sysincludes.h" /* Standard vendor system headers */
23 #include "afsincludes.h" /* Afs-based standard headers */
24 #include "afs/afs_stats.h" /* statistics */
25 #include "afs/afs_cbqueue.h"
26 #include "afs/nfsclient.h"
27 #include "afs/afs_osidnlc.h"
28 #include "afs/afs_osi.h"
31 extern char afs_zeros[AFS_ZEROS];
34 afs_int32 nihints; /* # of above actually in-use */
38 /* Imported variables */
39 extern afs_rwlock_t afs_xdcache;
40 extern unsigned char *afs_indexFlags;
41 extern afs_hyper_t *afs_indexTimes; /* Dcache entry Access times */
42 extern afs_hyper_t afs_indexCounter; /* Fake time for marking index */
45 /* Forward declarations */
46 void afs_PrefetchChunk(struct vcache *avc, struct dcache *adc,
47 AFS_UCRED *acred, struct vrequest *areq);
50 afs_MemRead(register struct vcache *avc, struct uio *auio,
51 AFS_UCRED *acred, daddr_t albn, struct buf **abpp,
54 afs_size_t totalLength;
55 afs_size_t transferLength;
57 afs_size_t offset, len, tlen;
59 struct dcache *tdc = 0;
60 afs_int32 error, trybusy = 1;
61 #ifdef AFS_DARWIN80_ENV
65 struct uio *tuiop = &tuio;
71 AFS_STATCNT(afs_MemRead);
75 /* check that we have the latest status info in the vnode cache */
76 if ((code = afs_InitReq(&treq, acred)))
79 code = afs_VerifyVCache(avc, &treq);
81 code = afs_CheckCode(code, &treq, 8); /* failed to get it */
85 #ifndef AFS_VM_RDWR_ENV
86 if (AFS_NFSXLATORREQ(acred)) {
88 (avc, PRSFS_READ, &treq,
89 CHECK_MODE_BITS | CMB_ALLOW_EXEC_AS_READ)) {
90 return afs_CheckCode(EACCES, &treq, 9);
95 #ifndef AFS_DARWIN80_ENV
96 tvec = (struct iovec *)osi_AllocSmallSpace(sizeof(struct iovec));
98 totalLength = AFS_UIO_RESID(auio);
99 filePos = AFS_UIO_OFFSET(auio);
100 afs_Trace4(afs_iclSetp, CM_TRACE_READ, ICL_TYPE_POINTER, avc,
101 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(filePos), ICL_TYPE_INT32,
102 totalLength, ICL_TYPE_OFFSET,
103 ICL_HANDLE_OFFSET(avc->f.m.Length));
107 ObtainReadLock(&avc->lock);
108 #if defined(AFS_TEXT_ENV) && !defined(AFS_VM_RDWR_ENV)
109 if (avc->flushDV.high == AFS_MAXDV && avc->flushDV.low == AFS_MAXDV) {
110 hset(avc->flushDV, avc->f.m.DataVersion);
118 if (filePos >= avc->f.m.Length) {
120 len = sizeof(afs_zeros); /* and in 0 buffer */
122 #ifdef AFS_DARWIN80_ENV
124 tuiop = afsio_darwin_partialcopy(auio, trimlen);
126 afsio_copy(auio, &tuio, tvec);
128 afsio_trim(&tuio, trimlen);
130 AFS_UIOMOVE(afs_zeros, trimlen, UIO_READ, tuiop, code);
133 while (avc->f.m.Length > 0 && totalLength > 0) {
134 /* read all of the cached info */
135 if (filePos >= avc->f.m.Length)
136 break; /* all done */
139 ReleaseReadLock(&tdc->lock);
142 tdc = afs_FindDCache(avc, filePos);
144 ObtainReadLock(&tdc->lock);
145 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
146 len = tdc->f.chunkBytes - offset;
149 /* a tricky question: does the presence of the DFFetching flag
150 * mean that we're fetching the latest version of the file? No.
151 * The server could update the file as soon as the fetch responsible
152 * for the setting of the DFFetching flag completes.
154 * However, the presence of the DFFetching flag (visible under
155 * a dcache read lock since it is set and cleared only under a
156 * dcache write lock) means that we're fetching as good a version
157 * as was known to this client at the time of the last call to
158 * afs_VerifyVCache, since the latter updates the stat cache's
159 * m.DataVersion field under a vcache write lock, and from the
160 * time that the DFFetching flag goes on in afs_GetDCache (before
161 * the fetch starts), to the time it goes off (after the fetch
162 * completes), afs_GetDCache keeps at least a read lock on the
165 * This means that if the DFFetching flag is set, we can use that
166 * data for any reads that must come from the current version of
167 * the file (current == m.DataVersion).
169 * Another way of looking at this same point is this: if we're
170 * fetching some data and then try do an afs_VerifyVCache, the
171 * VerifyVCache operation will not complete until after the
172 * DFFetching flag is turned off and the dcache entry's f.versionNo
175 * Note, by the way, that if DFFetching is set,
176 * m.DataVersion > f.versionNo (the latter is not updated until
177 * after the fetch completes).
180 ReleaseReadLock(&tdc->lock);
181 afs_PutDCache(tdc); /* before reusing tdc */
183 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 2);
184 ObtainReadLock(&tdc->lock);
185 /* now, first try to start transfer, if we'll need the data. If
186 * data already coming, we don't need to do this, obviously. Type
187 * 2 requests never return a null dcache entry, btw.
189 if (!(tdc->dflags & DFFetching)
190 && !hsame(avc->f.m.DataVersion, tdc->f.versionNo)) {
191 /* have cache entry, it is not coming in now,
192 * and we'll need new data */
194 if (trybusy && !afs_BBusy()) {
196 /* daemon is not busy */
197 ObtainSharedLock(&tdc->mflock, 665);
198 if (!(tdc->mflags & DFFetchReq)) {
199 /* start the daemon (may already be running, however) */
200 UpgradeSToWLock(&tdc->mflock, 666);
201 tdc->mflags |= DFFetchReq;
202 bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
203 (afs_size_t) filePos, (afs_size_t) 0,
206 tdc->mflags &= ~DFFetchReq;
207 trybusy = 0; /* Avoid bkg daemon since they're too busy */
208 ReleaseWriteLock(&tdc->mflock);
211 ConvertWToSLock(&tdc->mflock);
212 /* don't use bp pointer! */
215 ConvertSToRLock(&tdc->mflock);
216 while (!code && tdc->mflags & DFFetchReq) {
217 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT,
218 ICL_TYPE_STRING, __FILE__, ICL_TYPE_INT32,
219 __LINE__, ICL_TYPE_POINTER, tdc,
220 ICL_TYPE_INT32, tdc->dflags);
221 /* don't need waiting flag on this one */
222 ReleaseReadLock(&tdc->mflock);
223 ReleaseReadLock(&tdc->lock);
224 ReleaseReadLock(&avc->lock);
225 code = afs_osi_SleepSig(&tdc->validPos);
226 ObtainReadLock(&avc->lock);
227 ObtainReadLock(&tdc->lock);
228 ObtainReadLock(&tdc->mflock);
230 ReleaseReadLock(&tdc->mflock);
237 /* now data may have started flowing in (if DFFetching is on). If
238 * data is now streaming in, then wait for some interesting stuff.
241 while (!code && (tdc->dflags & DFFetching)
242 && tdc->validPos <= filePos) {
243 /* too early: wait for DFFetching flag to vanish,
244 * or data to appear */
245 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
246 __FILE__, ICL_TYPE_INT32, __LINE__,
247 ICL_TYPE_POINTER, tdc, ICL_TYPE_INT32,
249 ReleaseReadLock(&tdc->lock);
250 ReleaseReadLock(&avc->lock);
251 code = afs_osi_SleepSig(&tdc->validPos);
252 ObtainReadLock(&avc->lock);
253 ObtainReadLock(&tdc->lock);
259 /* fetching flag gone, data is here, or we never tried
260 * (BBusy for instance) */
261 if (tdc->dflags & DFFetching) {
262 /* still fetching, some new data is here:
263 * compute length and offset */
264 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
265 len = tdc->validPos - filePos;
267 /* no longer fetching, verify data version
268 * (avoid new GetDCache call) */
269 if (hsame(avc->f.m.DataVersion, tdc->f.versionNo)
270 && ((len = tdc->validPos - filePos) > 0)) {
271 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
273 /* don't have current data, so get it below */
274 afs_Trace3(afs_iclSetp, CM_TRACE_VERSIONNO,
275 ICL_TYPE_INT64, ICL_HANDLE_OFFSET(filePos),
276 ICL_TYPE_HYPER, &avc->f.m.DataVersion,
277 ICL_TYPE_HYPER, &tdc->f.versionNo);
278 ReleaseReadLock(&tdc->lock);
285 /* If we get, it was not possible to start the
286 * background daemon. With flag == 1 afs_GetDCache
287 * does the FetchData rpc synchronously.
289 ReleaseReadLock(&avc->lock);
290 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 1);
291 ObtainReadLock(&avc->lock);
293 ObtainReadLock(&tdc->lock);
297 afs_Trace3(afs_iclSetp, CM_TRACE_VNODEREAD, ICL_TYPE_POINTER, tdc,
298 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(offset),
299 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(len));
311 if (len > totalLength)
312 len = totalLength; /* will read len bytes */
313 if (len <= 0) { /* shouldn't get here if DFFetching is on */
314 /* read past the end of a chunk, may not be at next chunk yet, and yet
315 * also not at eof, so may have to supply fake zeros */
316 len = AFS_CHUNKTOSIZE(tdc->f.chunk) - offset; /* bytes left in chunk addr space */
317 if (len > totalLength)
318 len = totalLength; /* and still within xfr request */
319 tlen = avc->f.m.Length - offset; /* and still within file */
323 len = sizeof(afs_zeros); /* and in 0 buffer */
324 #ifdef AFS_DARWIN80_ENV
326 tuiop = afsio_darwin_partialcopy(auio, trimlen);
328 afsio_copy(auio, &tuio, tvec);
330 afsio_trim(&tuio, trimlen);
332 AFS_UIOMOVE(afs_zeros, trimlen, UIO_READ, tuiop, code);
338 /* get the data from the mem cache */
340 /* mung uio structure to be right for this transfer */
341 #ifdef AFS_DARWIN80_ENV
343 tuiop = afsio_darwin_partialcopy(auio, trimlen);
344 uio_setoffset(tuiop, offset);
346 afsio_copy(auio, &tuio, tvec);
348 afsio_trim(&tuio, trimlen);
349 tuio.afsio_offset = offset;
352 code = afs_MemReadUIO(&tdc->f.inode, tuiop);
359 /* otherwise we've read some, fixup length, etc and continue with next seg */
360 len = len - AFS_UIO_RESID(tuiop); /* compute amount really transferred */
362 afsio_skip(auio, trimlen); /* update input uio structure */
364 transferLength += len;
368 break; /* surprise eof */
369 #ifdef AFS_DARWIN80_ENV
375 } /* the whole while loop */
380 * tdc->lock(R) if tdc
383 /* if we make it here with tdc non-zero, then it is the last chunk we
384 * dealt with, and we have to release it when we're done. We hold on
385 * to it in case we need to do a prefetch.
388 ReleaseReadLock(&tdc->lock);
389 /* try to queue prefetch, if needed */
391 #ifndef AFS_VM_RDWR_ENV
397 afs_PrefetchChunk(avc, tdc, acred, &treq);
402 ReleaseReadLock(&avc->lock);
403 #ifdef AFS_DARWIN80_ENV
407 osi_FreeSmallSpace(tvec);
409 error = afs_CheckCode(error, &treq, 10);
413 /* called with the dcache entry triggering the fetch, the vcache entry involved,
414 * and a vrequest for the read call. Marks the dcache entry as having already
415 * triggered a prefetch, starts the prefetch going and sets the DFFetchReq
416 * flag in the prefetched block, so that the next call to read knows to wait
417 * for the daemon to start doing things.
419 * This function must be called with the vnode at least read-locked, and
420 * no locks on the dcache, because it plays around with dcache entries.
423 afs_PrefetchChunk(struct vcache *avc, struct dcache *adc,
424 AFS_UCRED *acred, struct vrequest *areq)
426 register struct dcache *tdc;
428 afs_size_t j1, j2; /* junk vbls for GetDCache to trash */
430 offset = adc->f.chunk + 1; /* next chunk we'll need */
431 offset = AFS_CHUNKTOBASE(offset); /* base of next chunk */
432 ObtainReadLock(&adc->lock);
433 ObtainSharedLock(&adc->mflock, 662);
434 if (offset < avc->f.m.Length && !(adc->mflags & DFNextStarted)
438 UpgradeSToWLock(&adc->mflock, 663);
439 adc->mflags |= DFNextStarted; /* we've tried to prefetch for this guy */
440 ReleaseWriteLock(&adc->mflock);
441 ReleaseReadLock(&adc->lock);
443 tdc = afs_GetDCache(avc, offset, areq, &j1, &j2, 2); /* type 2 never returns 0 */
444 #ifdef AFS_DISCON_ENV
446 * In disconnected mode, type 2 can return 0 because it doesn't
447 * make any sense to allocate a dcache we can never fill
451 #endif /* AFS_DISCON_ENV */
453 ObtainSharedLock(&tdc->mflock, 651);
454 if (!(tdc->mflags & DFFetchReq)) {
455 /* ask the daemon to do the work */
456 UpgradeSToWLock(&tdc->mflock, 652);
457 tdc->mflags |= DFFetchReq; /* guaranteed to be cleared by BKG or GetDCache */
458 /* last parm (1) tells bkg daemon to do an afs_PutDCache when it is done,
459 * since we don't want to wait for it to finish before doing so ourselves.
461 bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
462 (afs_size_t) offset, (afs_size_t) 1, tdc);
464 /* Bkg table full; just abort non-important prefetching to avoid deadlocks */
465 tdc->mflags &= ~DFFetchReq;
466 ReleaseWriteLock(&tdc->mflock);
470 * DCLOCKXXX: This is a little sketchy, since someone else
471 * could have already started a prefetch.. In practice,
472 * this probably doesn't matter; at most it would cause an
473 * extra slot in the BKG table to be used up when someone
474 * prefetches this for the second time.
476 ObtainReadLock(&adc->lock);
477 ObtainWriteLock(&adc->mflock, 664);
478 adc->mflags &= ~DFNextStarted;
479 ReleaseWriteLock(&adc->mflock);
480 ReleaseReadLock(&adc->lock);
482 ReleaseWriteLock(&tdc->mflock);
485 ReleaseSharedLock(&tdc->mflock);
489 ReleaseSharedLock(&adc->mflock);
490 ReleaseReadLock(&adc->lock);
495 afs_UFSRead(register struct vcache *avc, struct uio *auio,
496 AFS_UCRED *acred, daddr_t albn, struct buf **abpp,
499 afs_size_t totalLength;
500 afs_size_t transferLength;
502 afs_size_t offset, len, tlen;
504 struct dcache *tdc = 0;
506 #ifdef AFS_DARWIN80_ENV
510 struct uio *tuiop = &tuio;
513 struct osi_file *tfile;
516 struct vrequest treq;
518 AFS_STATCNT(afs_UFSRead);
519 if (avc && avc->vc_error)
524 /* check that we have the latest status info in the vnode cache */
525 if ((code = afs_InitReq(&treq, acred)))
529 osi_Panic("null avc in afs_UFSRead");
531 code = afs_VerifyVCache(avc, &treq);
533 code = afs_CheckCode(code, &treq, 11); /* failed to get it */
539 #ifndef AFS_VM_RDWR_ENV
540 if (AFS_NFSXLATORREQ(acred)) {
542 (avc, PRSFS_READ, &treq,
543 CHECK_MODE_BITS | CMB_ALLOW_EXEC_AS_READ)) {
545 return afs_CheckCode(EACCES, &treq, 12);
550 #ifndef AFS_DARWIN80_ENV
551 tvec = (struct iovec *)osi_AllocSmallSpace(sizeof(struct iovec));
553 totalLength = AFS_UIO_RESID(auio);
554 filePos = AFS_UIO_OFFSET(auio);
555 afs_Trace4(afs_iclSetp, CM_TRACE_READ, ICL_TYPE_POINTER, avc,
556 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(filePos), ICL_TYPE_INT32,
557 totalLength, ICL_TYPE_OFFSET,
558 ICL_HANDLE_OFFSET(avc->f.m.Length));
562 ObtainReadLock(&avc->lock);
563 #if defined(AFS_TEXT_ENV) && !defined(AFS_VM_RDWR_ENV)
564 if (avc->flushDV.high == AFS_MAXDV && avc->flushDV.low == AFS_MAXDV) {
565 hset(avc->flushDV, avc->f.m.DataVersion);
569 if (filePos >= avc->f.m.Length) {
571 len = sizeof(afs_zeros); /* and in 0 buffer */
573 #ifdef AFS_DARWIN80_ENV
575 tuiop = afsio_darwin_partialcopy(auio, trimlen);
577 afsio_copy(auio, &tuio, tvec);
579 afsio_trim(&tuio, trimlen);
581 AFS_UIOMOVE(afs_zeros, trimlen, UIO_READ, tuiop, code);
584 while (avc->f.m.Length > 0 && totalLength > 0) {
585 /* read all of the cached info */
586 if (filePos >= avc->f.m.Length)
587 break; /* all done */
590 ReleaseReadLock(&tdc->lock);
593 tdc = afs_FindDCache(avc, filePos);
595 ObtainReadLock(&tdc->lock);
596 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
597 len = tdc->validPos - filePos;
600 /* a tricky question: does the presence of the DFFetching flag
601 * mean that we're fetching the latest version of the file? No.
602 * The server could update the file as soon as the fetch responsible
603 * for the setting of the DFFetching flag completes.
605 * However, the presence of the DFFetching flag (visible under
606 * a dcache read lock since it is set and cleared only under a
607 * dcache write lock) means that we're fetching as good a version
608 * as was known to this client at the time of the last call to
609 * afs_VerifyVCache, since the latter updates the stat cache's
610 * m.DataVersion field under a vcache write lock, and from the
611 * time that the DFFetching flag goes on in afs_GetDCache (before
612 * the fetch starts), to the time it goes off (after the fetch
613 * completes), afs_GetDCache keeps at least a read lock on the
616 * This means that if the DFFetching flag is set, we can use that
617 * data for any reads that must come from the current version of
618 * the file (current == m.DataVersion).
620 * Another way of looking at this same point is this: if we're
621 * fetching some data and then try do an afs_VerifyVCache, the
622 * VerifyVCache operation will not complete until after the
623 * DFFetching flag is turned off and the dcache entry's f.versionNo
626 * Note, by the way, that if DFFetching is set,
627 * m.DataVersion > f.versionNo (the latter is not updated until
628 * after the fetch completes).
631 ReleaseReadLock(&tdc->lock);
632 afs_PutDCache(tdc); /* before reusing tdc */
634 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 2);
635 #ifdef AFS_DISCON_ENV
637 printf("Network down in afs_read");
641 #endif /* AFS_DISCON_ENV */
643 ObtainReadLock(&tdc->lock);
644 /* now, first try to start transfer, if we'll need the data. If
645 * data already coming, we don't need to do this, obviously. Type
646 * 2 requests never return a null dcache entry, btw. */
647 if (!(tdc->dflags & DFFetching)
648 && !hsame(avc->f.m.DataVersion, tdc->f.versionNo)) {
649 /* have cache entry, it is not coming in now, and we'll need new data */
651 if (trybusy && !afs_BBusy()) {
653 /* daemon is not busy */
654 ObtainSharedLock(&tdc->mflock, 667);
655 if (!(tdc->mflags & DFFetchReq)) {
656 UpgradeSToWLock(&tdc->mflock, 668);
657 tdc->mflags |= DFFetchReq;
658 bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
659 (afs_size_t) filePos, (afs_size_t) 0,
662 /* Bkg table full; retry deadlocks */
663 tdc->mflags &= ~DFFetchReq;
664 trybusy = 0; /* Avoid bkg daemon since they're too busy */
665 ReleaseWriteLock(&tdc->mflock);
668 ConvertWToSLock(&tdc->mflock);
671 ConvertSToRLock(&tdc->mflock);
672 while (!code && tdc->mflags & DFFetchReq) {
673 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT,
674 ICL_TYPE_STRING, __FILE__, ICL_TYPE_INT32,
675 __LINE__, ICL_TYPE_POINTER, tdc,
676 ICL_TYPE_INT32, tdc->dflags);
677 /* don't need waiting flag on this one */
678 ReleaseReadLock(&tdc->mflock);
679 ReleaseReadLock(&tdc->lock);
680 ReleaseReadLock(&avc->lock);
681 code = afs_osi_SleepSig(&tdc->validPos);
682 ObtainReadLock(&avc->lock);
683 ObtainReadLock(&tdc->lock);
684 ObtainReadLock(&tdc->mflock);
686 ReleaseReadLock(&tdc->mflock);
693 /* now data may have started flowing in (if DFFetching is on). If
694 * data is now streaming in, then wait for some interesting stuff.
697 while (!code && (tdc->dflags & DFFetching)
698 && tdc->validPos <= filePos) {
699 /* too early: wait for DFFetching flag to vanish,
700 * or data to appear */
701 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
702 __FILE__, ICL_TYPE_INT32, __LINE__,
703 ICL_TYPE_POINTER, tdc, ICL_TYPE_INT32,
705 ReleaseReadLock(&tdc->lock);
706 ReleaseReadLock(&avc->lock);
707 code = afs_osi_SleepSig(&tdc->validPos);
708 ObtainReadLock(&avc->lock);
709 ObtainReadLock(&tdc->lock);
715 /* fetching flag gone, data is here, or we never tried
716 * (BBusy for instance) */
717 if (tdc->dflags & DFFetching) {
718 /* still fetching, some new data is here:
719 * compute length and offset */
720 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
721 len = tdc->validPos - filePos;
723 /* no longer fetching, verify data version (avoid new
725 if (hsame(avc->f.m.DataVersion, tdc->f.versionNo)
726 && ((len = tdc->validPos - filePos) > 0)) {
727 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
729 /* don't have current data, so get it below */
730 afs_Trace3(afs_iclSetp, CM_TRACE_VERSIONNO,
731 ICL_TYPE_INT64, ICL_HANDLE_OFFSET(filePos),
732 ICL_TYPE_HYPER, &avc->f.m.DataVersion,
733 ICL_TYPE_HYPER, &tdc->f.versionNo);
734 ReleaseReadLock(&tdc->lock);
741 /* If we get, it was not possible to start the
742 * background daemon. With flag == 1 afs_GetDCache
743 * does the FetchData rpc synchronously.
745 ReleaseReadLock(&avc->lock);
746 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 1);
747 ObtainReadLock(&avc->lock);
749 ObtainReadLock(&tdc->lock);
757 len = tdc->validPos - filePos;
758 afs_Trace3(afs_iclSetp, CM_TRACE_VNODEREAD, ICL_TYPE_POINTER, tdc,
759 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(offset),
760 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(len));
761 if (len > totalLength)
762 len = totalLength; /* will read len bytes */
763 if (len <= 0) { /* shouldn't get here if DFFetching is on */
764 afs_Trace4(afs_iclSetp, CM_TRACE_VNODEREAD2, ICL_TYPE_POINTER,
765 tdc, ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(tdc->validPos),
766 ICL_TYPE_INT32, tdc->f.chunkBytes, ICL_TYPE_INT32,
768 /* read past the end of a chunk, may not be at next chunk yet, and yet
769 * also not at eof, so may have to supply fake zeros */
770 len = AFS_CHUNKTOSIZE(tdc->f.chunk) - offset; /* bytes left in chunk addr space */
771 if (len > totalLength)
772 len = totalLength; /* and still within xfr request */
773 tlen = avc->f.m.Length - offset; /* and still within file */
777 len = sizeof(afs_zeros); /* and in 0 buffer */
778 #ifdef AFS_DARWIN80_ENV
780 tuiop = afsio_darwin_partialcopy(auio, trimlen);
782 afsio_copy(auio, &tuio, tvec);
784 afsio_trim(&tuio, trimlen);
786 AFS_UIOMOVE(afs_zeros, trimlen, UIO_READ, tuiop, code);
792 /* get the data from the file */
794 if (tfile = tdc->ihint) {
795 if (tdc->f.inode != tfile->inum) {
796 afs_warn("afs_UFSRead: %x hint mismatch tdc %d inum %d\n",
797 tdc, tdc->f.inode, tfile->inum);
799 tdc->ihint = tfile = 0;
807 tfile = (struct osi_file *)osi_UFSOpen(&tdc->f.inode);
808 #ifdef AFS_DARWIN80_ENV
810 tuiop = afsio_darwin_partialcopy(auio, trimlen);
811 uio_setoffset(tuiop, offset);
813 /* mung uio structure to be right for this transfer */
814 afsio_copy(auio, &tuio, tvec);
816 afsio_trim(&tuio, trimlen);
817 tuio.afsio_offset = offset;
820 #if defined(AFS_AIX41_ENV)
823 VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, &tuio, NULL, NULL,
824 NULL, afs_osi_credp);
826 #elif defined(AFS_AIX32_ENV)
828 VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, &tuio, NULL, NULL);
829 /* Flush all JFS pages now for big performance gain in big file cases
830 * If we do something like this, must check to be sure that AFS file
831 * isn't mmapped... see afs_gn_map() for why.
834 if (tfile->vnode->v_gnode && tfile->vnode->v_gnode->gn_seg) {
835 many different ways to do similar things:
836 so far, the best performing one is #2, but #1 might match it if we
837 straighten out the confusion regarding which pages to flush. It
839 1. vm_flushp(tfile->vnode->v_gnode->gn_seg, 0, len/PAGESIZE - 1);
840 2. vm_releasep(tfile->vnode->v_gnode->gn_seg, offset/PAGESIZE,
841 (len + PAGESIZE-1)/PAGESIZE);
842 3. vms_inactive(tfile->vnode->v_gnode->gn_seg) Doesn't work correctly
843 4. vms_delete(tfile->vnode->v_gnode->gn_seg) probably also fails
844 tfile->vnode->v_gnode->gn_seg = NULL;
848 Unfortunately, this seems to cause frequent "cache corruption" episodes.
849 vm_releasep(tfile->vnode->v_gnode->gn_seg, offset/PAGESIZE,
850 (len + PAGESIZE-1)/PAGESIZE);
853 #elif defined(AFS_AIX_ENV)
855 VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, (off_t) & offset,
856 &tuio, NULL, NULL, -1);
857 #elif defined(AFS_SUN5_ENV)
859 #ifdef AFS_SUN510_ENV
863 VOP_RWLOCK(tfile->vnode, 0, &ct);
864 code = VOP_READ(tfile->vnode, &tuio, 0, afs_osi_credp, &ct);
865 VOP_RWUNLOCK(tfile->vnode, 0, &ct);
868 VOP_RWLOCK(tfile->vnode, 0);
869 code = VOP_READ(tfile->vnode, &tuio, 0, afs_osi_credp);
870 VOP_RWUNLOCK(tfile->vnode, 0);
873 #elif defined(AFS_SGI_ENV)
875 AFS_VOP_RWLOCK(tfile->vnode, VRWLOCK_READ);
876 AFS_VOP_READ(tfile->vnode, &tuio, IO_ISLOCKED, afs_osi_credp,
878 AFS_VOP_RWUNLOCK(tfile->vnode, VRWLOCK_READ);
880 #elif defined(AFS_OSF_ENV)
881 tuio.uio_rw = UIO_READ;
883 VOP_READ(tfile->vnode, &tuio, 0, afs_osi_credp, code);
885 #elif defined(AFS_HPUX100_ENV)
887 code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, afs_osi_credp);
889 #elif defined(AFS_LINUX20_ENV)
891 code = osi_rdwr(tfile, &tuio, UIO_READ);
893 #elif defined(AFS_DARWIN80_ENV)
895 code = VNOP_READ(tfile->vnode, tuiop, 0, afs_osi_ctxtp);
897 #elif defined(AFS_DARWIN_ENV)
899 VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, current_proc());
900 code = VOP_READ(tfile->vnode, &tuio, 0, afs_osi_credp);
901 VOP_UNLOCK(tfile->vnode, 0, current_proc());
903 #elif defined(AFS_FBSD80_ENV)
905 VOP_LOCK(tfile->vnode, LK_EXCLUSIVE);
906 code = VOP_READ(tfile->vnode, &tuio, 0, afs_osi_credp);
907 VOP_UNLOCK(tfile->vnode, 0);
909 #elif defined(AFS_FBSD50_ENV)
911 VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, curthread);
912 code = VOP_READ(tfile->vnode, &tuio, 0, afs_osi_credp);
913 VOP_UNLOCK(tfile->vnode, 0, curthread);
915 #elif defined(AFS_XBSD_ENV)
917 VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, curproc);
918 code = VOP_READ(tfile->vnode, &tuio, 0, afs_osi_credp);
919 VOP_UNLOCK(tfile->vnode, 0, curproc);
922 code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, afs_osi_credp);
926 if (!tdc->ihint && nihints < maxIHint) {
938 /* otherwise we've read some, fixup length, etc and continue with next seg */
939 len = len - AFS_UIO_RESID(tuiop); /* compute amount really transferred */
941 afsio_skip(auio, trimlen); /* update input uio structure */
943 transferLength += len;
946 break; /* surprise eof */
947 #ifdef AFS_DARWIN80_ENV
955 /* if we make it here with tdc non-zero, then it is the last chunk we
956 * dealt with, and we have to release it when we're done. We hold on
957 * to it in case we need to do a prefetch, obviously.
960 ReleaseReadLock(&tdc->lock);
961 #if !defined(AFS_VM_RDWR_ENV)
962 /* try to queue prefetch, if needed */
964 if (!(tdc->mflags & DFNextStarted))
965 afs_PrefetchChunk(avc, tdc, acred, &treq);
971 ReleaseReadLock(&avc->lock);
973 #ifdef AFS_DARWIN80_ENV
977 osi_FreeSmallSpace(tvec);
980 error = afs_CheckCode(error, &treq, 13);