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 */
123 #ifdef AFS_DARWIN80_ENV
125 tuiop = afsio_darwin_partialcopy(auio, trimlen);
127 afsio_copy(auio, &tuio, tvec);
129 afsio_trim(&tuio, trimlen);
131 AFS_UIOMOVE(afs_zeros, trimlen, UIO_READ, tuiop, code);
134 while (avc->m.Length > 0 && totalLength > 0) {
135 /* read all of the cached info */
136 if (filePos >= avc->m.Length)
137 break; /* all done */
140 ReleaseReadLock(&tdc->lock);
143 tdc = afs_FindDCache(avc, filePos);
145 ObtainReadLock(&tdc->lock);
146 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
147 len = tdc->f.chunkBytes - offset;
150 /* a tricky question: does the presence of the DFFetching flag
151 * mean that we're fetching the latest version of the file? No.
152 * The server could update the file as soon as the fetch responsible
153 * for the setting of the DFFetching flag completes.
155 * However, the presence of the DFFetching flag (visible under
156 * a dcache read lock since it is set and cleared only under a
157 * dcache write lock) means that we're fetching as good a version
158 * as was known to this client at the time of the last call to
159 * afs_VerifyVCache, since the latter updates the stat cache's
160 * m.DataVersion field under a vcache write lock, and from the
161 * time that the DFFetching flag goes on in afs_GetDCache (before
162 * the fetch starts), to the time it goes off (after the fetch
163 * completes), afs_GetDCache keeps at least a read lock on the
166 * This means that if the DFFetching flag is set, we can use that
167 * data for any reads that must come from the current version of
168 * the file (current == m.DataVersion).
170 * Another way of looking at this same point is this: if we're
171 * fetching some data and then try do an afs_VerifyVCache, the
172 * VerifyVCache operation will not complete until after the
173 * DFFetching flag is turned off and the dcache entry's f.versionNo
176 * Note, by the way, that if DFFetching is set,
177 * m.DataVersion > f.versionNo (the latter is not updated until
178 * after the fetch completes).
181 ReleaseReadLock(&tdc->lock);
182 afs_PutDCache(tdc); /* before reusing tdc */
184 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 2);
185 ObtainReadLock(&tdc->lock);
186 /* now, first try to start transfer, if we'll need the data. If
187 * data already coming, we don't need to do this, obviously. Type
188 * 2 requests never return a null dcache entry, btw.
190 if (!(tdc->dflags & DFFetching)
191 && !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
192 /* have cache entry, it is not coming in now,
193 * and we'll need new data */
195 if (trybusy && !afs_BBusy()) {
197 /* daemon is not busy */
198 ObtainSharedLock(&tdc->mflock, 665);
199 if (!(tdc->mflags & DFFetchReq)) {
200 /* start the daemon (may already be running, however) */
201 UpgradeSToWLock(&tdc->mflock, 666);
202 tdc->mflags |= DFFetchReq;
203 bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
204 (afs_size_t) filePos, (afs_size_t) 0,
207 tdc->mflags &= ~DFFetchReq;
208 trybusy = 0; /* Avoid bkg daemon since they're too busy */
209 ReleaseWriteLock(&tdc->mflock);
212 ConvertWToSLock(&tdc->mflock);
213 /* don't use bp pointer! */
216 ConvertSToRLock(&tdc->mflock);
217 while (!code && tdc->mflags & DFFetchReq) {
218 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT,
219 ICL_TYPE_STRING, __FILE__, ICL_TYPE_INT32,
220 __LINE__, ICL_TYPE_POINTER, tdc,
221 ICL_TYPE_INT32, tdc->dflags);
222 /* don't need waiting flag on this one */
223 ReleaseReadLock(&tdc->mflock);
224 ReleaseReadLock(&tdc->lock);
225 ReleaseReadLock(&avc->lock);
226 code = afs_osi_SleepSig(&tdc->validPos);
227 ObtainReadLock(&avc->lock);
228 ObtainReadLock(&tdc->lock);
229 ObtainReadLock(&tdc->mflock);
231 ReleaseReadLock(&tdc->mflock);
238 /* now data may have started flowing in (if DFFetching is on). If
239 * data is now streaming in, then wait for some interesting stuff.
242 while (!code && (tdc->dflags & DFFetching)
243 && tdc->validPos <= filePos) {
244 /* too early: wait for DFFetching flag to vanish,
245 * or data to appear */
246 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
247 __FILE__, ICL_TYPE_INT32, __LINE__,
248 ICL_TYPE_POINTER, tdc, ICL_TYPE_INT32,
250 ReleaseReadLock(&tdc->lock);
251 ReleaseReadLock(&avc->lock);
252 code = afs_osi_SleepSig(&tdc->validPos);
253 ObtainReadLock(&avc->lock);
254 ObtainReadLock(&tdc->lock);
260 /* fetching flag gone, data is here, or we never tried
261 * (BBusy for instance) */
262 if (tdc->dflags & DFFetching) {
263 /* still fetching, some new data is here:
264 * compute length and offset */
265 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
266 len = tdc->validPos - filePos;
268 /* no longer fetching, verify data version
269 * (avoid new GetDCache call) */
270 if (hsame(avc->m.DataVersion, tdc->f.versionNo)
271 && ((len = tdc->validPos - filePos) > 0)) {
272 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
274 /* don't have current data, so get it below */
275 afs_Trace3(afs_iclSetp, CM_TRACE_VERSIONNO,
276 ICL_TYPE_INT64, ICL_HANDLE_OFFSET(filePos),
277 ICL_TYPE_HYPER, &avc->m.DataVersion,
278 ICL_TYPE_HYPER, &tdc->f.versionNo);
279 ReleaseReadLock(&tdc->lock);
286 /* If we get, it was not possible to start the
287 * background daemon. With flag == 1 afs_GetDCache
288 * does the FetchData rpc synchronously.
290 ReleaseReadLock(&avc->lock);
291 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 1);
292 ObtainReadLock(&avc->lock);
294 ObtainReadLock(&tdc->lock);
298 afs_Trace3(afs_iclSetp, CM_TRACE_VNODEREAD, ICL_TYPE_POINTER, tdc,
299 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(offset),
300 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(len));
312 if (len > totalLength)
313 len = totalLength; /* will read len bytes */
314 if (len <= 0) { /* shouldn't get here if DFFetching is on */
315 /* read past the end of a chunk, may not be at next chunk yet, and yet
316 * also not at eof, so may have to supply fake zeros */
317 len = AFS_CHUNKTOSIZE(tdc->f.chunk) - offset; /* bytes left in chunk addr space */
318 if (len > totalLength)
319 len = totalLength; /* and still within xfr request */
320 tlen = avc->m.Length - offset; /* and still within file */
324 len = sizeof(afs_zeros); /* and in 0 buffer */
325 #ifdef AFS_DARWIN80_ENV
327 tuiop = afsio_darwin_partialcopy(auio, trimlen);
329 afsio_copy(auio, &tuio, tvec);
331 afsio_trim(&tuio, trimlen);
333 AFS_UIOMOVE(afs_zeros, trimlen, UIO_READ, tuiop, code);
339 /* get the data from the mem cache */
341 /* mung uio structure to be right for this transfer */
342 #ifdef AFS_DARWIN80_ENV
344 tuiop = afsio_darwin_partialcopy(auio, trimlen);
345 uio_setoffset(tuiop, offset);
347 afsio_copy(auio, &tuio, tvec);
349 afsio_trim(&tuio, trimlen);
350 tuio.afsio_offset = offset;
353 code = afs_MemReadUIO(tdc->f.inode, tuiop);
360 /* otherwise we've read some, fixup length, etc and continue with next seg */
361 len = len - AFS_UIO_RESID(tuiop); /* compute amount really transferred */
363 afsio_skip(auio, trimlen); /* update input uio structure */
365 transferLength += len;
369 break; /* surprise eof */
370 #ifdef AFS_DARWIN80_ENV
376 } /* the whole while loop */
381 * tdc->lock(R) if tdc
384 /* if we make it here with tdc non-zero, then it is the last chunk we
385 * dealt with, and we have to release it when we're done. We hold on
386 * to it in case we need to do a prefetch.
389 ReleaseReadLock(&tdc->lock);
390 #if !defined(AFS_VM_RDWR_ENV)
391 /* try to queue prefetch, if needed */
393 afs_PrefetchChunk(avc, tdc, acred, &treq);
399 ReleaseReadLock(&avc->lock);
400 #ifdef AFS_DARWIN80_ENV
404 osi_FreeSmallSpace(tvec);
406 error = afs_CheckCode(error, &treq, 10);
410 /* called with the dcache entry triggering the fetch, the vcache entry involved,
411 * and a vrequest for the read call. Marks the dcache entry as having already
412 * triggered a prefetch, starts the prefetch going and sets the DFFetchReq
413 * flag in the prefetched block, so that the next call to read knows to wait
414 * for the daemon to start doing things.
416 * This function must be called with the vnode at least read-locked, and
417 * no locks on the dcache, because it plays around with dcache entries.
420 afs_PrefetchChunk(struct vcache *avc, struct dcache *adc,
421 struct AFS_UCRED *acred, struct vrequest *areq)
423 register struct dcache *tdc;
425 afs_size_t j1, j2; /* junk vbls for GetDCache to trash */
427 offset = adc->f.chunk + 1; /* next chunk we'll need */
428 offset = AFS_CHUNKTOBASE(offset); /* base of next chunk */
429 ObtainReadLock(&adc->lock);
430 ObtainSharedLock(&adc->mflock, 662);
431 if (offset < avc->m.Length && !(adc->mflags & DFNextStarted)
435 UpgradeSToWLock(&adc->mflock, 663);
436 adc->mflags |= DFNextStarted; /* we've tried to prefetch for this guy */
437 ReleaseWriteLock(&adc->mflock);
438 ReleaseReadLock(&adc->lock);
440 tdc = afs_GetDCache(avc, offset, areq, &j1, &j2, 2); /* type 2 never returns 0 */
441 ObtainSharedLock(&tdc->mflock, 651);
442 if (!(tdc->mflags & DFFetchReq)) {
443 /* ask the daemon to do the work */
444 UpgradeSToWLock(&tdc->mflock, 652);
445 tdc->mflags |= DFFetchReq; /* guaranteed to be cleared by BKG or GetDCache */
446 /* last parm (1) tells bkg daemon to do an afs_PutDCache when it is done,
447 * since we don't want to wait for it to finish before doing so ourselves.
449 bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
450 (afs_size_t) offset, (afs_size_t) 1, tdc);
452 /* Bkg table full; just abort non-important prefetching to avoid deadlocks */
453 tdc->mflags &= ~DFFetchReq;
454 ReleaseWriteLock(&tdc->mflock);
458 * DCLOCKXXX: This is a little sketchy, since someone else
459 * could have already started a prefetch.. In practice,
460 * this probably doesn't matter; at most it would cause an
461 * extra slot in the BKG table to be used up when someone
462 * prefetches this for the second time.
464 ObtainReadLock(&adc->lock);
465 ObtainWriteLock(&adc->mflock, 664);
466 adc->mflags &= ~DFNextStarted;
467 ReleaseWriteLock(&adc->mflock);
468 ReleaseReadLock(&adc->lock);
470 ReleaseWriteLock(&tdc->mflock);
473 ReleaseSharedLock(&tdc->mflock);
477 ReleaseSharedLock(&adc->mflock);
478 ReleaseReadLock(&adc->lock);
483 afs_UFSRead(register struct vcache *avc, struct uio *auio,
484 struct AFS_UCRED *acred, daddr_t albn, struct buf **abpp,
487 afs_size_t totalLength;
488 afs_size_t transferLength;
490 afs_size_t offset, len, tlen;
492 struct dcache *tdc = 0;
494 #ifdef AFS_DARWIN80_ENV
498 struct uio *tuiop = &tuio;
501 struct osi_file *tfile;
504 struct vrequest treq;
506 AFS_STATCNT(afs_UFSRead);
507 if (avc && avc->vc_error)
510 /* check that we have the latest status info in the vnode cache */
511 if ((code = afs_InitReq(&treq, acred)))
515 osi_Panic("null avc in afs_UFSRead");
517 code = afs_VerifyVCache(avc, &treq);
519 code = afs_CheckCode(code, &treq, 11); /* failed to get it */
524 #ifndef AFS_VM_RDWR_ENV
525 if (AFS_NFSXLATORREQ(acred)) {
527 (avc, PRSFS_READ, &treq,
528 CHECK_MODE_BITS | CMB_ALLOW_EXEC_AS_READ)) {
529 return afs_CheckCode(EACCES, &treq, 12);
534 #ifndef AFS_DARWIN80_ENV
535 tvec = (struct iovec *)osi_AllocSmallSpace(sizeof(struct iovec));
537 totalLength = AFS_UIO_RESID(auio);
538 filePos = AFS_UIO_OFFSET(auio);
539 afs_Trace4(afs_iclSetp, CM_TRACE_READ, ICL_TYPE_POINTER, avc,
540 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(filePos), ICL_TYPE_INT32,
541 totalLength, ICL_TYPE_OFFSET,
542 ICL_HANDLE_OFFSET(avc->m.Length));
546 ObtainReadLock(&avc->lock);
547 #if defined(AFS_TEXT_ENV) && !defined(AFS_VM_RDWR_ENV)
548 if (avc->flushDV.high == AFS_MAXDV && avc->flushDV.low == AFS_MAXDV) {
549 hset(avc->flushDV, avc->m.DataVersion);
553 if (filePos >= avc->m.Length) {
555 len = sizeof(afs_zeros); /* and in 0 buffer */
557 #ifdef AFS_DARWIN80_ENV
559 tuiop = afsio_darwin_partialcopy(auio, trimlen);
561 afsio_copy(auio, &tuio, tvec);
563 afsio_trim(&tuio, trimlen);
565 AFS_UIOMOVE(afs_zeros, trimlen, UIO_READ, tuiop, code);
568 while (avc->m.Length > 0 && totalLength > 0) {
569 /* read all of the cached info */
570 if (filePos >= avc->m.Length)
571 break; /* all done */
574 ReleaseReadLock(&tdc->lock);
577 tdc = afs_FindDCache(avc, filePos);
579 ObtainReadLock(&tdc->lock);
580 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
581 len = tdc->validPos - filePos;
584 /* a tricky question: does the presence of the DFFetching flag
585 * mean that we're fetching the latest version of the file? No.
586 * The server could update the file as soon as the fetch responsible
587 * for the setting of the DFFetching flag completes.
589 * However, the presence of the DFFetching flag (visible under
590 * a dcache read lock since it is set and cleared only under a
591 * dcache write lock) means that we're fetching as good a version
592 * as was known to this client at the time of the last call to
593 * afs_VerifyVCache, since the latter updates the stat cache's
594 * m.DataVersion field under a vcache write lock, and from the
595 * time that the DFFetching flag goes on in afs_GetDCache (before
596 * the fetch starts), to the time it goes off (after the fetch
597 * completes), afs_GetDCache keeps at least a read lock on the
600 * This means that if the DFFetching flag is set, we can use that
601 * data for any reads that must come from the current version of
602 * the file (current == m.DataVersion).
604 * Another way of looking at this same point is this: if we're
605 * fetching some data and then try do an afs_VerifyVCache, the
606 * VerifyVCache operation will not complete until after the
607 * DFFetching flag is turned off and the dcache entry's f.versionNo
610 * Note, by the way, that if DFFetching is set,
611 * m.DataVersion > f.versionNo (the latter is not updated until
612 * after the fetch completes).
615 ReleaseReadLock(&tdc->lock);
616 afs_PutDCache(tdc); /* before reusing tdc */
618 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 2);
619 ObtainReadLock(&tdc->lock);
620 /* now, first try to start transfer, if we'll need the data. If
621 * data already coming, we don't need to do this, obviously. Type
622 * 2 requests never return a null dcache entry, btw. */
623 if (!(tdc->dflags & DFFetching)
624 && !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
625 /* have cache entry, it is not coming in now, and we'll need new data */
627 if (trybusy && !afs_BBusy()) {
629 /* daemon is not busy */
630 ObtainSharedLock(&tdc->mflock, 667);
631 if (!(tdc->mflags & DFFetchReq)) {
632 UpgradeSToWLock(&tdc->mflock, 668);
633 tdc->mflags |= DFFetchReq;
634 bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
635 (afs_size_t) filePos, (afs_size_t) 0,
638 /* Bkg table full; retry deadlocks */
639 tdc->mflags &= ~DFFetchReq;
640 trybusy = 0; /* Avoid bkg daemon since they're too busy */
641 ReleaseWriteLock(&tdc->mflock);
644 ConvertWToSLock(&tdc->mflock);
647 ConvertSToRLock(&tdc->mflock);
648 while (!code && tdc->mflags & DFFetchReq) {
649 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT,
650 ICL_TYPE_STRING, __FILE__, ICL_TYPE_INT32,
651 __LINE__, ICL_TYPE_POINTER, tdc,
652 ICL_TYPE_INT32, tdc->dflags);
653 /* don't need waiting flag on this one */
654 ReleaseReadLock(&tdc->mflock);
655 ReleaseReadLock(&tdc->lock);
656 ReleaseReadLock(&avc->lock);
657 code = afs_osi_SleepSig(&tdc->validPos);
658 ObtainReadLock(&avc->lock);
659 ObtainReadLock(&tdc->lock);
660 ObtainReadLock(&tdc->mflock);
662 ReleaseReadLock(&tdc->mflock);
669 /* now data may have started flowing in (if DFFetching is on). If
670 * data is now streaming in, then wait for some interesting stuff.
673 while (!code && (tdc->dflags & DFFetching)
674 && tdc->validPos <= filePos) {
675 /* too early: wait for DFFetching flag to vanish,
676 * or data to appear */
677 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
678 __FILE__, ICL_TYPE_INT32, __LINE__,
679 ICL_TYPE_POINTER, tdc, ICL_TYPE_INT32,
681 ReleaseReadLock(&tdc->lock);
682 ReleaseReadLock(&avc->lock);
683 code = afs_osi_SleepSig(&tdc->validPos);
684 ObtainReadLock(&avc->lock);
685 ObtainReadLock(&tdc->lock);
691 /* fetching flag gone, data is here, or we never tried
692 * (BBusy for instance) */
693 if (tdc->dflags & DFFetching) {
694 /* still fetching, some new data is here:
695 * compute length and offset */
696 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
697 len = tdc->validPos - filePos;
699 /* no longer fetching, verify data version (avoid new
701 if (hsame(avc->m.DataVersion, tdc->f.versionNo)
702 && ((len = tdc->validPos - filePos) > 0)) {
703 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
705 /* don't have current data, so get it below */
706 afs_Trace3(afs_iclSetp, CM_TRACE_VERSIONNO,
707 ICL_TYPE_INT64, ICL_HANDLE_OFFSET(filePos),
708 ICL_TYPE_HYPER, &avc->m.DataVersion,
709 ICL_TYPE_HYPER, &tdc->f.versionNo);
710 ReleaseReadLock(&tdc->lock);
717 /* If we get, it was not possible to start the
718 * background daemon. With flag == 1 afs_GetDCache
719 * does the FetchData rpc synchronously.
721 ReleaseReadLock(&avc->lock);
722 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 1);
723 ObtainReadLock(&avc->lock);
725 ObtainReadLock(&tdc->lock);
733 len = tdc->validPos - filePos;
734 afs_Trace3(afs_iclSetp, CM_TRACE_VNODEREAD, ICL_TYPE_POINTER, tdc,
735 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(offset),
736 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(len));
737 if (len > totalLength)
738 len = totalLength; /* will read len bytes */
739 if (len <= 0) { /* shouldn't get here if DFFetching is on */
740 afs_Trace4(afs_iclSetp, CM_TRACE_VNODEREAD2, ICL_TYPE_POINTER,
741 tdc, ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(tdc->validPos),
742 ICL_TYPE_INT32, tdc->f.chunkBytes, ICL_TYPE_INT32,
744 /* read past the end of a chunk, may not be at next chunk yet, and yet
745 * also not at eof, so may have to supply fake zeros */
746 len = AFS_CHUNKTOSIZE(tdc->f.chunk) - offset; /* bytes left in chunk addr space */
747 if (len > totalLength)
748 len = totalLength; /* and still within xfr request */
749 tlen = avc->m.Length - offset; /* and still within file */
753 len = sizeof(afs_zeros); /* and in 0 buffer */
754 #ifdef AFS_DARWIN80_ENV
756 tuiop = afsio_darwin_partialcopy(auio, trimlen);
758 afsio_copy(auio, &tuio, tvec);
760 afsio_trim(&tuio, trimlen);
762 AFS_UIOMOVE(afs_zeros, trimlen, UIO_READ, tuiop, code);
768 /* get the data from the file */
770 if (tfile = tdc->ihint) {
771 if (tdc->f.inode != tfile->inum) {
772 afs_warn("afs_UFSRead: %x hint mismatch tdc %d inum %d\n",
773 tdc, tdc->f.inode, tfile->inum);
775 tdc->ihint = tfile = 0;
784 tfile = (struct osi_file *)osi_UFSOpen(tdc->f.inode);
785 #ifdef AFS_DARWIN80_ENV
787 tuiop = afsio_darwin_partialcopy(auio, trimlen);
788 uio_setoffset(tuiop, offset);
790 /* mung uio structure to be right for this transfer */
791 afsio_copy(auio, &tuio, tvec);
793 afsio_trim(&tuio, trimlen);
794 tuio.afsio_offset = offset;
797 #if defined(AFS_AIX41_ENV)
800 VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, &tuio, NULL, NULL,
801 NULL, afs_osi_credp);
803 #elif defined(AFS_AIX32_ENV)
805 VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, &tuio, NULL, NULL);
806 /* Flush all JFS pages now for big performance gain in big file cases
807 * If we do something like this, must check to be sure that AFS file
808 * isn't mmapped... see afs_gn_map() for why.
811 if (tfile->vnode->v_gnode && tfile->vnode->v_gnode->gn_seg) {
812 many different ways to do similar things:
813 so far, the best performing one is #2, but #1 might match it if we
814 straighten out the confusion regarding which pages to flush. It
816 1. vm_flushp(tfile->vnode->v_gnode->gn_seg, 0, len/PAGESIZE - 1);
817 2. vm_releasep(tfile->vnode->v_gnode->gn_seg, offset/PAGESIZE,
818 (len + PAGESIZE-1)/PAGESIZE);
819 3. vms_inactive(tfile->vnode->v_gnode->gn_seg) Doesn't work correctly
820 4. vms_delete(tfile->vnode->v_gnode->gn_seg) probably also fails
821 tfile->vnode->v_gnode->gn_seg = NULL;
825 Unfortunately, this seems to cause frequent "cache corruption" episodes.
826 vm_releasep(tfile->vnode->v_gnode->gn_seg, offset/PAGESIZE,
827 (len + PAGESIZE-1)/PAGESIZE);
830 #elif defined(AFS_AIX_ENV)
832 VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, (off_t) & offset,
833 &tuio, NULL, NULL, -1);
834 #elif defined(AFS_SUN5_ENV)
836 #ifdef AFS_SUN510_ENV
840 VOP_RWLOCK(tfile->vnode, 0, &ct);
841 code = VOP_READ(tfile->vnode, &tuio, 0, afs_osi_credp, &ct);
842 VOP_RWUNLOCK(tfile->vnode, 0, &ct);
845 VOP_RWLOCK(tfile->vnode, 0);
846 code = VOP_READ(tfile->vnode, &tuio, 0, afs_osi_credp);
847 VOP_RWUNLOCK(tfile->vnode, 0);
850 #elif defined(AFS_SGI_ENV)
852 AFS_VOP_RWLOCK(tfile->vnode, VRWLOCK_READ);
853 AFS_VOP_READ(tfile->vnode, &tuio, IO_ISLOCKED, afs_osi_credp,
855 AFS_VOP_RWUNLOCK(tfile->vnode, VRWLOCK_READ);
857 #elif defined(AFS_OSF_ENV)
858 tuio.uio_rw = UIO_READ;
860 VOP_READ(tfile->vnode, &tuio, 0, afs_osi_credp, code);
862 #elif defined(AFS_HPUX100_ENV)
864 code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, afs_osi_credp);
866 #elif defined(AFS_LINUX20_ENV)
868 code = osi_rdwr(tfile, &tuio, UIO_READ);
870 #elif defined(AFS_DARWIN80_ENV)
872 code = VNOP_READ(tfile->vnode, tuiop, 0, afs_osi_ctxtp);
874 #elif defined(AFS_DARWIN_ENV)
876 VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, current_proc());
877 code = VOP_READ(tfile->vnode, &tuio, 0, afs_osi_credp);
878 VOP_UNLOCK(tfile->vnode, 0, current_proc());
880 #elif defined(AFS_FBSD50_ENV)
882 VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, curthread);
883 code = VOP_READ(tfile->vnode, &tuio, 0, afs_osi_credp);
884 VOP_UNLOCK(tfile->vnode, 0, curthread);
886 #elif defined(AFS_XBSD_ENV)
888 VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, curproc);
889 code = VOP_READ(tfile->vnode, &tuio, 0, afs_osi_credp);
890 VOP_UNLOCK(tfile->vnode, 0, curproc);
893 code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, afs_osi_credp);
897 if (!tdc->ihint && nihints < maxIHint) {
909 /* otherwise we've read some, fixup length, etc and continue with next seg */
910 len = len - AFS_UIO_RESID(tuiop); /* compute amount really transferred */
912 afsio_skip(auio, trimlen); /* update input uio structure */
914 transferLength += len;
917 break; /* surprise eof */
918 #ifdef AFS_DARWIN80_ENV
926 /* if we make it here with tdc non-zero, then it is the last chunk we
927 * dealt with, and we have to release it when we're done. We hold on
928 * to it in case we need to do a prefetch, obviously.
931 ReleaseReadLock(&tdc->lock);
932 #if !defined(AFS_VM_RDWR_ENV)
933 /* try to queue prefetch, if needed */
935 if (!(tdc->mflags & DFNextStarted))
936 afs_PrefetchChunk(avc, tdc, acred, &treq);
942 ReleaseReadLock(&avc->lock);
944 #ifdef AFS_DARWIN80_ENV
948 osi_FreeSmallSpace(tvec);
950 error = afs_CheckCode(error, &treq, 13);