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"
32 extern char afs_zeros[AFS_ZEROS];
35 afs_int32 nihints; /* # of above actually in-use */
39 /* Imported variables */
40 extern afs_rwlock_t afs_xdcache;
41 extern unsigned char *afs_indexFlags;
42 extern afs_hyper_t *afs_indexTimes; /* Dcache entry Access times */
43 extern afs_hyper_t afs_indexCounter; /* Fake time for marking index */
46 /* Forward declarations */
47 void afs_PrefetchChunk(struct vcache *avc, struct dcache *adc,
48 struct AFS_UCRED *acred, struct vrequest *areq);
51 afs_MemRead(register struct vcache *avc, struct uio *auio,
52 struct AFS_UCRED *acred, daddr_t albn, struct buf **abpp,
55 afs_size_t totalLength;
56 afs_size_t transferLength;
58 afs_size_t offset, len, tlen;
60 struct dcache *tdc = 0;
61 afs_int32 error, trybusy = 1;
67 AFS_STATCNT(afs_MemRead);
71 /* check that we have the latest status info in the vnode cache */
72 if ((code = afs_InitReq(&treq, acred)))
75 code = afs_VerifyVCache(avc, &treq);
77 code = afs_CheckCode(code, &treq, 8); /* failed to get it */
81 #ifndef AFS_VM_RDWR_ENV
82 if (AFS_NFSXLATORREQ(acred)) {
84 (avc, PRSFS_READ, &treq,
85 CHECK_MODE_BITS | CMB_ALLOW_EXEC_AS_READ)) {
86 return afs_CheckCode(EACCES, &treq, 9);
91 tvec = (struct iovec *)osi_AllocSmallSpace(sizeof(struct iovec));
92 totalLength = auio->afsio_resid;
93 filePos = auio->afsio_offset;
94 afs_Trace4(afs_iclSetp, CM_TRACE_READ, ICL_TYPE_POINTER, avc,
95 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(filePos), ICL_TYPE_INT32,
96 totalLength, ICL_TYPE_OFFSET,
97 ICL_HANDLE_OFFSET(avc->m.Length));
101 ObtainReadLock(&avc->lock);
102 #if defined(AFS_TEXT_ENV) && !defined(AFS_VM_RDWR_ENV)
103 if (avc->flushDV.high == AFS_MAXDV && avc->flushDV.low == AFS_MAXDV) {
104 hset(avc->flushDV, avc->m.DataVersion);
112 while (totalLength > 0) {
113 /* read all of the cached info */
114 if (filePos >= avc->m.Length)
115 break; /* all done */
118 ReleaseReadLock(&tdc->lock);
121 tdc = afs_FindDCache(avc, filePos);
123 ObtainReadLock(&tdc->lock);
124 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
125 len = tdc->f.chunkBytes - offset;
128 /* a tricky question: does the presence of the DFFetching flag
129 * mean that we're fetching the latest version of the file? No.
130 * The server could update the file as soon as the fetch responsible
131 * for the setting of the DFFetching flag completes.
133 * However, the presence of the DFFetching flag (visible under
134 * a dcache read lock since it is set and cleared only under a
135 * dcache write lock) means that we're fetching as good a version
136 * as was known to this client at the time of the last call to
137 * afs_VerifyVCache, since the latter updates the stat cache's
138 * m.DataVersion field under a vcache write lock, and from the
139 * time that the DFFetching flag goes on in afs_GetDCache (before
140 * the fetch starts), to the time it goes off (after the fetch
141 * completes), afs_GetDCache keeps at least a read lock on the
144 * This means that if the DFFetching flag is set, we can use that
145 * data for any reads that must come from the current version of
146 * the file (current == m.DataVersion).
148 * Another way of looking at this same point is this: if we're
149 * fetching some data and then try do an afs_VerifyVCache, the
150 * VerifyVCache operation will not complete until after the
151 * DFFetching flag is turned off and the dcache entry's f.versionNo
154 * Note, by the way, that if DFFetching is set,
155 * m.DataVersion > f.versionNo (the latter is not updated until
156 * after the fetch completes).
159 ReleaseReadLock(&tdc->lock);
160 afs_PutDCache(tdc); /* before reusing tdc */
162 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 2);
163 ObtainReadLock(&tdc->lock);
164 /* now, first try to start transfer, if we'll need the data. If
165 * data already coming, we don't need to do this, obviously. Type
166 * 2 requests never return a null dcache entry, btw.
168 if (!(tdc->dflags & DFFetching)
169 && !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
170 /* have cache entry, it is not coming in now,
171 * and we'll need new data */
173 if (trybusy && !afs_BBusy()) {
175 /* daemon is not busy */
176 ObtainSharedLock(&tdc->mflock, 665);
177 if (!(tdc->mflags & DFFetchReq)) {
178 /* start the daemon (may already be running, however) */
179 UpgradeSToWLock(&tdc->mflock, 666);
180 tdc->mflags |= DFFetchReq;
181 bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
182 (afs_size_t) filePos, (afs_size_t) 0,
185 tdc->mflags &= ~DFFetchReq;
186 trybusy = 0; /* Avoid bkg daemon since they're too busy */
187 ReleaseWriteLock(&tdc->mflock);
190 ConvertWToSLock(&tdc->mflock);
191 /* don't use bp pointer! */
194 ConvertSToRLock(&tdc->mflock);
195 while (!code && tdc->mflags & DFFetchReq) {
196 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT,
197 ICL_TYPE_STRING, __FILE__, ICL_TYPE_INT32,
198 __LINE__, ICL_TYPE_POINTER, tdc,
199 ICL_TYPE_INT32, tdc->dflags);
200 /* don't need waiting flag on this one */
201 ReleaseReadLock(&tdc->mflock);
202 ReleaseReadLock(&tdc->lock);
203 ReleaseReadLock(&avc->lock);
204 code = afs_osi_SleepSig(&tdc->validPos);
205 ObtainReadLock(&avc->lock);
206 ObtainReadLock(&tdc->lock);
207 ObtainReadLock(&tdc->mflock);
209 ReleaseReadLock(&tdc->mflock);
216 /* now data may have started flowing in (if DFFetching is on). If
217 * data is now streaming in, then wait for some interesting stuff.
220 while (!code && (tdc->dflags & DFFetching)
221 && tdc->validPos <= filePos) {
222 /* too early: wait for DFFetching flag to vanish,
223 * or data to appear */
224 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
225 __FILE__, ICL_TYPE_INT32, __LINE__,
226 ICL_TYPE_POINTER, tdc, ICL_TYPE_INT32,
228 ReleaseReadLock(&tdc->lock);
229 ReleaseReadLock(&avc->lock);
230 code = afs_osi_SleepSig(&tdc->validPos);
231 ObtainReadLock(&avc->lock);
232 ObtainReadLock(&tdc->lock);
238 /* fetching flag gone, data is here, or we never tried
239 * (BBusy for instance) */
240 if (tdc->dflags & DFFetching) {
241 /* still fetching, some new data is here:
242 * compute length and offset */
243 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
244 len = tdc->validPos - filePos;
246 /* no longer fetching, verify data version
247 * (avoid new GetDCache call) */
248 if (hsame(avc->m.DataVersion, tdc->f.versionNo)
249 && ((len = tdc->validPos - filePos) > 0)) {
250 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
252 /* don't have current data, so get it below */
253 afs_Trace3(afs_iclSetp, CM_TRACE_VERSIONNO,
254 ICL_TYPE_INT64, ICL_HANDLE_OFFSET(filePos),
255 ICL_TYPE_HYPER, &avc->m.DataVersion,
256 ICL_TYPE_HYPER, &tdc->f.versionNo);
257 ReleaseReadLock(&tdc->lock);
264 /* If we get, it was not possible to start the
265 * background daemon. With flag == 1 afs_GetDCache
266 * does the FetchData rpc synchronously.
268 ReleaseReadLock(&avc->lock);
269 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 1);
270 ObtainReadLock(&avc->lock);
272 ObtainReadLock(&tdc->lock);
276 afs_Trace3(afs_iclSetp, CM_TRACE_VNODEREAD, ICL_TYPE_POINTER, tdc,
277 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(offset),
278 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(len));
290 if (len > totalLength)
291 len = totalLength; /* will read len bytes */
292 if (len <= 0) { /* shouldn't get here if DFFetching is on */
293 /* read past the end of a chunk, may not be at next chunk yet, and yet
294 * also not at eof, so may have to supply fake zeros */
295 len = AFS_CHUNKTOSIZE(tdc->f.chunk) - offset; /* bytes left in chunk addr space */
296 if (len > totalLength)
297 len = totalLength; /* and still within xfr request */
298 tlen = avc->m.Length - offset; /* and still within file */
302 len = sizeof(afs_zeros); /* and in 0 buffer */
303 afsio_copy(auio, &tuio, tvec);
305 afsio_trim(&tuio, trimlen);
306 AFS_UIOMOVE(afs_zeros, trimlen, UIO_READ, &tuio, code);
312 /* get the data from the mem cache */
314 /* mung uio structure to be right for this transfer */
315 afsio_copy(auio, &tuio, tvec);
317 afsio_trim(&tuio, trimlen);
318 tuio.afsio_offset = offset;
320 code = afs_MemReadUIO(tdc->f.inode, &tuio);
327 /* otherwise we've read some, fixup length, etc and continue with next seg */
328 len = len - tuio.afsio_resid; /* compute amount really transferred */
330 afsio_skip(auio, trimlen); /* update input uio structure */
332 transferLength += len;
336 break; /* surprise eof */
337 } /* the whole while loop */
342 * tdc->lock(R) if tdc
345 /* if we make it here with tdc non-zero, then it is the last chunk we
346 * dealt with, and we have to release it when we're done. We hold on
347 * to it in case we need to do a prefetch.
350 ReleaseReadLock(&tdc->lock);
351 #if !defined(AFS_VM_RDWR_ENV)
352 /* try to queue prefetch, if needed */
354 afs_PrefetchChunk(avc, tdc, acred, &treq);
360 ReleaseReadLock(&avc->lock);
361 osi_FreeSmallSpace(tvec);
362 error = afs_CheckCode(error, &treq, 10);
366 /* called with the dcache entry triggering the fetch, the vcache entry involved,
367 * and a vrequest for the read call. Marks the dcache entry as having already
368 * triggered a prefetch, starts the prefetch going and sets the DFFetchReq
369 * flag in the prefetched block, so that the next call to read knows to wait
370 * for the daemon to start doing things.
372 * This function must be called with the vnode at least read-locked, and
373 * no locks on the dcache, because it plays around with dcache entries.
376 afs_PrefetchChunk(struct vcache *avc, struct dcache *adc,
377 struct AFS_UCRED *acred, struct vrequest *areq)
379 register struct dcache *tdc;
381 afs_size_t j1, j2; /* junk vbls for GetDCache to trash */
383 offset = adc->f.chunk + 1; /* next chunk we'll need */
384 offset = AFS_CHUNKTOBASE(offset); /* base of next chunk */
385 ObtainReadLock(&adc->lock);
386 ObtainSharedLock(&adc->mflock, 662);
387 if (offset < avc->m.Length && !(adc->mflags & DFNextStarted)
391 UpgradeSToWLock(&adc->mflock, 663);
392 adc->mflags |= DFNextStarted; /* we've tried to prefetch for this guy */
393 ReleaseWriteLock(&adc->mflock);
394 ReleaseReadLock(&adc->lock);
396 tdc = afs_GetDCache(avc, offset, areq, &j1, &j2, 2); /* type 2 never returns 0 */
397 ObtainSharedLock(&tdc->mflock, 651);
398 if (!(tdc->mflags & DFFetchReq)) {
399 /* ask the daemon to do the work */
400 UpgradeSToWLock(&tdc->mflock, 652);
401 tdc->mflags |= DFFetchReq; /* guaranteed to be cleared by BKG or GetDCache */
402 /* last parm (1) tells bkg daemon to do an afs_PutDCache when it is done,
403 * since we don't want to wait for it to finish before doing so ourselves.
405 bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
406 (afs_size_t) offset, (afs_size_t) 1, tdc);
408 /* Bkg table full; just abort non-important prefetching to avoid deadlocks */
409 tdc->mflags &= ~DFFetchReq;
410 ReleaseWriteLock(&tdc->mflock);
414 * DCLOCKXXX: This is a little sketchy, since someone else
415 * could have already started a prefetch.. In practice,
416 * this probably doesn't matter; at most it would cause an
417 * extra slot in the BKG table to be used up when someone
418 * prefetches this for the second time.
420 ObtainReadLock(&adc->lock);
421 ObtainWriteLock(&adc->mflock, 664);
422 adc->mflags &= ~DFNextStarted;
423 ReleaseWriteLock(&adc->mflock);
424 ReleaseReadLock(&adc->lock);
426 ReleaseWriteLock(&tdc->mflock);
429 ReleaseSharedLock(&tdc->mflock);
433 ReleaseSharedLock(&adc->mflock);
434 ReleaseReadLock(&adc->lock);
439 afs_UFSRead(register struct vcache *avc, struct uio *auio,
440 struct AFS_UCRED *acred, daddr_t albn, struct buf **abpp,
443 afs_size_t totalLength;
444 afs_size_t transferLength;
446 afs_size_t offset, len, tlen;
448 struct dcache *tdc = 0;
452 struct osi_file *tfile;
455 struct vrequest treq;
457 AFS_STATCNT(afs_UFSRead);
458 if (avc && avc->vc_error)
461 /* check that we have the latest status info in the vnode cache */
462 if ((code = afs_InitReq(&treq, acred)))
466 osi_Panic("null avc in afs_UFSRead");
468 code = afs_VerifyVCache(avc, &treq);
470 code = afs_CheckCode(code, &treq, 11); /* failed to get it */
475 #ifndef AFS_VM_RDWR_ENV
476 if (AFS_NFSXLATORREQ(acred)) {
478 (avc, PRSFS_READ, &treq,
479 CHECK_MODE_BITS | CMB_ALLOW_EXEC_AS_READ)) {
480 return afs_CheckCode(EACCES, &treq, 12);
485 tvec = (struct iovec *)osi_AllocSmallSpace(sizeof(struct iovec));
486 totalLength = auio->afsio_resid;
487 filePos = auio->afsio_offset;
488 afs_Trace4(afs_iclSetp, CM_TRACE_READ, ICL_TYPE_POINTER, avc,
489 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(filePos), ICL_TYPE_INT32,
490 totalLength, ICL_TYPE_OFFSET,
491 ICL_HANDLE_OFFSET(avc->m.Length));
495 ObtainReadLock(&avc->lock);
496 #if defined(AFS_TEXT_ENV) && !defined(AFS_VM_RDWR_ENV)
497 if (avc->flushDV.high == AFS_MAXDV && avc->flushDV.low == AFS_MAXDV) {
498 hset(avc->flushDV, avc->m.DataVersion);
502 while (totalLength > 0) {
503 /* read all of the cached info */
504 if (filePos >= avc->m.Length)
505 break; /* all done */
508 ReleaseReadLock(&tdc->lock);
511 tdc = afs_FindDCache(avc, filePos);
513 ObtainReadLock(&tdc->lock);
514 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
515 len = tdc->validPos - filePos;
518 /* a tricky question: does the presence of the DFFetching flag
519 * mean that we're fetching the latest version of the file? No.
520 * The server could update the file as soon as the fetch responsible
521 * for the setting of the DFFetching flag completes.
523 * However, the presence of the DFFetching flag (visible under
524 * a dcache read lock since it is set and cleared only under a
525 * dcache write lock) means that we're fetching as good a version
526 * as was known to this client at the time of the last call to
527 * afs_VerifyVCache, since the latter updates the stat cache's
528 * m.DataVersion field under a vcache write lock, and from the
529 * time that the DFFetching flag goes on in afs_GetDCache (before
530 * the fetch starts), to the time it goes off (after the fetch
531 * completes), afs_GetDCache keeps at least a read lock on the
534 * This means that if the DFFetching flag is set, we can use that
535 * data for any reads that must come from the current version of
536 * the file (current == m.DataVersion).
538 * Another way of looking at this same point is this: if we're
539 * fetching some data and then try do an afs_VerifyVCache, the
540 * VerifyVCache operation will not complete until after the
541 * DFFetching flag is turned off and the dcache entry's f.versionNo
544 * Note, by the way, that if DFFetching is set,
545 * m.DataVersion > f.versionNo (the latter is not updated until
546 * after the fetch completes).
549 ReleaseReadLock(&tdc->lock);
550 afs_PutDCache(tdc); /* before reusing tdc */
552 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 2);
553 ObtainReadLock(&tdc->lock);
554 /* now, first try to start transfer, if we'll need the data. If
555 * data already coming, we don't need to do this, obviously. Type
556 * 2 requests never return a null dcache entry, btw. */
557 if (!(tdc->dflags & DFFetching)
558 && !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
559 /* have cache entry, it is not coming in now, and we'll need new data */
561 if (trybusy && !afs_BBusy()) {
563 /* daemon is not busy */
564 ObtainSharedLock(&tdc->mflock, 667);
565 if (!(tdc->mflags & DFFetchReq)) {
566 UpgradeSToWLock(&tdc->mflock, 668);
567 tdc->mflags |= DFFetchReq;
568 bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
569 (afs_size_t) filePos, (afs_size_t) 0,
572 /* Bkg table full; retry deadlocks */
573 tdc->mflags &= ~DFFetchReq;
574 trybusy = 0; /* Avoid bkg daemon since they're too busy */
575 ReleaseWriteLock(&tdc->mflock);
578 ConvertWToSLock(&tdc->mflock);
581 ConvertSToRLock(&tdc->mflock);
582 while (!code && tdc->mflags & DFFetchReq) {
583 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT,
584 ICL_TYPE_STRING, __FILE__, ICL_TYPE_INT32,
585 __LINE__, ICL_TYPE_POINTER, tdc,
586 ICL_TYPE_INT32, tdc->dflags);
587 /* don't need waiting flag on this one */
588 ReleaseReadLock(&tdc->mflock);
589 ReleaseReadLock(&tdc->lock);
590 ReleaseReadLock(&avc->lock);
591 code = afs_osi_SleepSig(&tdc->validPos);
592 ObtainReadLock(&avc->lock);
593 ObtainReadLock(&tdc->lock);
594 ObtainReadLock(&tdc->mflock);
596 ReleaseReadLock(&tdc->mflock);
603 /* now data may have started flowing in (if DFFetching is on). If
604 * data is now streaming in, then wait for some interesting stuff.
607 while (!code && (tdc->dflags & DFFetching)
608 && tdc->validPos <= filePos) {
609 /* too early: wait for DFFetching flag to vanish,
610 * or data to appear */
611 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
612 __FILE__, ICL_TYPE_INT32, __LINE__,
613 ICL_TYPE_POINTER, tdc, ICL_TYPE_INT32,
615 ReleaseReadLock(&tdc->lock);
616 ReleaseReadLock(&avc->lock);
617 code = afs_osi_SleepSig(&tdc->validPos);
618 ObtainReadLock(&avc->lock);
619 ObtainReadLock(&tdc->lock);
625 /* fetching flag gone, data is here, or we never tried
626 * (BBusy for instance) */
627 if (tdc->dflags & DFFetching) {
628 /* still fetching, some new data is here:
629 * compute length and offset */
630 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
631 len = tdc->validPos - filePos;
633 /* no longer fetching, verify data version (avoid new
635 if (hsame(avc->m.DataVersion, tdc->f.versionNo)
636 && ((len = tdc->validPos - filePos) > 0)) {
637 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
639 /* don't have current data, so get it below */
640 afs_Trace3(afs_iclSetp, CM_TRACE_VERSIONNO,
641 ICL_TYPE_INT64, ICL_HANDLE_OFFSET(filePos),
642 ICL_TYPE_HYPER, &avc->m.DataVersion,
643 ICL_TYPE_HYPER, &tdc->f.versionNo);
644 ReleaseReadLock(&tdc->lock);
651 /* If we get, it was not possible to start the
652 * background daemon. With flag == 1 afs_GetDCache
653 * does the FetchData rpc synchronously.
655 ReleaseReadLock(&avc->lock);
656 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 1);
657 ObtainReadLock(&avc->lock);
659 ObtainReadLock(&tdc->lock);
667 len = tdc->validPos - filePos;
668 afs_Trace3(afs_iclSetp, CM_TRACE_VNODEREAD, ICL_TYPE_POINTER, tdc,
669 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(offset),
670 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(len));
671 if (len > totalLength)
672 len = totalLength; /* will read len bytes */
673 if (len <= 0) { /* shouldn't get here if DFFetching is on */
674 afs_Trace4(afs_iclSetp, CM_TRACE_VNODEREAD2, ICL_TYPE_POINTER,
675 tdc, ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(tdc->validPos),
676 ICL_TYPE_INT32, tdc->f.chunkBytes, ICL_TYPE_INT32,
678 /* read past the end of a chunk, may not be at next chunk yet, and yet
679 * also not at eof, so may have to supply fake zeros */
680 len = AFS_CHUNKTOSIZE(tdc->f.chunk) - offset; /* bytes left in chunk addr space */
681 if (len > totalLength)
682 len = totalLength; /* and still within xfr request */
683 tlen = avc->m.Length - offset; /* and still within file */
687 len = sizeof(afs_zeros); /* and in 0 buffer */
688 afsio_copy(auio, &tuio, tvec);
690 afsio_trim(&tuio, trimlen);
691 AFS_UIOMOVE(afs_zeros, trimlen, UIO_READ, &tuio, code);
697 /* get the data from the file */
699 if (tfile = tdc->ihint) {
700 if (tdc->f.inode != tfile->inum) {
701 afs_warn("afs_UFSRead: %x hint mismatch tdc %d inum %d\n",
702 tdc, tdc->f.inode, tfile->inum);
704 tdc->ihint = tfile = 0;
713 tfile = (struct osi_file *)osi_UFSOpen(tdc->f.inode);
714 /* mung uio structure to be right for this transfer */
715 afsio_copy(auio, &tuio, tvec);
717 afsio_trim(&tuio, trimlen);
718 tuio.afsio_offset = offset;
719 #if defined(AFS_AIX41_ENV)
722 VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, &tuio, NULL, NULL,
723 NULL, afs_osi_credp);
725 #elif defined(AFS_AIX32_ENV)
727 VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, &tuio, NULL, NULL);
728 /* Flush all JFS pages now for big performance gain in big file cases
729 * If we do something like this, must check to be sure that AFS file
730 * isn't mmapped... see afs_gn_map() for why.
733 if (tfile->vnode->v_gnode && tfile->vnode->v_gnode->gn_seg) {
734 many different ways to do similar things:
735 so far, the best performing one is #2, but #1 might match it if we
736 straighten out the confusion regarding which pages to flush. It
738 1. vm_flushp(tfile->vnode->v_gnode->gn_seg, 0, len/PAGESIZE - 1);
739 2. vm_releasep(tfile->vnode->v_gnode->gn_seg, offset/PAGESIZE,
740 (len + PAGESIZE-1)/PAGESIZE);
741 3. vms_inactive(tfile->vnode->v_gnode->gn_seg) Doesn't work correctly
742 4. vms_delete(tfile->vnode->v_gnode->gn_seg) probably also fails
743 tfile->vnode->v_gnode->gn_seg = NULL;
747 Unfortunately, this seems to cause frequent "cache corruption" episodes.
748 vm_releasep(tfile->vnode->v_gnode->gn_seg, offset/PAGESIZE,
749 (len + PAGESIZE-1)/PAGESIZE);
752 #elif defined(AFS_AIX_ENV)
754 VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, (off_t) & offset,
755 &tuio, NULL, NULL, -1);
756 #elif defined(AFS_SUN5_ENV)
758 VOP_RWLOCK(tfile->vnode, 0);
759 code = VOP_READ(tfile->vnode, &tuio, 0, afs_osi_credp);
760 VOP_RWUNLOCK(tfile->vnode, 0);
762 #elif defined(AFS_SGI_ENV)
764 AFS_VOP_RWLOCK(tfile->vnode, VRWLOCK_READ);
765 AFS_VOP_READ(tfile->vnode, &tuio, IO_ISLOCKED, afs_osi_credp,
767 AFS_VOP_RWUNLOCK(tfile->vnode, VRWLOCK_READ);
769 #elif defined(AFS_OSF_ENV)
770 tuio.uio_rw = UIO_READ;
772 VOP_READ(tfile->vnode, &tuio, 0, afs_osi_credp, code);
774 #elif defined(AFS_SUN_ENV)
775 code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, afs_osi_credp);
776 #elif defined(AFS_HPUX100_ENV)
778 code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, afs_osi_credp);
780 #elif defined(AFS_LINUX20_ENV)
782 code = osi_file_uio_rdwr(tfile, &tuio, UIO_READ);
784 #elif defined(AFS_DARWIN_ENV)
786 VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, current_proc());
787 code = VOP_READ(tfile->vnode, &tuio, 0, afs_osi_credp);
788 VOP_UNLOCK(tfile->vnode, 0, current_proc());
790 #elif defined(AFS_FBSD50_ENV)
792 VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, curthread);
793 code = VOP_READ(tfile->vnode, &tuio, 0, afs_osi_credp);
794 VOP_UNLOCK(tfile->vnode, 0, curthread);
796 #elif defined(AFS_XBSD_ENV)
798 VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, curproc);
799 code = VOP_READ(tfile->vnode, &tuio, 0, afs_osi_credp);
800 VOP_UNLOCK(tfile->vnode, 0, curproc);
803 code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, afs_osi_credp);
807 if (!tdc->ihint && nihints < maxIHint) {
819 /* otherwise we've read some, fixup length, etc and continue with next seg */
820 len = len - tuio.afsio_resid; /* compute amount really transferred */
822 afsio_skip(auio, trimlen); /* update input uio structure */
824 transferLength += len;
827 break; /* surprise eof */
830 /* if we make it here with tdc non-zero, then it is the last chunk we
831 * dealt with, and we have to release it when we're done. We hold on
832 * to it in case we need to do a prefetch, obviously.
835 ReleaseReadLock(&tdc->lock);
836 #if !defined(AFS_VM_RDWR_ENV)
837 /* try to queue prefetch, if needed */
839 if (!(tdc->mflags & DFNextStarted))
840 afs_PrefetchChunk(avc, tdc, acred, &treq);
846 ReleaseReadLock(&avc->lock);
848 osi_FreeSmallSpace(tvec);
849 error = afs_CheckCode(error, &treq, 13);