2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
18 #include <afsconfig.h>
19 #include "afs/param.h"
24 #include "afs/sysincludes.h" /* Standard vendor system headers */
25 #include "afsincludes.h" /* Afs-based standard headers */
26 #include "afs/afs_stats.h" /* statistics */
27 #include "afs/afs_cbqueue.h"
28 #include "afs/nfsclient.h"
29 #include "afs/afs_osidnlc.h"
30 #include "afs/afs_osi.h"
33 extern char afs_zeros[AFS_ZEROS];
36 afs_int32 nihints; /* # of above actually in-use */
40 /* Imported variables */
41 extern afs_rwlock_t afs_xdcache;
42 extern unsigned char *afs_indexFlags;
43 extern afs_hyper_t *afs_indexTimes; /* Dcache entry Access times */
44 extern afs_hyper_t afs_indexCounter; /* Fake time for marking index */
47 /* Forward declarations */
48 void afs_PrefetchChunk(struct vcache *avc, struct dcache *adc,
49 struct AFS_UCRED *acred, struct vrequest *areq);
52 afs_MemRead(register struct vcache *avc, struct uio *auio,
53 struct AFS_UCRED *acred, daddr_t albn, struct buf **abpp,
56 afs_size_t totalLength;
57 afs_size_t transferLength;
59 afs_size_t offset, len, tlen;
61 struct dcache *tdc = 0;
62 afs_int32 error, trybusy = 1;
63 #ifdef AFS_DARWIN80_ENV
67 struct uio *tuiop = &tuio;
73 AFS_STATCNT(afs_MemRead);
77 /* check that we have the latest status info in the vnode cache */
78 if ((code = afs_InitReq(&treq, acred)))
81 code = afs_VerifyVCache(avc, &treq);
83 code = afs_CheckCode(code, &treq, 8); /* failed to get it */
87 #ifndef AFS_VM_RDWR_ENV
88 if (AFS_NFSXLATORREQ(acred)) {
90 (avc, PRSFS_READ, &treq,
91 CHECK_MODE_BITS | CMB_ALLOW_EXEC_AS_READ)) {
92 return afs_CheckCode(EACCES, &treq, 9);
97 #ifndef AFS_DARWIN80_ENV
98 tvec = (struct iovec *)osi_AllocSmallSpace(sizeof(struct iovec));
100 totalLength = AFS_UIO_RESID(auio);
101 filePos = AFS_UIO_OFFSET(auio);
102 afs_Trace4(afs_iclSetp, CM_TRACE_READ, ICL_TYPE_POINTER, avc,
103 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(filePos), ICL_TYPE_INT32,
104 totalLength, ICL_TYPE_OFFSET,
105 ICL_HANDLE_OFFSET(avc->m.Length));
109 ObtainReadLock(&avc->lock);
110 #if defined(AFS_TEXT_ENV) && !defined(AFS_VM_RDWR_ENV)
111 if (avc->flushDV.high == AFS_MAXDV && avc->flushDV.low == AFS_MAXDV) {
112 hset(avc->flushDV, avc->m.DataVersion);
120 while (totalLength > 0) {
121 /* read all of the cached info */
122 if (filePos >= avc->m.Length)
123 break; /* all done */
126 ReleaseReadLock(&tdc->lock);
129 tdc = afs_FindDCache(avc, filePos);
131 ObtainReadLock(&tdc->lock);
132 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
133 len = tdc->f.chunkBytes - offset;
136 /* a tricky question: does the presence of the DFFetching flag
137 * mean that we're fetching the latest version of the file? No.
138 * The server could update the file as soon as the fetch responsible
139 * for the setting of the DFFetching flag completes.
141 * However, the presence of the DFFetching flag (visible under
142 * a dcache read lock since it is set and cleared only under a
143 * dcache write lock) means that we're fetching as good a version
144 * as was known to this client at the time of the last call to
145 * afs_VerifyVCache, since the latter updates the stat cache's
146 * m.DataVersion field under a vcache write lock, and from the
147 * time that the DFFetching flag goes on in afs_GetDCache (before
148 * the fetch starts), to the time it goes off (after the fetch
149 * completes), afs_GetDCache keeps at least a read lock on the
152 * This means that if the DFFetching flag is set, we can use that
153 * data for any reads that must come from the current version of
154 * the file (current == m.DataVersion).
156 * Another way of looking at this same point is this: if we're
157 * fetching some data and then try do an afs_VerifyVCache, the
158 * VerifyVCache operation will not complete until after the
159 * DFFetching flag is turned off and the dcache entry's f.versionNo
162 * Note, by the way, that if DFFetching is set,
163 * m.DataVersion > f.versionNo (the latter is not updated until
164 * after the fetch completes).
167 ReleaseReadLock(&tdc->lock);
168 afs_PutDCache(tdc); /* before reusing tdc */
170 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 2);
171 ObtainReadLock(&tdc->lock);
172 /* now, first try to start transfer, if we'll need the data. If
173 * data already coming, we don't need to do this, obviously. Type
174 * 2 requests never return a null dcache entry, btw.
176 if (!(tdc->dflags & DFFetching)
177 && !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
178 /* have cache entry, it is not coming in now,
179 * and we'll need new data */
181 if (trybusy && !afs_BBusy()) {
183 /* daemon is not busy */
184 ObtainSharedLock(&tdc->mflock, 665);
185 if (!(tdc->mflags & DFFetchReq)) {
186 /* start the daemon (may already be running, however) */
187 UpgradeSToWLock(&tdc->mflock, 666);
188 tdc->mflags |= DFFetchReq;
189 bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
190 (afs_size_t) filePos, (afs_size_t) 0,
193 tdc->mflags &= ~DFFetchReq;
194 trybusy = 0; /* Avoid bkg daemon since they're too busy */
195 ReleaseWriteLock(&tdc->mflock);
198 ConvertWToSLock(&tdc->mflock);
199 /* don't use bp pointer! */
202 ConvertSToRLock(&tdc->mflock);
203 while (!code && tdc->mflags & DFFetchReq) {
204 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT,
205 ICL_TYPE_STRING, __FILE__, ICL_TYPE_INT32,
206 __LINE__, ICL_TYPE_POINTER, tdc,
207 ICL_TYPE_INT32, tdc->dflags);
208 /* don't need waiting flag on this one */
209 ReleaseReadLock(&tdc->mflock);
210 ReleaseReadLock(&tdc->lock);
211 ReleaseReadLock(&avc->lock);
212 code = afs_osi_SleepSig(&tdc->validPos);
213 ObtainReadLock(&avc->lock);
214 ObtainReadLock(&tdc->lock);
215 ObtainReadLock(&tdc->mflock);
217 ReleaseReadLock(&tdc->mflock);
224 /* now data may have started flowing in (if DFFetching is on). If
225 * data is now streaming in, then wait for some interesting stuff.
228 while (!code && (tdc->dflags & DFFetching)
229 && tdc->validPos <= filePos) {
230 /* too early: wait for DFFetching flag to vanish,
231 * or data to appear */
232 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
233 __FILE__, ICL_TYPE_INT32, __LINE__,
234 ICL_TYPE_POINTER, tdc, ICL_TYPE_INT32,
236 ReleaseReadLock(&tdc->lock);
237 ReleaseReadLock(&avc->lock);
238 code = afs_osi_SleepSig(&tdc->validPos);
239 ObtainReadLock(&avc->lock);
240 ObtainReadLock(&tdc->lock);
246 /* fetching flag gone, data is here, or we never tried
247 * (BBusy for instance) */
248 if (tdc->dflags & DFFetching) {
249 /* still fetching, some new data is here:
250 * compute length and offset */
251 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
252 len = tdc->validPos - filePos;
254 /* no longer fetching, verify data version
255 * (avoid new GetDCache call) */
256 if (hsame(avc->m.DataVersion, tdc->f.versionNo)
257 && ((len = tdc->validPos - filePos) > 0)) {
258 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
260 /* don't have current data, so get it below */
261 afs_Trace3(afs_iclSetp, CM_TRACE_VERSIONNO,
262 ICL_TYPE_INT64, ICL_HANDLE_OFFSET(filePos),
263 ICL_TYPE_HYPER, &avc->m.DataVersion,
264 ICL_TYPE_HYPER, &tdc->f.versionNo);
265 ReleaseReadLock(&tdc->lock);
272 /* If we get, it was not possible to start the
273 * background daemon. With flag == 1 afs_GetDCache
274 * does the FetchData rpc synchronously.
276 ReleaseReadLock(&avc->lock);
277 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 1);
278 ObtainReadLock(&avc->lock);
280 ObtainReadLock(&tdc->lock);
284 afs_Trace3(afs_iclSetp, CM_TRACE_VNODEREAD, ICL_TYPE_POINTER, tdc,
285 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(offset),
286 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(len));
298 if (len > totalLength)
299 len = totalLength; /* will read len bytes */
300 if (len <= 0) { /* shouldn't get here if DFFetching is on */
301 /* read past the end of a chunk, may not be at next chunk yet, and yet
302 * also not at eof, so may have to supply fake zeros */
303 len = AFS_CHUNKTOSIZE(tdc->f.chunk) - offset; /* bytes left in chunk addr space */
304 if (len > totalLength)
305 len = totalLength; /* and still within xfr request */
306 tlen = avc->m.Length - offset; /* and still within file */
310 len = sizeof(afs_zeros); /* and in 0 buffer */
311 #ifdef AFS_DARWIN80_ENV
313 tuiop = afsio_darwin_partialcopy(auio, trimlen);
315 afsio_copy(auio, &tuio, tvec);
317 afsio_trim(&tuio, trimlen);
319 AFS_UIOMOVE(afs_zeros, trimlen, UIO_READ, tuiop, code);
325 /* get the data from the mem cache */
327 /* mung uio structure to be right for this transfer */
328 #ifdef AFS_DARWIN80_ENV
330 tuiop = afsio_darwin_partialcopy(auio, trimlen);
331 uio_setoffset(tuiop, offset);
333 afsio_copy(auio, &tuio, tvec);
335 afsio_trim(&tuio, trimlen);
336 tuio.afsio_offset = offset;
339 code = afs_MemReadUIO(tdc->f.inode, tuiop);
346 /* otherwise we've read some, fixup length, etc and continue with next seg */
347 len = len - AFS_UIO_RESID(tuiop); /* compute amount really transferred */
349 afsio_skip(auio, trimlen); /* update input uio structure */
351 transferLength += len;
355 break; /* surprise eof */
356 } /* the whole while loop */
361 * tdc->lock(R) if tdc
364 /* if we make it here with tdc non-zero, then it is the last chunk we
365 * dealt with, and we have to release it when we're done. We hold on
366 * to it in case we need to do a prefetch.
369 ReleaseReadLock(&tdc->lock);
370 #if !defined(AFS_VM_RDWR_ENV)
371 /* try to queue prefetch, if needed */
373 afs_PrefetchChunk(avc, tdc, acred, &treq);
379 ReleaseReadLock(&avc->lock);
380 #ifdef AFS_DARWIN80_ENV
383 osi_FreeSmallSpace(tvec);
385 error = afs_CheckCode(error, &treq, 10);
389 /* called with the dcache entry triggering the fetch, the vcache entry involved,
390 * and a vrequest for the read call. Marks the dcache entry as having already
391 * triggered a prefetch, starts the prefetch going and sets the DFFetchReq
392 * flag in the prefetched block, so that the next call to read knows to wait
393 * for the daemon to start doing things.
395 * This function must be called with the vnode at least read-locked, and
396 * no locks on the dcache, because it plays around with dcache entries.
399 afs_PrefetchChunk(struct vcache *avc, struct dcache *adc,
400 struct AFS_UCRED *acred, struct vrequest *areq)
402 register struct dcache *tdc;
404 afs_size_t j1, j2; /* junk vbls for GetDCache to trash */
406 offset = adc->f.chunk + 1; /* next chunk we'll need */
407 offset = AFS_CHUNKTOBASE(offset); /* base of next chunk */
408 ObtainReadLock(&adc->lock);
409 ObtainSharedLock(&adc->mflock, 662);
410 if (offset < avc->m.Length && !(adc->mflags & DFNextStarted)
414 UpgradeSToWLock(&adc->mflock, 663);
415 adc->mflags |= DFNextStarted; /* we've tried to prefetch for this guy */
416 ReleaseWriteLock(&adc->mflock);
417 ReleaseReadLock(&adc->lock);
419 tdc = afs_GetDCache(avc, offset, areq, &j1, &j2, 2); /* type 2 never returns 0 */
420 ObtainSharedLock(&tdc->mflock, 651);
421 if (!(tdc->mflags & DFFetchReq)) {
422 /* ask the daemon to do the work */
423 UpgradeSToWLock(&tdc->mflock, 652);
424 tdc->mflags |= DFFetchReq; /* guaranteed to be cleared by BKG or GetDCache */
425 /* last parm (1) tells bkg daemon to do an afs_PutDCache when it is done,
426 * since we don't want to wait for it to finish before doing so ourselves.
428 bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
429 (afs_size_t) offset, (afs_size_t) 1, tdc);
431 /* Bkg table full; just abort non-important prefetching to avoid deadlocks */
432 tdc->mflags &= ~DFFetchReq;
433 ReleaseWriteLock(&tdc->mflock);
437 * DCLOCKXXX: This is a little sketchy, since someone else
438 * could have already started a prefetch.. In practice,
439 * this probably doesn't matter; at most it would cause an
440 * extra slot in the BKG table to be used up when someone
441 * prefetches this for the second time.
443 ObtainReadLock(&adc->lock);
444 ObtainWriteLock(&adc->mflock, 664);
445 adc->mflags &= ~DFNextStarted;
446 ReleaseWriteLock(&adc->mflock);
447 ReleaseReadLock(&adc->lock);
449 ReleaseWriteLock(&tdc->mflock);
452 ReleaseSharedLock(&tdc->mflock);
456 ReleaseSharedLock(&adc->mflock);
457 ReleaseReadLock(&adc->lock);
462 afs_UFSRead(register struct vcache *avc, struct uio *auio,
463 struct AFS_UCRED *acred, daddr_t albn, struct buf **abpp,
466 afs_size_t totalLength;
467 afs_size_t transferLength;
469 afs_size_t offset, len, tlen;
471 struct dcache *tdc = 0;
473 #ifdef AFS_DARWIN80_ENV
477 struct uio *tuiop = &tuio;
480 struct osi_file *tfile;
483 struct vrequest treq;
485 AFS_STATCNT(afs_UFSRead);
486 if (avc && avc->vc_error)
489 /* check that we have the latest status info in the vnode cache */
490 if ((code = afs_InitReq(&treq, acred)))
494 osi_Panic("null avc in afs_UFSRead");
496 code = afs_VerifyVCache(avc, &treq);
498 code = afs_CheckCode(code, &treq, 11); /* failed to get it */
503 #ifndef AFS_VM_RDWR_ENV
504 if (AFS_NFSXLATORREQ(acred)) {
506 (avc, PRSFS_READ, &treq,
507 CHECK_MODE_BITS | CMB_ALLOW_EXEC_AS_READ)) {
508 return afs_CheckCode(EACCES, &treq, 12);
513 #ifndef AFS_DARWIN80_ENV
514 tvec = (struct iovec *)osi_AllocSmallSpace(sizeof(struct iovec));
516 totalLength = AFS_UIO_RESID(auio);
517 filePos = AFS_UIO_OFFSET(auio);
518 afs_Trace4(afs_iclSetp, CM_TRACE_READ, ICL_TYPE_POINTER, avc,
519 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(filePos), ICL_TYPE_INT32,
520 totalLength, ICL_TYPE_OFFSET,
521 ICL_HANDLE_OFFSET(avc->m.Length));
525 ObtainReadLock(&avc->lock);
526 #if defined(AFS_TEXT_ENV) && !defined(AFS_VM_RDWR_ENV)
527 if (avc->flushDV.high == AFS_MAXDV && avc->flushDV.low == AFS_MAXDV) {
528 hset(avc->flushDV, avc->m.DataVersion);
532 while (totalLength > 0) {
533 /* read all of the cached info */
534 if (filePos >= avc->m.Length)
535 break; /* all done */
538 ReleaseReadLock(&tdc->lock);
541 tdc = afs_FindDCache(avc, filePos);
543 ObtainReadLock(&tdc->lock);
544 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
545 len = tdc->validPos - filePos;
548 /* a tricky question: does the presence of the DFFetching flag
549 * mean that we're fetching the latest version of the file? No.
550 * The server could update the file as soon as the fetch responsible
551 * for the setting of the DFFetching flag completes.
553 * However, the presence of the DFFetching flag (visible under
554 * a dcache read lock since it is set and cleared only under a
555 * dcache write lock) means that we're fetching as good a version
556 * as was known to this client at the time of the last call to
557 * afs_VerifyVCache, since the latter updates the stat cache's
558 * m.DataVersion field under a vcache write lock, and from the
559 * time that the DFFetching flag goes on in afs_GetDCache (before
560 * the fetch starts), to the time it goes off (after the fetch
561 * completes), afs_GetDCache keeps at least a read lock on the
564 * This means that if the DFFetching flag is set, we can use that
565 * data for any reads that must come from the current version of
566 * the file (current == m.DataVersion).
568 * Another way of looking at this same point is this: if we're
569 * fetching some data and then try do an afs_VerifyVCache, the
570 * VerifyVCache operation will not complete until after the
571 * DFFetching flag is turned off and the dcache entry's f.versionNo
574 * Note, by the way, that if DFFetching is set,
575 * m.DataVersion > f.versionNo (the latter is not updated until
576 * after the fetch completes).
579 ReleaseReadLock(&tdc->lock);
580 afs_PutDCache(tdc); /* before reusing tdc */
582 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 2);
583 ObtainReadLock(&tdc->lock);
584 /* now, first try to start transfer, if we'll need the data. If
585 * data already coming, we don't need to do this, obviously. Type
586 * 2 requests never return a null dcache entry, btw. */
587 if (!(tdc->dflags & DFFetching)
588 && !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
589 /* have cache entry, it is not coming in now, and we'll need new data */
591 if (trybusy && !afs_BBusy()) {
593 /* daemon is not busy */
594 ObtainSharedLock(&tdc->mflock, 667);
595 if (!(tdc->mflags & DFFetchReq)) {
596 UpgradeSToWLock(&tdc->mflock, 668);
597 tdc->mflags |= DFFetchReq;
598 bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
599 (afs_size_t) filePos, (afs_size_t) 0,
602 /* Bkg table full; retry deadlocks */
603 tdc->mflags &= ~DFFetchReq;
604 trybusy = 0; /* Avoid bkg daemon since they're too busy */
605 ReleaseWriteLock(&tdc->mflock);
608 ConvertWToSLock(&tdc->mflock);
611 ConvertSToRLock(&tdc->mflock);
612 while (!code && tdc->mflags & DFFetchReq) {
613 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT,
614 ICL_TYPE_STRING, __FILE__, ICL_TYPE_INT32,
615 __LINE__, ICL_TYPE_POINTER, tdc,
616 ICL_TYPE_INT32, tdc->dflags);
617 /* don't need waiting flag on this one */
618 ReleaseReadLock(&tdc->mflock);
619 ReleaseReadLock(&tdc->lock);
620 ReleaseReadLock(&avc->lock);
621 code = afs_osi_SleepSig(&tdc->validPos);
622 ObtainReadLock(&avc->lock);
623 ObtainReadLock(&tdc->lock);
624 ObtainReadLock(&tdc->mflock);
626 ReleaseReadLock(&tdc->mflock);
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.
637 while (!code && (tdc->dflags & DFFetching)
638 && tdc->validPos <= filePos) {
639 /* too early: wait for DFFetching flag to vanish,
640 * or data to appear */
641 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
642 __FILE__, ICL_TYPE_INT32, __LINE__,
643 ICL_TYPE_POINTER, tdc, ICL_TYPE_INT32,
645 ReleaseReadLock(&tdc->lock);
646 ReleaseReadLock(&avc->lock);
647 code = afs_osi_SleepSig(&tdc->validPos);
648 ObtainReadLock(&avc->lock);
649 ObtainReadLock(&tdc->lock);
655 /* fetching flag gone, data is here, or we never tried
656 * (BBusy for instance) */
657 if (tdc->dflags & DFFetching) {
658 /* still fetching, some new data is here:
659 * compute length and offset */
660 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
661 len = tdc->validPos - filePos;
663 /* no longer fetching, verify data version (avoid new
665 if (hsame(avc->m.DataVersion, tdc->f.versionNo)
666 && ((len = tdc->validPos - filePos) > 0)) {
667 offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
669 /* don't have current data, so get it below */
670 afs_Trace3(afs_iclSetp, CM_TRACE_VERSIONNO,
671 ICL_TYPE_INT64, ICL_HANDLE_OFFSET(filePos),
672 ICL_TYPE_HYPER, &avc->m.DataVersion,
673 ICL_TYPE_HYPER, &tdc->f.versionNo);
674 ReleaseReadLock(&tdc->lock);
681 /* If we get, it was not possible to start the
682 * background daemon. With flag == 1 afs_GetDCache
683 * does the FetchData rpc synchronously.
685 ReleaseReadLock(&avc->lock);
686 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 1);
687 ObtainReadLock(&avc->lock);
689 ObtainReadLock(&tdc->lock);
697 len = tdc->validPos - filePos;
698 afs_Trace3(afs_iclSetp, CM_TRACE_VNODEREAD, ICL_TYPE_POINTER, tdc,
699 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(offset),
700 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(len));
701 if (len > totalLength)
702 len = totalLength; /* will read len bytes */
703 if (len <= 0) { /* shouldn't get here if DFFetching is on */
704 afs_Trace4(afs_iclSetp, CM_TRACE_VNODEREAD2, ICL_TYPE_POINTER,
705 tdc, ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(tdc->validPos),
706 ICL_TYPE_INT32, tdc->f.chunkBytes, ICL_TYPE_INT32,
708 /* read past the end of a chunk, may not be at next chunk yet, and yet
709 * also not at eof, so may have to supply fake zeros */
710 len = AFS_CHUNKTOSIZE(tdc->f.chunk) - offset; /* bytes left in chunk addr space */
711 if (len > totalLength)
712 len = totalLength; /* and still within xfr request */
713 tlen = avc->m.Length - offset; /* and still within file */
717 len = sizeof(afs_zeros); /* and in 0 buffer */
718 #ifdef AFS_DARWIN80_ENV
720 tuiop = afsio_darwin_partialcopy(auio, trimlen);
722 afsio_copy(auio, &tuio, tvec);
724 afsio_trim(&tuio, trimlen);
726 AFS_UIOMOVE(afs_zeros, trimlen, UIO_READ, tuiop, code);
732 /* get the data from the file */
734 if (tfile = tdc->ihint) {
735 if (tdc->f.inode != tfile->inum) {
736 afs_warn("afs_UFSRead: %x hint mismatch tdc %d inum %d\n",
737 tdc, tdc->f.inode, tfile->inum);
739 tdc->ihint = tfile = 0;
748 tfile = (struct osi_file *)osi_UFSOpen(tdc->f.inode);
749 #ifdef AFS_DARWIN80_ENV
751 tuiop = afsio_darwin_partialcopy(auio, trimlen);
752 uio_setoffset(tuiop, offset);
754 /* mung uio structure to be right for this transfer */
755 afsio_copy(auio, &tuio, tvec);
757 afsio_trim(&tuio, trimlen);
758 tuio.afsio_offset = offset;
761 #if defined(AFS_AIX41_ENV)
764 VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, &tuio, NULL, NULL,
765 NULL, afs_osi_credp);
767 #elif defined(AFS_AIX32_ENV)
769 VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, &tuio, NULL, NULL);
770 /* Flush all JFS pages now for big performance gain in big file cases
771 * If we do something like this, must check to be sure that AFS file
772 * isn't mmapped... see afs_gn_map() for why.
775 if (tfile->vnode->v_gnode && tfile->vnode->v_gnode->gn_seg) {
776 many different ways to do similar things:
777 so far, the best performing one is #2, but #1 might match it if we
778 straighten out the confusion regarding which pages to flush. It
780 1. vm_flushp(tfile->vnode->v_gnode->gn_seg, 0, len/PAGESIZE - 1);
781 2. vm_releasep(tfile->vnode->v_gnode->gn_seg, offset/PAGESIZE,
782 (len + PAGESIZE-1)/PAGESIZE);
783 3. vms_inactive(tfile->vnode->v_gnode->gn_seg) Doesn't work correctly
784 4. vms_delete(tfile->vnode->v_gnode->gn_seg) probably also fails
785 tfile->vnode->v_gnode->gn_seg = NULL;
789 Unfortunately, this seems to cause frequent "cache corruption" episodes.
790 vm_releasep(tfile->vnode->v_gnode->gn_seg, offset/PAGESIZE,
791 (len + PAGESIZE-1)/PAGESIZE);
794 #elif defined(AFS_AIX_ENV)
796 VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, (off_t) & offset,
797 &tuio, NULL, NULL, -1);
798 #elif defined(AFS_SUN5_ENV)
800 #ifdef AFS_SUN510_ENV
804 VOP_RWLOCK(tfile->vnode, 0, &ct);
805 code = VOP_READ(tfile->vnode, &tuio, 0, afs_osi_credp, &ct);
806 VOP_RWUNLOCK(tfile->vnode, 0, &ct);
809 VOP_RWLOCK(tfile->vnode, 0);
810 code = VOP_READ(tfile->vnode, &tuio, 0, afs_osi_credp);
811 VOP_RWUNLOCK(tfile->vnode, 0);
814 #elif defined(AFS_SGI_ENV)
816 AFS_VOP_RWLOCK(tfile->vnode, VRWLOCK_READ);
817 AFS_VOP_READ(tfile->vnode, &tuio, IO_ISLOCKED, afs_osi_credp,
819 AFS_VOP_RWUNLOCK(tfile->vnode, VRWLOCK_READ);
821 #elif defined(AFS_OSF_ENV)
822 tuio.uio_rw = UIO_READ;
824 VOP_READ(tfile->vnode, &tuio, 0, afs_osi_credp, code);
826 #elif defined(AFS_HPUX100_ENV)
828 code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, afs_osi_credp);
830 #elif defined(AFS_LINUX20_ENV)
832 code = osi_rdwr(tfile, &tuio, UIO_READ);
834 #elif defined(AFS_DARWIN_ENV)
836 VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, current_proc());
837 code = VOP_READ(tfile->vnode, &tuio, 0, afs_osi_credp);
838 VOP_UNLOCK(tfile->vnode, 0, current_proc());
840 #elif defined(AFS_DARWIN80_ENV)
842 code = VOP_READ(tfile->vnode, tuiop, 0, afs_osi_ctxp);
844 #elif defined(AFS_DARWIN_ENV)
846 VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, current_proc());
847 code = VOP_READ(tfile->vnode, &tuio, 0, afs_osi_credp);
848 VOP_UNLOCK(tfile->vnode, 0, current_proc());
850 #elif defined(AFS_FBSD50_ENV)
852 VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, curthread);
853 code = VOP_READ(tfile->vnode, &tuio, 0, afs_osi_credp);
854 VOP_UNLOCK(tfile->vnode, 0, curthread);
856 #elif defined(AFS_XBSD_ENV)
858 VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, curproc);
859 code = VOP_READ(tfile->vnode, &tuio, 0, afs_osi_credp);
860 VOP_UNLOCK(tfile->vnode, 0, curproc);
863 code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, afs_osi_credp);
867 if (!tdc->ihint && nihints < maxIHint) {
879 /* otherwise we've read some, fixup length, etc and continue with next seg */
880 len = len - AFS_UIO_RESID(tuiop); /* compute amount really transferred */
882 afsio_skip(auio, trimlen); /* update input uio structure */
884 transferLength += len;
887 break; /* surprise eof */
890 /* if we make it here with tdc non-zero, then it is the last chunk we
891 * dealt with, and we have to release it when we're done. We hold on
892 * to it in case we need to do a prefetch, obviously.
895 ReleaseReadLock(&tdc->lock);
896 #if !defined(AFS_VM_RDWR_ENV)
897 /* try to queue prefetch, if needed */
899 if (!(tdc->mflags & DFNextStarted))
900 afs_PrefetchChunk(avc, tdc, acred, &treq);
906 ReleaseReadLock(&avc->lock);
908 #ifdef AFS_DARWIN80_ENV
911 osi_FreeSmallSpace(tvec);
913 error = afs_CheckCode(error, &treq, 13);