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 <afsconfig.h>
20 #include "../afs/param.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;
58 afs_size_t totalLength;
59 afs_size_t transferLength;
61 afs_size_t offset, len, tlen;
64 afs_int32 error, trybusy=1;
71 AFS_STATCNT(afs_MemRead);
75 /* check that we have the latest status info in the vnode cache */
76 if (code = afs_InitReq(&treq, acred)) return code;
78 code = afs_VerifyVCache(avc, &treq);
80 code = afs_CheckCode(code, &treq, 8); /* failed to get it */
85 #ifndef AFS_VM_RDWR_ENV
86 if (AFS_NFSXLATORREQ(acred)) {
87 if (!afs_AccessOK(avc, PRSFS_READ, &treq,
88 CHECK_MODE_BITS|CMB_ALLOW_EXEC_AS_READ)) {
89 return afs_CheckCode(EACCES, &treq, 9);
94 tvec = (struct iovec *) osi_AllocSmallSpace(sizeof(struct iovec));
95 totalLength = auio->afsio_resid;
96 filePos = auio->afsio_offset;
97 afs_Trace4(afs_iclSetp, CM_TRACE_READ, ICL_TYPE_POINTER, avc,
98 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(filePos),
99 ICL_TYPE_INT32, totalLength,
100 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length));
104 ObtainReadLock(&avc->lock);
105 #if defined(AFS_TEXT_ENV) && !defined(AFS_VM_RDWR_ENV)
106 if (avc->flushDV.high == AFS_MAXDV && avc->flushDV.low == AFS_MAXDV) {
107 hset(avc->flushDV, avc->m.DataVersion);
110 while (totalLength > 0) {
111 /* read all of the cached info */
112 if (filePos >= avc->m.Length) break; /* all done */
114 if (tdc) afs_PutDCache(tdc);
115 tdc = afs_FindDCache(avc, filePos);
117 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
118 len = tdc->f.chunkBytes - offset;
121 /* a tricky question: does the presence of the DFFetching flag
122 mean that we're fetching the latest version of the file? No.
123 The server could update the file as soon as the fetch responsible
124 for the setting of the DFFetching flag completes.
126 However, the presence of the DFFetching flag (visible under a
127 read lock since it is set and cleared only under a write lock)
128 means that we're fetching as good a version as was known to this
129 client at the time of the last call to afs_VerifyVCache, since
130 the latter updates the stat cache's m.DataVersion field under a
131 write lock, and from the time that the DFFetching flag goes on
132 (before the fetch starts), to the time it goes off (after the
133 fetch completes), afs_GetDCache keeps at least a read lock
134 (actually it keeps an S lock) on the cache entry.
136 This means that if the DFFetching flag is set, we can use that
137 data for any reads that must come from the current version of
138 the file (current == m.DataVersion).
140 Another way of looking at this same point is this: if we're
141 fetching some data and then try do an afs_VerifyVCache, the
142 VerifyVCache operation will not complete until after the
143 DFFetching flag is turned off and the dcache entry's f.versionNo
146 Note, by the way, that if DFFetching is set,
147 m.DataVersion > f.versionNo (the latter is not updated until
148 after the fetch completes).
150 if (tdc) afs_PutDCache(tdc); /* before reusing tdc */
151 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 2);
152 /* now, first try to start transfer, if we'll need the data. If
153 * data already coming, we don't need to do this, obviously. Type
154 * 2 requests never return a null dcache entry, btw.
156 if (!(tdc->flags & DFFetching)
157 && !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
158 /* have cache entry, it is not coming in now,
159 * and we'll need new data */
161 if (trybusy && !afs_BBusy()) {
163 /* daemon is not busy */
164 if (!(tdc->flags & DFFetchReq)) {
165 /* start the daemon (may already be running, however) */
166 tdc->flags |= DFFetchReq;
167 bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
168 (afs_size_t)filePos, (afs_size_t) 0,
171 tdc->flags &= ~DFFetchReq;
172 trybusy = 0; /* Avoid bkg daemon since they're too busy */
175 /* don't use bp pointer! */
177 while (tdc->flags & DFFetchReq) {
178 /* don't need waiting flag on this one */
179 ReleaseReadLock(&avc->lock);
180 afs_osi_Sleep(&tdc->validPos);
181 ObtainReadLock(&avc->lock);
185 /* now data may have started flowing in (if DFFetching is on). If
186 * data is now streaming in, then wait for some interesting stuff. */
187 while ((tdc->flags & DFFetching) && tdc->validPos <= filePos) {
188 /* too early: wait for DFFetching flag to vanish, or data to appear */
189 tdc->flags |= DFWaiting;
190 ReleaseReadLock(&avc->lock);
191 afs_osi_Sleep(&tdc->validPos);
192 ObtainReadLock(&avc->lock);
194 /* fetching flag gone, data is here, or we never tried (BBusy for instance) */
195 if (tdc->flags & DFFetching) {
196 /* still fetching, some new data is here: compute length and offset */
197 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
198 len = tdc->validPos - filePos;
201 /* no longer fetching, verify data version (avoid new GetDCache call) */
202 if (hsame(avc->m.DataVersion, tdc->f.versionNo)) {
203 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
204 len = tdc->f.chunkBytes - offset;
207 /* don't have current data, so get it below */
209 tdc = (struct dcache *) 0;
214 ReleaseReadLock(&avc->lock);
215 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 1);
216 ObtainReadLock(&avc->lock);
224 if (len > totalLength) len = totalLength; /* will read len bytes */
225 if (len <= 0) { /* shouldn't get here if DFFetching is on */
226 /* read past the end of a chunk, may not be at next chunk yet, and yet
227 also not at eof, so may have to supply fake zeros */
228 len = AFS_CHUNKTOSIZE(tdc->f.chunk) - offset; /* bytes left in chunk addr space */
229 if (len > totalLength) len = totalLength; /* and still within xfr request */
230 tlen = avc->m.Length - offset; /* and still within file */
231 if (len > tlen) len = tlen;
232 if (len > AFS_ZEROS) len = sizeof(afs_zeros); /* and in 0 buffer */
233 afsio_copy(auio, &tuio, tvec);
235 afsio_trim(&tuio, trimlen);
236 AFS_UIOMOVE(afs_zeros, trimlen, UIO_READ, &tuio, code);
243 /* get the data from the mem cache */
245 /* mung uio structure to be right for this transfer */
246 afsio_copy(auio, &tuio, tvec);
248 afsio_trim(&tuio, trimlen);
249 tuio.afsio_offset = offset;
251 code = afs_MemReadUIO(tdc->f.inode, &tuio);
258 /* otherwise we've read some, fixup length, etc and continue with next seg */
259 len = len - tuio.afsio_resid; /* compute amount really transferred */
261 afsio_skip(auio, trimlen); /* update input uio structure */
263 transferLength += len;
266 if (len <= 0) break; /* surprise eof */
267 } /* the whole while loop */
269 /* if we make it here with tdc non-zero, then it is the last chunk we
270 * dealt with, and we have to release it when we're done. We hold on
271 * to it in case we need to do a prefetch.
274 #ifndef AFS_VM_RDWR_ENV
275 /* try to queue prefetch, if needed */
276 if (!(tdc->flags & DFNextStarted) && !noLock) {
277 afs_PrefetchChunk(avc, tdc, acred, &treq);
283 ReleaseReadLock(&avc->lock);
284 osi_FreeSmallSpace(tvec);
285 error = afs_CheckCode(error, &treq, 10);
289 /* called with the dcache entry triggering the fetch, the vcache entry involved,
290 * and a vrequest for the read call. Marks the dcache entry as having already
291 * triggered a prefetch, starts the prefetch going and sets the DFFetchReq
292 * flag in the prefetched block, so that the next call to read knows to wait
293 * for the daemon to start doing things.
295 * This function must be called with the vnode at least read-locked
296 * because it plays around with dcache entries.
298 void afs_PrefetchChunk(struct vcache *avc, struct dcache *adc,
299 struct AFS_UCRED *acred, struct vrequest *areq)
301 register struct dcache *tdc;
303 afs_size_t j1, j2; /* junk vbls for GetDCache to trash */
305 offset = adc->f.chunk+1; /* next chunk we'll need */
306 offset = AFS_CHUNKTOBASE(offset); /* base of next chunk */
307 if (offset < avc->m.Length && !afs_BBusy()) {
309 adc->flags |= DFNextStarted; /* we've tried to prefetch for this guy */
310 tdc = afs_GetDCache(avc, offset, areq, &j1, &j2, 2); /* type 2 never returns 0 */
311 if (!(tdc->flags & DFFetchReq)) {
312 /* ask the daemon to do the work */
313 tdc->flags |= DFFetchReq; /* guaranteed to be cleared by BKG or GetDCache */
314 /* last parm (1) tells bkg daemon to do an afs_PutDCache when it is done,
315 * since we don't want to wait for it to finish before doing so ourselves.
318 mutex_exit(&tdc->lock);
320 bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
321 (afs_size_t) offset, (afs_size_t) 1, tdc);
323 /* Bkg table full; just abort non-important prefetching to avoid deadlocks */
324 tdc->flags &= ~(DFNextStarted | DFFetchReq);
335 /* if the vcache is up-to-date, and the request fits entirely into the chunk
336 * that the hint here references, then we just use it quickly, otherwise we
337 * have to call the slow read.
339 * This could be generalized in several ways to take advantage of partial
340 * state even when all the chips don't fall the right way. For instance,
341 * if the hint is good and the first part of the read request can be
342 * satisfied from the chunk, then just do the read. After the read has
343 * completed, check to see if there's more. (Chances are there won't be.)
344 * If there is more, then just call afs_UFSReadSlow and let it do the rest.
346 * For the time being, I'm ignoring quick.f, but it should be used at
348 * do this in the future avc->quick.f = tfile; but I think it
349 * has to be done under a write lock, but don't want to wait on the
352 /* everywhere that a dcache can be freed (look for NULLIDX)
353 * probably does it under a write lock on xdcache. Need to invalidate
355 * Also need to worry about DFFetching, and IFFree, I think. */
356 static struct dcache *savedc = 0;
358 afs_UFSReadFast(avc, auio, acred, albn, abpp, noLock)
359 register struct vcache *avc;
361 struct AFS_UCRED *acred;
366 struct vrequest treq;
370 struct osi_file *tfile;
374 ObtainReadLock(&avc->lock);
375 ObtainReadLock(&afs_xdcache);
377 if ((avc->states & CStatd) /* up to date */
378 && (tdc = avc->quick.dc) && (tdc->index != NULLIDX)
379 && !(afs_indexFlags[tdc->index] & IFFree)) {
382 ReleaseReadLock(&afs_xdcache);
384 if ((tdc->stamp == avc->quick.stamp) /* hint matches */
385 && ((offDiff = (auio->afsio_offset - avc->quick.minLoc)) >= 0)
386 && (tdc->f.chunkBytes >= auio->afsio_resid + offDiff)
387 && !(tdc->flags & DFFetching)) { /* fits in chunk */
389 auio->afsio_offset -= avc->quick.minLoc;
391 afs_Trace4(afs_iclSetp, CM_TRACE_READFAST, ICL_TYPE_POINTER, avc,
392 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(auio->afsio_offset),
393 ICL_TYPE_INT32, auio->afsio_resid,
394 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length));
396 tfile = (struct osi_file *)osi_UFSOpen(tdc->f.inode);
401 code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, auio, NULL, NULL, NULL, &afs_osi_cred);
405 code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, auio, NULL, NULL);
407 code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, (off_t)&auio->afsio_offset, auio, NULL, NULL, -1);
413 VOP_RWLOCK(tfile->vnode, 0);
414 code = VOP_READ(tfile->vnode, auio, 0, &afs_osi_cred);
415 VOP_RWUNLOCK(tfile->vnode, 0);
418 #if defined(AFS_SGI_ENV)
420 AFS_VOP_RWLOCK(tfile->vnode, VRWLOCK_READ);
421 AFS_VOP_READ(tfile->vnode, auio, IO_ISLOCKED, &afs_osi_cred, code);
422 AFS_VOP_RWUNLOCK(tfile->vnode, VRWLOCK_READ);
426 auio->uio_rw = UIO_READ;
428 VOP_READ(tfile->vnode, auio, 0, &afs_osi_cred, code);
430 #else /* AFS_OSF_ENV */
431 #if defined(AFS_HPUX100_ENV)
433 code = VOP_RDWR(tfile->vnode, auio, UIO_READ, 0, &afs_osi_cred);
436 #if defined(AFS_LINUX20_ENV)
438 code = osi_file_uio_rdwr(tfile, auio, UIO_READ);
441 #if defined(AFS_DARWIN_ENV)
443 VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, current_proc());
444 code = VOP_READ(tfile->vnode, auio, 0, &afs_osi_cred);
445 VOP_UNLOCK(tfile->vnode, 0, current_proc());
448 code = VOP_RDWR(tfile->vnode, auio, UIO_READ, 0, &afs_osi_cred);
456 auio->afsio_offset += avc->quick.minLoc;
458 /* Fix up LRU info */
459 hset(afs_indexTimes[tdc->index], afs_indexCounter);
460 hadd32(afs_indexCounter, 1);
463 #ifndef AFS_VM_RDWR_ENV
464 if (!(code = afs_InitReq(&treq, acred))&& (!(tdc->flags & DFNextStarted)))
465 afs_PrefetchChunk(avc, tdc, acred, &treq);
467 ReleaseReadLock(&avc->lock);
472 if (!tdc->f.chunkBytes) { /* debugging f.chunkBytes == 0 problem */
477 ReleaseReadLock(&afs_xdcache);
480 /* come here if fast path doesn't work for some reason or other */
482 ReleaseReadLock(&avc->lock);
483 return afs_UFSRead(avc, auio, acred, albn, abpp, noLock);
486 afs_UFSRead(avc, auio, acred, albn, abpp, noLock)
489 struct AFS_UCRED *acred;
494 afs_size_t totalLength;
495 afs_size_t transferLength;
497 afs_size_t offset, len, tlen;
499 struct dcache *tdc=0;
503 struct osi_file *tfile;
505 int munlocked, trybusy=1;
507 struct vrequest treq;
509 AFS_STATCNT(afs_UFSRead);
513 /* check that we have the latest status info in the vnode cache */
514 if (code = afs_InitReq(&treq, acred)) return code;
517 osi_Panic ("null avc in afs_UFSRead");
519 code = afs_VerifyVCache(avc, &treq);
521 code = afs_CheckCode(code, &treq, 11); /* failed to get it */
527 #ifndef AFS_VM_RDWR_ENV
528 if (AFS_NFSXLATORREQ(acred)) {
529 if (!afs_AccessOK(avc, PRSFS_READ, &treq,
530 CHECK_MODE_BITS|CMB_ALLOW_EXEC_AS_READ)) {
531 return afs_CheckCode(EACCES, &treq, 12);
536 tvec = (struct iovec *) osi_AllocSmallSpace(sizeof(struct iovec));
537 totalLength = auio->afsio_resid;
538 filePos = auio->afsio_offset;
539 afs_Trace4(afs_iclSetp, CM_TRACE_READ, ICL_TYPE_POINTER, avc,
540 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(filePos),
541 ICL_TYPE_INT32, totalLength,
542 ICL_TYPE_OFFSET, 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 while (totalLength > 0) {
554 /* read all of the cached info */
555 if (filePos >= avc->m.Length) break; /* all done */
557 if (tdc) afs_PutDCache(tdc);
558 tdc = afs_FindDCache(avc, filePos);
560 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
561 len = tdc->f.chunkBytes - offset;
564 /* a tricky question: does the presence of the DFFetching flag
565 mean that we're fetching the latest version of the file? No.
566 The server could update the file as soon as the fetch responsible
567 for the setting of the DFFetching flag completes.
569 However, the presence of the DFFetching flag (visible under a
570 read lock since it is set and cleared only under a write lock)
571 means that we're fetching as good a version as was known to this
572 client at the time of the last call to afs_VerifyVCache, since
573 the latter updates the stat cache's m.DataVersion field under a
574 write lock, and from the time that the DFFetching flag goes on
575 (before the fetch starts), to the time it goes off (after the
576 fetch completes), afs_GetDCache keeps at least a read lock
577 (actually it keeps an S lock) on the cache entry.
579 This means that if the DFFetching flag is set, we can use that
580 data for any reads that must come from the current version of
581 the file (current == m.DataVersion).
583 Another way of looking at this same point is this: if we're
584 fetching some data and then try do an afs_VerifyVCache, the
585 VerifyVCache operation will not complete until after the
586 DFFetching flag is turned off and the dcache entry's f.versionNo
589 Note, by the way, that if DFFetching is set,
590 m.DataVersion > f.versionNo (the latter is not updated until
591 after the fetch completes).
593 if (tdc) afs_PutDCache(tdc); /* before reusing tdc */
595 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 2);
599 /* now, first try to start transfer, if we'll need the data. If
600 * data already coming, we don't need to do this, obviously. Type
601 * 2 requests never return a null dcache entry, btw. */
602 if (!(tdc->flags & DFFetching)
603 && !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
604 /* have cache entry, it is not coming in now, and we'll need new data */
606 if (trybusy && !afs_BBusy()) {
608 /* daemon is not busy */
609 if (!(tdc->flags & DFFetchReq)) {
610 tdc->flags |= DFFetchReq;
612 mutex_exit(&tdc->lock);
615 bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
616 (afs_size_t)filePos, (afs_size_t) 0,
619 /* Bkg table full; retry deadlocks */
620 tdc->flags &= ~DFFetchReq;
621 trybusy = 0; /* Avoid bkg daemon since they're too busy */
625 while (tdc->flags & DFFetchReq) {
626 /* don't need waiting flag on this one */
627 ReleaseReadLock(&avc->lock);
628 afs_osi_Sleep(&tdc->validPos);
629 ObtainReadLock(&avc->lock);
633 /* now data may have started flowing in (if DFFetching is on). If
634 * data is now streaming in, then wait for some interesting stuff. */
635 while ((tdc->flags & DFFetching) && tdc->validPos <= filePos) {
636 /* too early: wait for DFFetching flag to vanish, or data to appear */
637 tdc->flags |= DFWaiting;
638 ReleaseReadLock(&avc->lock);
639 afs_osi_Sleep(&tdc->validPos);
640 ObtainReadLock(&avc->lock);
642 /* fetching flag gone, data is here, or we never tried (BBusy for instance) */
643 if (tdc->flags & DFFetching) {
644 /* still fetching, some new data is here: compute length and offset */
645 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
646 len = tdc->validPos - filePos;
649 /* no longer fetching, verify data version (avoid new GetDCache call) */
650 if (hsame(avc->m.DataVersion, tdc->f.versionNo)) {
651 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
652 len = tdc->f.chunkBytes - offset;
655 /* don't have current data, so get it below */
657 tdc = (struct dcache *) 0;
662 ReleaseReadLock(&avc->lock);
663 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 1);
664 ObtainReadLock(&avc->lock);
672 if (len > totalLength) len = totalLength; /* will read len bytes */
673 if (len <= 0) { /* shouldn't get here if DFFetching is on */
674 /* read past the end of a chunk, may not be at next chunk yet, and yet
675 also not at eof, so may have to supply fake zeros */
676 len = AFS_CHUNKTOSIZE(tdc->f.chunk) - offset; /* bytes left in chunk addr space */
677 if (len > totalLength) len = totalLength; /* and still within xfr request */
678 tlen = avc->m.Length - offset; /* and still within file */
679 if (len > tlen) len = tlen;
680 if (len > AFS_ZEROS) len = sizeof(afs_zeros); /* and in 0 buffer */
681 afsio_copy(auio, &tuio, tvec);
683 afsio_trim(&tuio, trimlen);
684 AFS_UIOMOVE(afs_zeros, trimlen, UIO_READ, &tuio, code);
691 /* get the data from the file */
693 if (tfile = tdc->ihint) {
694 if (tdc->f.inode != tfile->inum){
695 afs_warn( "afs_UFSRead: %x hint mismatch tdc %d inum %d\n",
696 tdc, tdc->f.inode, tfile->inum );
698 tdc->ihint = tfile = 0;
708 tfile = (struct osi_file *)osi_UFSOpen(tdc->f.inode);
709 /* mung uio structure to be right for this transfer */
710 afsio_copy(auio, &tuio, tvec);
712 afsio_trim(&tuio, trimlen);
713 tuio.afsio_offset = offset;
717 code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, &tuio, NULL, NULL,
718 NULL, &afs_osi_cred);
722 code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, &tuio, NULL, NULL);
723 /* Flush all JFS pages now for big performance gain in big file cases
724 * If we do something like this, must check to be sure that AFS file
725 * isn't mmapped... see afs_gn_map() for why.
728 if (tfile->vnode->v_gnode && tfile->vnode->v_gnode->gn_seg) {
729 many different ways to do similar things:
730 so far, the best performing one is #2, but #1 might match it if we
731 straighten out the confusion regarding which pages to flush. It
733 1. vm_flushp(tfile->vnode->v_gnode->gn_seg, 0, len/PAGESIZE - 1);
734 2. vm_releasep(tfile->vnode->v_gnode->gn_seg, offset/PAGESIZE,
735 (len + PAGESIZE-1)/PAGESIZE);
736 3. vms_inactive(tfile->vnode->v_gnode->gn_seg) Doesn't work correctly
737 4. vms_delete(tfile->vnode->v_gnode->gn_seg) probably also fails
738 tfile->vnode->v_gnode->gn_seg = NULL;
742 Unfortunately, this seems to cause frequent "cache corruption" episodes.
743 vm_releasep(tfile->vnode->v_gnode->gn_seg, offset/PAGESIZE,
744 (len + PAGESIZE-1)/PAGESIZE);
748 code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, (off_t)&offset, &tuio, NULL, NULL, -1);
754 VOP_RWLOCK(tfile->vnode, 0);
755 code = VOP_READ(tfile->vnode, &tuio, 0, &afs_osi_cred);
756 VOP_RWUNLOCK(tfile->vnode, 0);
759 #if defined(AFS_SGI_ENV)
761 AFS_VOP_RWLOCK(tfile->vnode, VRWLOCK_READ);
762 AFS_VOP_READ(tfile->vnode, &tuio, IO_ISLOCKED, &afs_osi_cred,
764 AFS_VOP_RWUNLOCK(tfile->vnode, VRWLOCK_READ);
768 tuio.uio_rw = UIO_READ;
770 VOP_READ(tfile->vnode, &tuio, 0, &afs_osi_cred, code);
772 #else /* AFS_OSF_ENV */
774 code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, &afs_osi_cred);
776 #if defined(AFS_HPUX100_ENV)
778 code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, &afs_osi_cred);
781 #if defined(AFS_LINUX20_ENV)
783 code = osi_file_uio_rdwr(tfile, &tuio, UIO_READ);
786 #if defined(AFS_DARWIN_ENV)
788 VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, current_proc());
789 code = VOP_READ(tfile->vnode, &tuio, 0, &afs_osi_cred);
790 VOP_UNLOCK(tfile->vnode, 0, current_proc());
793 code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, &afs_osi_cred);
804 if (!tdc->ihint && nihints < maxIHint) {
817 /* otherwise we've read some, fixup length, etc and continue with next seg */
818 len = len - tuio.afsio_resid; /* compute amount really transferred */
820 afsio_skip(auio, trimlen); /* update input uio structure */
822 transferLength += len;
824 if (len <= 0) break; /* surprise eof */
827 /* if we make it here with tdc non-zero, then it is the last chunk we
828 * dealt with, and we have to release it when we're done. We hold on
829 * to it in case we need to do a prefetch, obviously.
832 #ifndef AFS_VM_RDWR_ENV
833 /* try to queue prefetch, if needed */
834 if (!(tdc->flags & DFNextStarted) && !noLock) {
835 afs_PrefetchChunk(avc, tdc, acred, &treq);
841 ReleaseReadLock(&avc->lock);
843 osi_FreeSmallSpace(tvec);
844 error = afs_CheckCode(error, &treq, 13);