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
19 #include "../afs/param.h" /* Should be always first */
20 #include <afsconfig.h>
24 #include "../afs/sysincludes.h" /* Standard vendor system headers */
25 #include "../afs/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);
50 afs_MemRead(avc, auio, acred, albn, abpp, noLock)
51 register struct vcache *avc;
53 struct AFS_UCRED *acred;
57 afs_int32 totalLength;
58 afs_int32 transferLength;
61 afs_int32 offset, len, error, trybusy=1;
68 AFS_STATCNT(afs_MemRead);
72 /* check that we have the latest status info in the vnode cache */
73 if (code = afs_InitReq(&treq, acred)) return code;
75 code = afs_VerifyVCache(avc, &treq);
77 code = afs_CheckCode(code, &treq, 8); /* failed to get it */
82 #ifndef AFS_VM_RDWR_ENV
83 if (AFS_NFSXLATORREQ(acred)) {
84 if (!afs_AccessOK(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_INT32, filePos, ICL_TYPE_INT32, totalLength,
96 ICL_TYPE_INT32, avc->m.Length);
100 ObtainReadLock(&avc->lock);
101 #if defined(AFS_TEXT_ENV) && !defined(AFS_VM_RDWR_ENV)
102 if (avc->flushDV.high == AFS_MAXDV && avc->flushDV.low == AFS_MAXDV) {
103 hset(avc->flushDV, avc->m.DataVersion);
106 while (totalLength > 0) {
107 /* read all of the cached info */
108 if (filePos >= avc->m.Length) break; /* all done */
110 if (tdc) afs_PutDCache(tdc);
111 tdc = afs_FindDCache(avc, filePos);
113 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
114 len = tdc->f.chunkBytes - offset;
117 /* a tricky question: does the presence of the DFFetching flag
118 mean that we're fetching the latest version of the file? No.
119 The server could update the file as soon as the fetch responsible
120 for the setting of the DFFetching flag completes.
122 However, the presence of the DFFetching flag (visible under a
123 read lock since it is set and cleared only under a write lock)
124 means that we're fetching as good a version as was known to this
125 client at the time of the last call to afs_VerifyVCache, since
126 the latter updates the stat cache's m.DataVersion field under a
127 write lock, and from the time that the DFFetching flag goes on
128 (before the fetch starts), to the time it goes off (after the
129 fetch completes), afs_GetDCache keeps at least a read lock
130 (actually it keeps an S lock) on the cache entry.
132 This means that if the DFFetching flag is set, we can use that
133 data for any reads that must come from the current version of
134 the file (current == m.DataVersion).
136 Another way of looking at this same point is this: if we're
137 fetching some data and then try do an afs_VerifyVCache, the
138 VerifyVCache operation will not complete until after the
139 DFFetching flag is turned off and the dcache entry's f.versionNo
142 Note, by the way, that if DFFetching is set,
143 m.DataVersion > f.versionNo (the latter is not updated until
144 after the fetch completes).
146 if (tdc) afs_PutDCache(tdc); /* before reusing tdc */
147 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 2);
148 /* now, first try to start transfer, if we'll need the data. If
149 * data already coming, we don't need to do this, obviously. Type
150 * 2 requests never return a null dcache entry, btw.
152 if (!(tdc->flags & DFFetching)
153 && !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
154 /* have cache entry, it is not coming in now,
155 * and we'll need new data */
157 if (trybusy && !afs_BBusy()) {
159 /* daemon is not busy */
160 if (!(tdc->flags & DFFetchReq)) {
161 /* start the daemon (may already be running, however) */
162 tdc->flags |= DFFetchReq;
163 bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
164 (long)filePos, (long) tdc, 0L, 0L);
166 tdc->flags &= ~DFFetchReq;
167 trybusy = 0; /* Avoid bkg daemon since they're too busy */
170 /* don't use bp pointer! */
172 while (tdc->flags & DFFetchReq) {
173 /* don't need waiting flag on this one */
174 ReleaseReadLock(&avc->lock);
175 afs_osi_Sleep(&tdc->validPos);
176 ObtainReadLock(&avc->lock);
180 /* now data may have started flowing in (if DFFetching is on). If
181 * data is now streaming in, then wait for some interesting stuff. */
182 while ((tdc->flags & DFFetching) && tdc->validPos <= filePos) {
183 /* too early: wait for DFFetching flag to vanish, or data to appear */
184 tdc->flags |= DFWaiting;
185 ReleaseReadLock(&avc->lock);
186 afs_osi_Sleep(&tdc->validPos);
187 ObtainReadLock(&avc->lock);
189 /* fetching flag gone, data is here, or we never tried (BBusy for instance) */
190 if (tdc->flags & DFFetching) {
191 /* still fetching, some new data is here: compute length and offset */
192 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
193 len = tdc->validPos - filePos;
196 /* no longer fetching, verify data version (avoid new GetDCache call) */
197 if (hsame(avc->m.DataVersion, tdc->f.versionNo)) {
198 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
199 len = tdc->f.chunkBytes - offset;
202 /* don't have current data, so get it below */
204 tdc = (struct dcache *) 0;
209 ReleaseReadLock(&avc->lock);
210 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 1);
211 ObtainReadLock(&avc->lock);
219 if (len > totalLength) len = totalLength; /* will read len bytes */
220 if (len <= 0) { /* shouldn't get here if DFFetching is on */
221 /* read past the end of a chunk, may not be at next chunk yet, and yet
222 also not at eof, so may have to supply fake zeros */
223 len = AFS_CHUNKTOSIZE(tdc->f.chunk) - offset; /* bytes left in chunk addr space */
224 if (len > totalLength) len = totalLength; /* and still within xfr request */
225 code = avc->m.Length - offset; /* and still within file */
226 if (len > code) len = code;
227 if (len > AFS_ZEROS) len = sizeof(afs_zeros); /* and in 0 buffer */
228 afsio_copy(auio, &tuio, tvec);
229 afsio_trim(&tuio, len);
230 AFS_UIOMOVE(afs_zeros, len, UIO_READ, &tuio, code);
237 /* get the data from the mem cache */
239 /* mung uio structure to be right for this transfer */
240 afsio_copy(auio, &tuio, tvec);
241 afsio_trim(&tuio, len);
242 tuio.afsio_offset = offset;
244 code = afs_MemReadUIO(tdc->f.inode, &tuio);
251 /* otherwise we've read some, fixup length, etc and continue with next seg */
252 len = len - tuio.afsio_resid; /* compute amount really transferred */
253 afsio_skip(auio, len); /* update input uio structure */
255 transferLength += len;
258 if (len <= 0) break; /* surprise eof */
259 } /* the whole while loop */
261 /* if we make it here with tdc non-zero, then it is the last chunk we
262 * dealt with, and we have to release it when we're done. We hold on
263 * to it in case we need to do a prefetch.
266 #ifndef AFS_VM_RDWR_ENV
267 /* try to queue prefetch, if needed */
268 if (!(tdc->flags & DFNextStarted) && !noLock) {
269 afs_PrefetchChunk(avc, tdc, acred, &treq);
275 ReleaseReadLock(&avc->lock);
276 osi_FreeSmallSpace(tvec);
277 error = afs_CheckCode(error, &treq, 10);
281 /* called with the dcache entry triggering the fetch, the vcache entry involved,
282 * and a vrequest for the read call. Marks the dcache entry as having already
283 * triggered a prefetch, starts the prefetch going and sets the DFFetchReq
284 * flag in the prefetched block, so that the next call to read knows to wait
285 * for the daemon to start doing things.
287 * This function must be called with the vnode at least read-locked
288 * because it plays around with dcache entries.
290 void afs_PrefetchChunk(struct vcache *avc, struct dcache *adc,
291 struct AFS_UCRED *acred, struct vrequest *areq)
293 register struct dcache *tdc;
294 register afs_int32 offset;
295 afs_int32 j1, j2; /* junk vbls for GetDCache to trash */
297 offset = adc->f.chunk+1; /* next chunk we'll need */
298 offset = AFS_CHUNKTOBASE(offset); /* base of next chunk */
299 if (offset < avc->m.Length && !afs_BBusy()) {
301 adc->flags |= DFNextStarted; /* we've tried to prefetch for this guy */
302 tdc = afs_GetDCache(avc, offset, areq, &j1, &j2, 2); /* type 2 never returns 0 */
303 if (!(tdc->flags & DFFetchReq)) {
304 /* ask the daemon to do the work */
305 tdc->flags |= DFFetchReq; /* guaranteed to be cleared by BKG or GetDCache */
306 /* last parm (1) tells bkg daemon to do an afs_PutDCache when it is done,
307 * since we don't want to wait for it to finish before doing so ourselves.
310 mutex_exit(&tdc->lock);
312 bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred, (long)offset,
313 (long) tdc, 1L, 0L, 0L);
315 /* Bkg table full; just abort non-important prefetching to avoid deadlocks */
316 tdc->flags &= ~(DFNextStarted | DFFetchReq);
327 /* if the vcache is up-to-date, and the request fits entirely into the chunk
328 * that the hint here references, then we just use it quickly, otherwise we
329 * have to call the slow read.
331 * This could be generalized in several ways to take advantage of partial
332 * state even when all the chips don't fall the right way. For instance,
333 * if the hint is good and the first part of the read request can be
334 * satisfied from the chunk, then just do the read. After the read has
335 * completed, check to see if there's more. (Chances are there won't be.)
336 * If there is more, then just call afs_UFSReadSlow and let it do the rest.
338 * For the time being, I'm ignoring quick.f, but it should be used at
340 * do this in the future avc->quick.f = tfile; but I think it
341 * has to be done under a write lock, but don't want to wait on the
344 /* everywhere that a dcache can be freed (look for NULLIDX)
345 * probably does it under a write lock on xdcache. Need to invalidate
347 * Also need to worry about DFFetching, and IFFree, I think. */
348 static struct dcache *savedc = 0;
350 afs_UFSReadFast(avc, auio, acred, albn, abpp, noLock)
351 register struct vcache *avc;
353 struct AFS_UCRED *acred;
357 struct vrequest treq;
361 struct osi_file *tfile;
365 ObtainReadLock(&avc->lock);
366 ObtainReadLock(&afs_xdcache);
368 if ((avc->states & CStatd) /* up to date */
369 && (tdc = avc->quick.dc) && (tdc->index != NULLIDX)
370 && !(afs_indexFlags[tdc->index] & IFFree)) {
373 ReleaseReadLock(&afs_xdcache);
375 if ((tdc->stamp == avc->quick.stamp) /* hint matches */
376 && ((offDiff = (auio->afsio_offset - avc->quick.minLoc)) >= 0)
377 && (tdc->f.chunkBytes >= auio->afsio_resid + offDiff)
378 && !(tdc->flags & DFFetching)) { /* fits in chunk */
380 auio->afsio_offset -= avc->quick.minLoc;
382 tfile = (struct osi_file *)osi_UFSOpen(tdc->f.inode);
387 code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, auio, NULL, NULL, NULL, &afs_osi_cred);
391 code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, auio, NULL, NULL);
393 code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, (off_t)&auio->afsio_offset, auio, NULL, NULL, -1);
399 VOP_RWLOCK(tfile->vnode, 0);
400 code = VOP_READ(tfile->vnode, auio, 0, &afs_osi_cred);
401 VOP_RWUNLOCK(tfile->vnode, 0);
404 #if defined(AFS_SGI_ENV)
406 AFS_VOP_RWLOCK(tfile->vnode, VRWLOCK_READ);
407 AFS_VOP_READ(tfile->vnode, auio, IO_ISLOCKED, &afs_osi_cred, code);
408 AFS_VOP_RWUNLOCK(tfile->vnode, VRWLOCK_READ);
412 auio->uio_rw = UIO_READ;
414 VOP_READ(tfile->vnode, auio, 0, &afs_osi_cred, code);
416 #else /* AFS_OSF_ENV */
417 #if defined(AFS_HPUX100_ENV)
419 code = VOP_RDWR(tfile->vnode, auio, UIO_READ, 0, &afs_osi_cred);
422 #if defined(AFS_LINUX20_ENV)
424 code = osi_file_uio_rdwr(tfile, auio, UIO_READ);
427 #if defined(AFS_DARWIN_ENV)
429 VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, current_proc());
430 code = VOP_READ(tfile->vnode, auio, 0, &afs_osi_cred);
431 VOP_UNLOCK(tfile->vnode, 0, current_proc());
434 code = VOP_RDWR(tfile->vnode, auio, UIO_READ, 0, &afs_osi_cred);
442 auio->afsio_offset += avc->quick.minLoc;
444 /* Fix up LRU info */
445 hset(afs_indexTimes[tdc->index], afs_indexCounter);
446 hadd32(afs_indexCounter, 1);
449 #ifndef AFS_VM_RDWR_ENV
450 if (!(code = afs_InitReq(&treq, acred))&& (!(tdc->flags & DFNextStarted)))
451 afs_PrefetchChunk(avc, tdc, acred, &treq);
453 ReleaseReadLock(&avc->lock);
458 if (!tdc->f.chunkBytes) { /* debugging f.chunkBytes == 0 problem */
463 ReleaseReadLock(&afs_xdcache);
466 /* come here if fast path doesn't work for some reason or other */
468 ReleaseReadLock(&avc->lock);
469 return afs_UFSRead(avc, auio, acred, albn, abpp, noLock);
472 afs_UFSRead(avc, auio, acred, albn, abpp, noLock)
475 struct AFS_UCRED *acred;
479 afs_int32 totalLength;
480 afs_int32 transferLength;
482 struct dcache *tdc=0;
483 afs_int32 offset, len, error;
486 struct osi_file *tfile;
488 int munlocked, trybusy=1;
490 struct vrequest treq;
492 AFS_STATCNT(afs_UFSRead);
496 /* check that we have the latest status info in the vnode cache */
497 if (code = afs_InitReq(&treq, acred)) return code;
500 osi_Panic ("null avc in afs_UFSRead");
502 code = afs_VerifyVCache(avc, &treq);
504 code = afs_CheckCode(code, &treq, 11); /* failed to get it */
510 #ifndef AFS_VM_RDWR_ENV
511 if (AFS_NFSXLATORREQ(acred)) {
512 if (!afs_AccessOK(avc, PRSFS_READ, &treq,
513 CHECK_MODE_BITS|CMB_ALLOW_EXEC_AS_READ)) {
514 return afs_CheckCode(EACCES, &treq, 12);
519 tvec = (struct iovec *) osi_AllocSmallSpace(sizeof(struct iovec));
520 totalLength = auio->afsio_resid;
521 filePos = auio->afsio_offset;
522 afs_Trace4(afs_iclSetp, CM_TRACE_READ, ICL_TYPE_POINTER, avc,
523 ICL_TYPE_INT32, filePos, ICL_TYPE_INT32, totalLength,
524 ICL_TYPE_INT32, avc->m.Length);
528 ObtainReadLock(&avc->lock);
529 #if defined(AFS_TEXT_ENV) && !defined(AFS_VM_RDWR_ENV)
530 if (avc->flushDV.high == AFS_MAXDV && avc->flushDV.low == AFS_MAXDV) {
531 hset(avc->flushDV, avc->m.DataVersion);
535 while (totalLength > 0) {
536 /* read all of the cached info */
537 if (filePos >= avc->m.Length) break; /* all done */
539 if (tdc) afs_PutDCache(tdc);
540 tdc = afs_FindDCache(avc, filePos);
542 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
543 len = tdc->f.chunkBytes - offset;
546 /* a tricky question: does the presence of the DFFetching flag
547 mean that we're fetching the latest version of the file? No.
548 The server could update the file as soon as the fetch responsible
549 for the setting of the DFFetching flag completes.
551 However, the presence of the DFFetching flag (visible under a
552 read lock since it is set and cleared only under a write lock)
553 means that we're fetching as good a version as was known to this
554 client at the time of the last call to afs_VerifyVCache, since
555 the latter updates the stat cache's m.DataVersion field under a
556 write lock, and from the time that the DFFetching flag goes on
557 (before the fetch starts), to the time it goes off (after the
558 fetch completes), afs_GetDCache keeps at least a read lock
559 (actually it keeps an S lock) on the cache entry.
561 This means that if the DFFetching flag is set, we can use that
562 data for any reads that must come from the current version of
563 the file (current == m.DataVersion).
565 Another way of looking at this same point is this: if we're
566 fetching some data and then try do an afs_VerifyVCache, the
567 VerifyVCache operation will not complete until after the
568 DFFetching flag is turned off and the dcache entry's f.versionNo
571 Note, by the way, that if DFFetching is set,
572 m.DataVersion > f.versionNo (the latter is not updated until
573 after the fetch completes).
575 if (tdc) afs_PutDCache(tdc); /* before reusing tdc */
577 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 2);
581 /* now, first try to start transfer, if we'll need the data. If
582 * data already coming, we don't need to do this, obviously. Type
583 * 2 requests never return a null dcache entry, btw. */
584 if (!(tdc->flags & DFFetching)
585 && !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
586 /* have cache entry, it is not coming in now, and we'll need new data */
588 if (trybusy && !afs_BBusy()) {
590 /* daemon is not busy */
591 if (!(tdc->flags & DFFetchReq)) {
592 tdc->flags |= DFFetchReq;
594 mutex_exit(&tdc->lock);
597 bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
598 (long)filePos, (long) tdc, 0L, 0L);
600 /* Bkg table full; retry deadlocks */
601 tdc->flags &= ~DFFetchReq;
602 trybusy = 0; /* Avoid bkg daemon since they're too busy */
606 while (tdc->flags & DFFetchReq) {
607 /* don't need waiting flag on this one */
608 ReleaseReadLock(&avc->lock);
609 afs_osi_Sleep(&tdc->validPos);
610 ObtainReadLock(&avc->lock);
614 /* now data may have started flowing in (if DFFetching is on). If
615 * data is now streaming in, then wait for some interesting stuff. */
616 while ((tdc->flags & DFFetching) && tdc->validPos <= filePos) {
617 /* too early: wait for DFFetching flag to vanish, or data to appear */
618 tdc->flags |= DFWaiting;
619 ReleaseReadLock(&avc->lock);
620 afs_osi_Sleep(&tdc->validPos);
621 ObtainReadLock(&avc->lock);
623 /* fetching flag gone, data is here, or we never tried (BBusy for instance) */
624 if (tdc->flags & DFFetching) {
625 /* still fetching, some new data is here: compute length and offset */
626 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
627 len = tdc->validPos - filePos;
630 /* no longer fetching, verify data version (avoid new GetDCache call) */
631 if (hsame(avc->m.DataVersion, tdc->f.versionNo)) {
632 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
633 len = tdc->f.chunkBytes - offset;
636 /* don't have current data, so get it below */
638 tdc = (struct dcache *) 0;
643 ReleaseReadLock(&avc->lock);
644 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 1);
645 ObtainReadLock(&avc->lock);
653 if (len > totalLength) len = totalLength; /* will read len bytes */
654 if (len <= 0) { /* shouldn't get here if DFFetching is on */
655 /* read past the end of a chunk, may not be at next chunk yet, and yet
656 also not at eof, so may have to supply fake zeros */
657 len = AFS_CHUNKTOSIZE(tdc->f.chunk) - offset; /* bytes left in chunk addr space */
658 if (len > totalLength) len = totalLength; /* and still within xfr request */
659 code = avc->m.Length - offset; /* and still within file */
660 if (len > code) len = code;
661 if (len > AFS_ZEROS) len = sizeof(afs_zeros); /* and in 0 buffer */
662 afsio_copy(auio, &tuio, tvec);
663 afsio_trim(&tuio, len);
664 AFS_UIOMOVE(afs_zeros, len, UIO_READ, &tuio, code);
671 /* get the data from the file */
673 if (tfile = tdc->ihint) {
674 if (tdc->f.inode != tfile->inum){
675 afs_warn( "afs_UFSRead: %x hint mismatch tdc %d inum %d\n",
676 tdc, tdc->f.inode, tfile->inum );
678 tdc->ihint = tfile = 0;
688 tfile = (struct osi_file *)osi_UFSOpen(tdc->f.inode);
689 /* mung uio structure to be right for this transfer */
690 afsio_copy(auio, &tuio, tvec);
691 afsio_trim(&tuio, len);
692 tuio.afsio_offset = offset;
696 code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, &tuio, NULL, NULL,
697 NULL, &afs_osi_cred);
701 code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, &tuio, NULL, NULL);
702 /* Flush all JFS pages now for big performance gain in big file cases
703 * If we do something like this, must check to be sure that AFS file
704 * isn't mmapped... see afs_gn_map() for why.
707 if (tfile->vnode->v_gnode && tfile->vnode->v_gnode->gn_seg) {
708 many different ways to do similar things:
709 so far, the best performing one is #2, but #1 might match it if we
710 straighten out the confusion regarding which pages to flush. It
712 1. vm_flushp(tfile->vnode->v_gnode->gn_seg, 0, len/PAGESIZE - 1);
713 2. vm_releasep(tfile->vnode->v_gnode->gn_seg, offset/PAGESIZE,
714 (len + PAGESIZE-1)/PAGESIZE);
715 3. vms_inactive(tfile->vnode->v_gnode->gn_seg) Doesn't work correctly
716 4. vms_delete(tfile->vnode->v_gnode->gn_seg) probably also fails
717 tfile->vnode->v_gnode->gn_seg = NULL;
721 Unfortunately, this seems to cause frequent "cache corruption" episodes.
722 vm_releasep(tfile->vnode->v_gnode->gn_seg, offset/PAGESIZE,
723 (len + PAGESIZE-1)/PAGESIZE);
727 code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, (off_t)&offset, &tuio, NULL, NULL, -1);
733 VOP_RWLOCK(tfile->vnode, 0);
734 code = VOP_READ(tfile->vnode, &tuio, 0, &afs_osi_cred);
735 VOP_RWUNLOCK(tfile->vnode, 0);
738 #if defined(AFS_SGI_ENV)
740 AFS_VOP_RWLOCK(tfile->vnode, VRWLOCK_READ);
741 AFS_VOP_READ(tfile->vnode, &tuio, IO_ISLOCKED, &afs_osi_cred,
743 AFS_VOP_RWUNLOCK(tfile->vnode, VRWLOCK_READ);
747 tuio.uio_rw = UIO_READ;
749 VOP_READ(tfile->vnode, &tuio, 0, &afs_osi_cred, code);
751 #else /* AFS_OSF_ENV */
753 code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, &afs_osi_cred);
755 #if defined(AFS_HPUX100_ENV)
757 code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, &afs_osi_cred);
760 #if defined(AFS_LINUX20_ENV)
762 code = osi_file_uio_rdwr(tfile, &tuio, UIO_READ);
765 #if defined(AFS_DARWIN_ENV)
767 VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, current_proc());
768 code = VOP_READ(tfile->vnode, &tuio, 0, &afs_osi_cred);
769 VOP_UNLOCK(tfile->vnode, 0, current_proc());
772 code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, &afs_osi_cred);
783 if (!tdc->ihint && nihints < maxIHint) {
796 /* otherwise we've read some, fixup length, etc and continue with next seg */
797 len = len - tuio.afsio_resid; /* compute amount really transferred */
798 afsio_skip(auio, len); /* update input uio structure */
800 transferLength += len;
802 if (len <= 0) break; /* surprise eof */
805 /* if we make it here with tdc non-zero, then it is the last chunk we
806 * dealt with, and we have to release it when we're done. We hold on
807 * to it in case we need to do a prefetch, obviously.
810 #ifndef AFS_VM_RDWR_ENV
811 /* try to queue prefetch, if needed */
812 if (!(tdc->flags & DFNextStarted) && !noLock) {
813 afs_PrefetchChunk(avc, tdc, acred, &treq);
819 ReleaseReadLock(&avc->lock);
821 osi_FreeSmallSpace(tvec);
822 error = afs_CheckCode(error, &treq, 13);