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"
23 #include "afs/sysincludes.h" /* Standard vendor system headers */
24 #include "afsincludes.h" /* Afs-based standard headers */
25 #include "afs/afs_stats.h" /* statistics */
26 #include "afs/afs_cbqueue.h"
27 #include "afs/nfsclient.h"
28 #include "afs/afs_osidnlc.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 struct AFS_UCRED *acred, struct vrequest *areq);
49 int afs_MemRead(register struct vcache *avc, struct uio *auio, struct AFS_UCRED *acred,
50 daddr_t albn, struct buf **abpp, int noLock)
52 afs_size_t totalLength;
53 afs_size_t transferLength;
55 afs_size_t offset, len, tlen;
58 afs_int32 error, trybusy=1;
64 AFS_STATCNT(afs_MemRead);
68 /* check that we have the latest status info in the vnode cache */
69 if ((code = afs_InitReq(&treq, acred))) return code;
71 code = afs_VerifyVCache(avc, &treq);
73 code = afs_CheckCode(code, &treq, 8); /* failed to get it */
78 #ifndef AFS_VM_RDWR_ENV
79 if (AFS_NFSXLATORREQ(acred)) {
80 if (!afs_AccessOK(avc, PRSFS_READ, &treq,
81 CHECK_MODE_BITS|CMB_ALLOW_EXEC_AS_READ)) {
82 return afs_CheckCode(EACCES, &treq, 9);
87 tvec = (struct iovec *) osi_AllocSmallSpace(sizeof(struct iovec));
88 totalLength = auio->afsio_resid;
89 filePos = auio->afsio_offset;
90 afs_Trace4(afs_iclSetp, CM_TRACE_READ, ICL_TYPE_POINTER, avc,
91 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(filePos),
92 ICL_TYPE_INT32, totalLength,
93 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length));
97 ObtainReadLock(&avc->lock);
98 #if defined(AFS_TEXT_ENV) && !defined(AFS_VM_RDWR_ENV)
99 if (avc->flushDV.high == AFS_MAXDV && avc->flushDV.low == AFS_MAXDV) {
100 hset(avc->flushDV, avc->m.DataVersion);
108 while (totalLength > 0) {
109 /* read all of the cached info */
110 if (filePos >= avc->m.Length) break; /* all done */
113 ReleaseReadLock(&tdc->lock);
116 tdc = afs_FindDCache(avc, filePos);
118 ObtainReadLock(&tdc->lock);
119 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
120 len = tdc->f.chunkBytes - offset;
123 /* a tricky question: does the presence of the DFFetching flag
124 mean that we're fetching the latest version of the file? No.
125 The server could update the file as soon as the fetch responsible
126 for the setting of the DFFetching flag completes.
128 However, the presence of the DFFetching flag (visible under
129 a dcache read lock since it is set and cleared only under a
130 dcache write lock) means that we're fetching as good a version
131 as was known to this client at the time of the last call to
132 afs_VerifyVCache, since the latter updates the stat cache's
133 m.DataVersion field under a vcache write lock, and from the
134 time that the DFFetching flag goes on in afs_GetDCache (before
135 the fetch starts), to the time it goes off (after the fetch
136 completes), afs_GetDCache keeps at least a read lock on the
139 This means that if the DFFetching flag is set, we can use that
140 data for any reads that must come from the current version of
141 the file (current == m.DataVersion).
143 Another way of looking at this same point is this: if we're
144 fetching some data and then try do an afs_VerifyVCache, the
145 VerifyVCache operation will not complete until after the
146 DFFetching flag is turned off and the dcache entry's f.versionNo
149 Note, by the way, that if DFFetching is set,
150 m.DataVersion > f.versionNo (the latter is not updated until
151 after the fetch completes).
154 ReleaseReadLock(&tdc->lock);
155 afs_PutDCache(tdc); /* before reusing tdc */
157 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 2);
158 ObtainReadLock(&tdc->lock);
159 /* now, first try to start transfer, if we'll need the data. If
160 * data already coming, we don't need to do this, obviously. Type
161 * 2 requests never return a null dcache entry, btw.
163 if (!(tdc->dflags & DFFetching)
164 && !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
165 /* have cache entry, it is not coming in now,
166 * and we'll need new data */
168 if (trybusy && !afs_BBusy()) {
170 /* daemon is not busy */
171 ObtainSharedLock(&tdc->mflock, 665);
172 if (!(tdc->mflags & DFFetchReq)) {
173 /* start the daemon (may already be running, however) */
174 UpgradeSToWLock(&tdc->mflock, 666);
175 tdc->mflags |= DFFetchReq;
176 bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
177 (afs_size_t)filePos, (afs_size_t) 0,
180 tdc->mflags &= ~DFFetchReq;
181 trybusy = 0; /* Avoid bkg daemon since they're too busy */
182 ReleaseWriteLock(&tdc->mflock);
185 ConvertWToSLock(&tdc->mflock);
186 /* don't use bp pointer! */
189 ConvertSToRLock(&tdc->mflock);
190 while (!code && tdc->mflags & DFFetchReq) {
191 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT,
192 ICL_TYPE_STRING, __FILE__,
193 ICL_TYPE_INT32, __LINE__,
194 ICL_TYPE_POINTER, tdc,
195 ICL_TYPE_INT32, tdc->dflags);
196 /* don't need waiting flag on this one */
197 ReleaseReadLock(&tdc->mflock);
198 ReleaseReadLock(&tdc->lock);
199 ReleaseReadLock(&avc->lock);
200 code = afs_osi_SleepSig(&tdc->validPos);
201 ObtainReadLock(&avc->lock);
202 ObtainReadLock(&tdc->lock);
203 ObtainReadLock(&tdc->mflock);
205 ReleaseReadLock(&tdc->mflock);
212 /* now data may have started flowing in (if DFFetching is on). If
213 * data is now streaming in, then wait for some interesting stuff.
216 while (!code && (tdc->dflags & DFFetching) &&
217 tdc->validPos <= filePos) {
218 /* too early: wait for DFFetching flag to vanish,
219 * or data to appear */
220 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT,
221 ICL_TYPE_STRING, __FILE__,
222 ICL_TYPE_INT32, __LINE__,
223 ICL_TYPE_POINTER, tdc,
224 ICL_TYPE_INT32, tdc->dflags);
225 ReleaseReadLock(&tdc->lock);
226 ReleaseReadLock(&avc->lock);
227 code = afs_osi_SleepSig(&tdc->validPos);
228 ObtainReadLock(&avc->lock);
229 ObtainReadLock(&tdc->lock);
235 /* fetching flag gone, data is here, or we never tried
236 * (BBusy for instance) */
237 if (tdc->dflags & DFFetching) {
238 /* still fetching, some new data is here:
239 * compute length and offset */
240 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
241 len = tdc->validPos - filePos;
244 /* no longer fetching, verify data version
245 * (avoid new GetDCache call) */
246 if (hsame(avc->m.DataVersion, tdc->f.versionNo)
247 && ((len = tdc->validPos - filePos) > 0)) {
248 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
251 /* don't have current data, so get it below */
252 afs_Trace3(afs_iclSetp, CM_TRACE_VERSIONNO,
253 ICL_TYPE_INT64, ICL_HANDLE_OFFSET(filePos),
254 ICL_TYPE_HYPER, &avc->m.DataVersion,
255 ICL_TYPE_HYPER, &tdc->f.versionNo);
256 ReleaseReadLock(&tdc->lock);
263 /* If we get, it was not possible to start the
264 * background daemon. With flag == 1 afs_GetDCache
265 * does the FetchData rpc synchronously.
267 ReleaseReadLock(&avc->lock);
268 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 1);
269 ObtainReadLock(&avc->lock);
270 if (tdc) ObtainReadLock(&tdc->lock);
274 afs_Trace3(afs_iclSetp, CM_TRACE_VNODEREAD,
275 ICL_TYPE_POINTER, tdc,
276 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(offset),
277 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(len));
289 if (len > totalLength) len = totalLength; /* will read len bytes */
290 if (len <= 0) { /* shouldn't get here if DFFetching is on */
291 /* read past the end of a chunk, may not be at next chunk yet, and yet
292 also not at eof, so may have to supply fake zeros */
293 len = AFS_CHUNKTOSIZE(tdc->f.chunk) - offset; /* bytes left in chunk addr space */
294 if (len > totalLength) len = totalLength; /* and still within xfr request */
295 tlen = avc->m.Length - offset; /* and still within file */
296 if (len > tlen) len = tlen;
297 if (len > AFS_ZEROS) len = sizeof(afs_zeros); /* and in 0 buffer */
298 afsio_copy(auio, &tuio, tvec);
300 afsio_trim(&tuio, trimlen);
301 AFS_UIOMOVE(afs_zeros, trimlen, UIO_READ, &tuio, code);
308 /* get the data from the mem cache */
310 /* mung uio structure to be right for this transfer */
311 afsio_copy(auio, &tuio, tvec);
313 afsio_trim(&tuio, trimlen);
314 tuio.afsio_offset = offset;
316 code = afs_MemReadUIO(tdc->f.inode, &tuio);
323 /* otherwise we've read some, fixup length, etc and continue with next seg */
324 len = len - tuio.afsio_resid; /* compute amount really transferred */
326 afsio_skip(auio, trimlen); /* update input uio structure */
328 transferLength += len;
331 if (len <= 0) break; /* surprise eof */
332 } /* the whole while loop */
337 * tdc->lock(R) if tdc
340 /* if we make it here with tdc non-zero, then it is the last chunk we
341 * dealt with, and we have to release it when we're done. We hold on
342 * to it in case we need to do a prefetch.
345 ReleaseReadLock(&tdc->lock);
346 #if !defined(AFS_VM_RDWR_ENV)
347 /* try to queue prefetch, if needed */
349 afs_PrefetchChunk(avc, tdc, acred, &treq);
355 ReleaseReadLock(&avc->lock);
356 osi_FreeSmallSpace(tvec);
357 error = afs_CheckCode(error, &treq, 10);
361 /* called with the dcache entry triggering the fetch, the vcache entry involved,
362 * and a vrequest for the read call. Marks the dcache entry as having already
363 * triggered a prefetch, starts the prefetch going and sets the DFFetchReq
364 * flag in the prefetched block, so that the next call to read knows to wait
365 * for the daemon to start doing things.
367 * This function must be called with the vnode at least read-locked, and
368 * no locks on the dcache, because it plays around with dcache entries.
370 void afs_PrefetchChunk(struct vcache *avc, struct dcache *adc,
371 struct AFS_UCRED *acred, struct vrequest *areq)
373 register struct dcache *tdc;
375 afs_size_t j1, j2; /* junk vbls for GetDCache to trash */
377 offset = adc->f.chunk+1; /* next chunk we'll need */
378 offset = AFS_CHUNKTOBASE(offset); /* base of next chunk */
379 ObtainReadLock(&adc->lock);
380 ObtainSharedLock(&adc->mflock, 662);
381 if (offset < avc->m.Length && !(adc->mflags & DFNextStarted) && !afs_BBusy()) {
384 UpgradeSToWLock(&adc->mflock, 663);
385 adc->mflags |= DFNextStarted; /* we've tried to prefetch for this guy */
386 ReleaseWriteLock(&adc->mflock);
387 ReleaseReadLock(&adc->lock);
389 tdc = afs_GetDCache(avc, offset, areq, &j1, &j2, 2); /* type 2 never returns 0 */
390 ObtainSharedLock(&tdc->mflock, 651);
391 if (!(tdc->mflags & DFFetchReq)) {
392 /* ask the daemon to do the work */
393 UpgradeSToWLock(&tdc->mflock, 652);
394 tdc->mflags |= DFFetchReq; /* guaranteed to be cleared by BKG or GetDCache */
395 /* last parm (1) tells bkg daemon to do an afs_PutDCache when it is done,
396 * since we don't want to wait for it to finish before doing so ourselves.
398 bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
399 (afs_size_t) offset, (afs_size_t) 1, tdc);
401 /* Bkg table full; just abort non-important prefetching to avoid deadlocks */
402 tdc->mflags &= ~DFFetchReq;
403 ReleaseWriteLock(&tdc->mflock);
407 * DCLOCKXXX: This is a little sketchy, since someone else
408 * could have already started a prefetch.. In practice,
409 * this probably doesn't matter; at most it would cause an
410 * extra slot in the BKG table to be used up when someone
411 * prefetches this for the second time.
413 ObtainReadLock(&adc->lock);
414 ObtainWriteLock(&adc->mflock, 664);
415 adc->mflags &= ~DFNextStarted;
416 ReleaseWriteLock(&adc->mflock);
417 ReleaseReadLock(&adc->lock);
419 ReleaseWriteLock(&tdc->mflock);
422 ReleaseSharedLock(&tdc->mflock);
426 ReleaseSharedLock(&adc->mflock);
427 ReleaseReadLock(&adc->lock);
431 int afs_UFSRead(register struct vcache *avc, struct uio *auio,
432 struct AFS_UCRED *acred, daddr_t albn, struct buf **abpp, int noLock)
434 afs_size_t totalLength;
435 afs_size_t transferLength;
437 afs_size_t offset, len, tlen;
439 struct dcache *tdc=0;
443 struct osi_file *tfile;
446 struct vrequest treq;
448 AFS_STATCNT(afs_UFSRead);
449 if (avc && avc->vc_error)
452 /* check that we have the latest status info in the vnode cache */
453 if ((code = afs_InitReq(&treq, acred))) return code;
456 osi_Panic ("null avc in afs_UFSRead");
458 code = afs_VerifyVCache(avc, &treq);
460 code = afs_CheckCode(code, &treq, 11); /* failed to get it */
466 #ifndef AFS_VM_RDWR_ENV
467 if (AFS_NFSXLATORREQ(acred)) {
468 if (!afs_AccessOK(avc, PRSFS_READ, &treq,
469 CHECK_MODE_BITS|CMB_ALLOW_EXEC_AS_READ)) {
470 return afs_CheckCode(EACCES, &treq, 12);
475 tvec = (struct iovec *) osi_AllocSmallSpace(sizeof(struct iovec));
476 totalLength = auio->afsio_resid;
477 filePos = auio->afsio_offset;
478 afs_Trace4(afs_iclSetp, CM_TRACE_READ, ICL_TYPE_POINTER, avc,
479 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(filePos),
480 ICL_TYPE_INT32, totalLength,
481 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length));
485 ObtainReadLock(&avc->lock);
486 #if defined(AFS_TEXT_ENV) && !defined(AFS_VM_RDWR_ENV)
487 if (avc->flushDV.high == AFS_MAXDV && avc->flushDV.low == AFS_MAXDV) {
488 hset(avc->flushDV, avc->m.DataVersion);
492 while (totalLength > 0) {
493 /* read all of the cached info */
494 if (filePos >= avc->m.Length) break; /* all done */
497 ReleaseReadLock(&tdc->lock);
500 tdc = afs_FindDCache(avc, filePos);
502 ObtainReadLock(&tdc->lock);
503 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
504 len = tdc->validPos - filePos;
507 /* a tricky question: does the presence of the DFFetching flag
508 mean that we're fetching the latest version of the file? No.
509 The server could update the file as soon as the fetch responsible
510 for the setting of the DFFetching flag completes.
512 However, the presence of the DFFetching flag (visible under
513 a dcache read lock since it is set and cleared only under a
514 dcache write lock) means that we're fetching as good a version
515 as was known to this client at the time of the last call to
516 afs_VerifyVCache, since the latter updates the stat cache's
517 m.DataVersion field under a vcache write lock, and from the
518 time that the DFFetching flag goes on in afs_GetDCache (before
519 the fetch starts), to the time it goes off (after the fetch
520 completes), afs_GetDCache keeps at least a read lock on the
523 This means that if the DFFetching flag is set, we can use that
524 data for any reads that must come from the current version of
525 the file (current == m.DataVersion).
527 Another way of looking at this same point is this: if we're
528 fetching some data and then try do an afs_VerifyVCache, the
529 VerifyVCache operation will not complete until after the
530 DFFetching flag is turned off and the dcache entry's f.versionNo
533 Note, by the way, that if DFFetching is set,
534 m.DataVersion > f.versionNo (the latter is not updated until
535 after the fetch completes).
538 ReleaseReadLock(&tdc->lock);
539 afs_PutDCache(tdc); /* before reusing tdc */
541 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 2);
542 ObtainReadLock(&tdc->lock);
543 /* now, first try to start transfer, if we'll need the data. If
544 * data already coming, we don't need to do this, obviously. Type
545 * 2 requests never return a null dcache entry, btw. */
546 if (!(tdc->dflags & DFFetching)
547 && !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
548 /* have cache entry, it is not coming in now, and we'll need new data */
550 if (trybusy && !afs_BBusy()) {
552 /* daemon is not busy */
553 ObtainSharedLock(&tdc->mflock, 667);
554 if (!(tdc->mflags & DFFetchReq)) {
555 UpgradeSToWLock(&tdc->mflock, 668);
556 tdc->mflags |= DFFetchReq;
557 bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
558 (afs_size_t) filePos, (afs_size_t) 0,
561 /* Bkg table full; retry deadlocks */
562 tdc->mflags &= ~DFFetchReq;
563 trybusy = 0; /* Avoid bkg daemon since they're too busy */
564 ReleaseWriteLock(&tdc->mflock);
567 ConvertWToSLock(&tdc->mflock);
570 ConvertSToRLock(&tdc->mflock);
571 while (!code && tdc->mflags & DFFetchReq) {
572 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT,
573 ICL_TYPE_STRING, __FILE__,
574 ICL_TYPE_INT32, __LINE__,
575 ICL_TYPE_POINTER, tdc,
576 ICL_TYPE_INT32, tdc->dflags);
577 /* don't need waiting flag on this one */
578 ReleaseReadLock(&tdc->mflock);
579 ReleaseReadLock(&tdc->lock);
580 ReleaseReadLock(&avc->lock);
581 code = afs_osi_SleepSig(&tdc->validPos);
582 ObtainReadLock(&avc->lock);
583 ObtainReadLock(&tdc->lock);
584 ObtainReadLock(&tdc->mflock);
586 ReleaseReadLock(&tdc->mflock);
593 /* now data may have started flowing in (if DFFetching is on). If
594 * data is now streaming in, then wait for some interesting stuff.
597 while (!code && (tdc->dflags & DFFetching) &&
598 tdc->validPos <= filePos) {
599 /* too early: wait for DFFetching flag to vanish,
600 * or data to appear */
601 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT,
602 ICL_TYPE_STRING, __FILE__,
603 ICL_TYPE_INT32, __LINE__,
604 ICL_TYPE_POINTER, tdc,
605 ICL_TYPE_INT32, tdc->dflags);
606 ReleaseReadLock(&tdc->lock);
607 ReleaseReadLock(&avc->lock);
608 code = afs_osi_SleepSig(&tdc->validPos);
609 ObtainReadLock(&avc->lock);
610 ObtainReadLock(&tdc->lock);
616 /* fetching flag gone, data is here, or we never tried
617 * (BBusy for instance) */
618 if (tdc->dflags & DFFetching) {
619 /* still fetching, some new data is here:
620 * compute length and offset */
621 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
622 len = tdc->validPos - filePos;
625 /* no longer fetching, verify data version (avoid new
627 if (hsame(avc->m.DataVersion, tdc->f.versionNo)
628 && ((len = tdc->validPos - filePos) > 0)) {
629 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
632 /* don't have current data, so get it below */
633 afs_Trace3(afs_iclSetp, CM_TRACE_VERSIONNO,
634 ICL_TYPE_INT64, ICL_HANDLE_OFFSET(filePos),
635 ICL_TYPE_HYPER, &avc->m.DataVersion,
636 ICL_TYPE_HYPER, &tdc->f.versionNo);
637 ReleaseReadLock(&tdc->lock);
644 /* If we get, it was not possible to start the
645 * background daemon. With flag == 1 afs_GetDCache
646 * does the FetchData rpc synchronously.
648 ReleaseReadLock(&avc->lock);
649 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 1);
650 ObtainReadLock(&avc->lock);
651 if (tdc) ObtainReadLock(&tdc->lock);
659 len = tdc->validPos - filePos;
660 afs_Trace3(afs_iclSetp, CM_TRACE_VNODEREAD,
661 ICL_TYPE_POINTER, tdc,
662 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(offset),
663 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(len));
664 if (len > totalLength) len = totalLength; /* will read len bytes */
665 if (len <= 0) { /* shouldn't get here if DFFetching is on */
666 afs_Trace4(afs_iclSetp, CM_TRACE_VNODEREAD2,
667 ICL_TYPE_POINTER, tdc,
668 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(tdc->validPos),
669 ICL_TYPE_INT32, tdc->f.chunkBytes,
670 ICL_TYPE_INT32, tdc->dflags);
671 /* read past the end of a chunk, may not be at next chunk yet, and yet
672 also not at eof, so may have to supply fake zeros */
673 len = AFS_CHUNKTOSIZE(tdc->f.chunk) - offset; /* bytes left in chunk addr space */
674 if (len > totalLength) len = totalLength; /* and still within xfr request */
675 tlen = avc->m.Length - offset; /* and still within file */
676 if (len > tlen) len = tlen;
677 if (len > AFS_ZEROS) len = sizeof(afs_zeros); /* and in 0 buffer */
678 afsio_copy(auio, &tuio, tvec);
680 afsio_trim(&tuio, trimlen);
681 AFS_UIOMOVE(afs_zeros, trimlen, UIO_READ, &tuio, code);
688 /* get the data from the file */
690 if (tfile = tdc->ihint) {
691 if (tdc->f.inode != tfile->inum){
692 afs_warn( "afs_UFSRead: %x hint mismatch tdc %d inum %d\n",
693 tdc, tdc->f.inode, tfile->inum );
695 tdc->ihint = tfile = 0;
705 tfile = (struct osi_file *)osi_UFSOpen(tdc->f.inode);
706 /* mung uio structure to be right for this transfer */
707 afsio_copy(auio, &tuio, tvec);
709 afsio_trim(&tuio, trimlen);
710 tuio.afsio_offset = offset;
714 code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, &tuio, NULL, NULL,
715 NULL, &afs_osi_cred);
719 code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, &tuio, NULL, NULL);
720 /* Flush all JFS pages now for big performance gain in big file cases
721 * If we do something like this, must check to be sure that AFS file
722 * isn't mmapped... see afs_gn_map() for why.
725 if (tfile->vnode->v_gnode && tfile->vnode->v_gnode->gn_seg) {
726 many different ways to do similar things:
727 so far, the best performing one is #2, but #1 might match it if we
728 straighten out the confusion regarding which pages to flush. It
730 1. vm_flushp(tfile->vnode->v_gnode->gn_seg, 0, len/PAGESIZE - 1);
731 2. vm_releasep(tfile->vnode->v_gnode->gn_seg, offset/PAGESIZE,
732 (len + PAGESIZE-1)/PAGESIZE);
733 3. vms_inactive(tfile->vnode->v_gnode->gn_seg) Doesn't work correctly
734 4. vms_delete(tfile->vnode->v_gnode->gn_seg) probably also fails
735 tfile->vnode->v_gnode->gn_seg = NULL;
739 Unfortunately, this seems to cause frequent "cache corruption" episodes.
740 vm_releasep(tfile->vnode->v_gnode->gn_seg, offset/PAGESIZE,
741 (len + PAGESIZE-1)/PAGESIZE);
745 code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, (off_t)&offset, &tuio, NULL, NULL, -1);
751 VOP_RWLOCK(tfile->vnode, 0);
752 code = VOP_READ(tfile->vnode, &tuio, 0, &afs_osi_cred);
753 VOP_RWUNLOCK(tfile->vnode, 0);
756 #if defined(AFS_SGI_ENV)
758 AFS_VOP_RWLOCK(tfile->vnode, VRWLOCK_READ);
759 AFS_VOP_READ(tfile->vnode, &tuio, IO_ISLOCKED, &afs_osi_cred,
761 AFS_VOP_RWUNLOCK(tfile->vnode, VRWLOCK_READ);
765 tuio.uio_rw = UIO_READ;
767 VOP_READ(tfile->vnode, &tuio, 0, &afs_osi_cred, code);
769 #else /* AFS_OSF_ENV */
771 code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, &afs_osi_cred);
773 #if defined(AFS_HPUX100_ENV)
775 code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, &afs_osi_cred);
778 #if defined(AFS_LINUX20_ENV)
780 code = osi_file_uio_rdwr(tfile, &tuio, UIO_READ);
783 #if defined(AFS_DARWIN_ENV)
785 VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, current_proc());
786 code = VOP_READ(tfile->vnode, &tuio, 0, &afs_osi_cred);
787 VOP_UNLOCK(tfile->vnode, 0, current_proc());
790 #if defined(AFS_XBSD_ENV)
792 VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, curproc);
793 code = VOP_READ(tfile->vnode, &tuio, 0, &afs_osi_cred);
794 VOP_UNLOCK(tfile->vnode, 0, curproc);
797 code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, &afs_osi_cred);
809 if (!tdc->ihint && nihints < maxIHint) {
822 /* otherwise we've read some, fixup length, etc and continue with next seg */
823 len = len - tuio.afsio_resid; /* compute amount really transferred */
825 afsio_skip(auio, trimlen); /* update input uio structure */
827 transferLength += len;
829 if (len <= 0) break; /* surprise eof */
832 /* if we make it here with tdc non-zero, then it is the last chunk we
833 * dealt with, and we have to release it when we're done. We hold on
834 * to it in case we need to do a prefetch, obviously.
837 ReleaseReadLock(&tdc->lock);
838 #if !defined(AFS_VM_RDWR_ENV)
839 /* try to queue prefetch, if needed */
841 if (!(tdc->mflags & DFNextStarted))
842 afs_PrefetchChunk(avc, tdc, acred, &treq);
848 ReleaseReadLock(&avc->lock);
850 osi_FreeSmallSpace(tvec);
851 error = afs_CheckCode(error, &treq, 13);