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"
22 #include "afs/sysincludes.h" /* Standard vendor system headers */
23 #include "afsincludes.h" /* Afs-based standard headers */
24 #include "afs/afs_stats.h" /* statistics */
25 #include "afs/afs_cbqueue.h"
26 #include "afs/nfsclient.h"
27 #include "afs/afs_osidnlc.h"
28 #include "afs/afs_osi.h"
31 extern char afs_zeros
[AFS_ZEROS
];
33 /* Imported variables */
34 extern afs_rwlock_t afs_xdcache
;
35 extern unsigned char *afs_indexFlags
;
36 extern afs_hyper_t
*afs_indexTimes
; /* Dcache entry Access times */
37 extern afs_hyper_t afs_indexCounter
; /* Fake time for marking index */
40 /* Forward declarations */
41 void afs_PrefetchChunk(struct vcache
*avc
, struct dcache
*adc
,
42 afs_ucred_t
*acred
, struct vrequest
*areq
);
45 afs_read(struct vcache
*avc
, struct uio
*auio
, afs_ucred_t
*acred
,
48 afs_size_t totalLength
;
49 afs_size_t transferLength
;
51 afs_size_t offset
, tlen
;
54 struct dcache
*tdc
= 0;
55 afs_int32 error
, trybusy
= 1;
56 struct uio
*tuiop
= NULL
;
58 struct vrequest
*treq
= NULL
;
60 AFS_STATCNT(afs_read
);
67 /* check that we have the latest status info in the vnode cache */
68 if ((code
= afs_CreateReq(&treq
, acred
)))
73 osi_Panic("null avc in afs_GenericRead");
75 code
= afs_VerifyVCache(avc
, treq
);
77 code
= afs_CheckCode(code
, treq
, 8); /* failed to get it */
81 #ifndef AFS_VM_RDWR_ENV
82 if (AFS_NFSXLATORREQ(acred
)) {
84 (avc
, PRSFS_READ
, treq
,
85 CHECK_MODE_BITS
| CMB_ALLOW_EXEC_AS_READ
)) {
86 code
= afs_CheckCode(EACCES
, treq
, 9);
92 totalLength
= AFS_UIO_RESID(auio
);
93 filePos
= AFS_UIO_OFFSET(auio
);
94 afs_Trace4(afs_iclSetp
, CM_TRACE_READ
, ICL_TYPE_POINTER
, avc
,
95 ICL_TYPE_OFFSET
, ICL_HANDLE_OFFSET(filePos
), ICL_TYPE_INT32
,
96 totalLength
, ICL_TYPE_OFFSET
,
97 ICL_HANDLE_OFFSET(avc
->f
.m
.Length
));
101 ObtainReadLock(&avc
->lock
);
102 #if defined(AFS_TEXT_ENV) && !defined(AFS_VM_RDWR_ENV)
103 if (avc
->flushDV
.high
== AFS_MAXDV
&& avc
->flushDV
.low
== AFS_MAXDV
) {
104 hset(avc
->flushDV
, avc
->f
.m
.DataVersion
);
113 /* This bit is bogus. We're checking to see if the read goes past the
114 * end of the file. If so, we should be zeroing out all of the buffers
115 * that the client has passed into us (there is a danger that we may leak
116 * kernel memory if we do not). However, this behaviour is disabled by
117 * not setting len before this segment runs, and by setting len to 0
118 * immediately we enter it. In addition, we also need to check for a read
119 * which partially goes off the end of the file in the while loop below.
122 if (filePos
>= avc
->f
.m
.Length
) {
124 len
= sizeof(afs_zeros
); /* and in 0 buffer */
127 tuiop
= afsio_partialcopy(auio
, trimlen
);
128 AFS_UIOMOVE(afs_zeros
, trimlen
, UIO_READ
, tuiop
, code
);
131 while (avc
->f
.m
.Length
> 0 && totalLength
> 0) {
132 /* read all of the cached info */
133 if (filePos
>= avc
->f
.m
.Length
)
134 break; /* all done */
137 ReleaseReadLock(&tdc
->lock
);
140 tdc
= afs_FindDCache(avc
, filePos
);
142 ObtainReadLock(&tdc
->lock
);
143 offset
= filePos
- AFS_CHUNKTOBASE(tdc
->f
.chunk
);
144 len
= tdc
->validPos
- filePos
;
147 /* a tricky question: does the presence of the DFFetching flag
148 * mean that we're fetching the latest version of the file? No.
149 * The server could update the file as soon as the fetch responsible
150 * for the setting of the DFFetching flag completes.
152 * However, the presence of the DFFetching flag (visible under
153 * a dcache read lock since it is set and cleared only under a
154 * dcache write lock) means that we're fetching as good a version
155 * as was known to this client at the time of the last call to
156 * afs_VerifyVCache, since the latter updates the stat cache's
157 * m.DataVersion field under a vcache write lock, and from the
158 * time that the DFFetching flag goes on in afs_GetDCache (before
159 * the fetch starts), to the time it goes off (after the fetch
160 * completes), afs_GetDCache keeps at least a read lock on the
163 * This means that if the DFFetching flag is set, we can use that
164 * data for any reads that must come from the current version of
165 * the file (current == m.DataVersion).
167 * Another way of looking at this same point is this: if we're
168 * fetching some data and then try do an afs_VerifyVCache, the
169 * VerifyVCache operation will not complete until after the
170 * DFFetching flag is turned off and the dcache entry's f.versionNo
173 * Note, by the way, that if DFFetching is set,
174 * m.DataVersion > f.versionNo (the latter is not updated until
175 * after the fetch completes).
178 ReleaseReadLock(&tdc
->lock
);
179 afs_PutDCache(tdc
); /* before reusing tdc */
181 tdc
= afs_GetDCache(avc
, filePos
, treq
, &offset
, &len
, 2);
187 ObtainReadLock(&tdc
->lock
);
188 /* now, first try to start transfer, if we'll need the data. If
189 * data already coming, we don't need to do this, obviously. Type
190 * 2 requests never return a null dcache entry, btw.
192 if (!(tdc
->dflags
& DFFetching
)
193 && !hsame(avc
->f
.m
.DataVersion
, tdc
->f
.versionNo
)) {
194 /* have cache entry, it is not coming in now,
195 * and we'll need new data */
197 if (trybusy
&& !afs_BBusy()) {
199 /* daemon is not busy */
200 ObtainSharedLock(&tdc
->mflock
, 665);
201 if (!(tdc
->mflags
& DFFetchReq
)) {
202 /* start the daemon (may already be running, however) */
203 UpgradeSToWLock(&tdc
->mflock
, 666);
204 tdc
->mflags
|= DFFetchReq
;
205 bp
= afs_BQueue(BOP_FETCH
, avc
, B_DONTWAIT
, 0, acred
,
206 (afs_size_t
) filePos
, (afs_size_t
) 0,
209 /* Bkg table full; retry deadlocks */
210 tdc
->mflags
&= ~DFFetchReq
;
211 trybusy
= 0; /* Avoid bkg daemon since they're too busy */
212 ReleaseWriteLock(&tdc
->mflock
);
215 ConvertWToSLock(&tdc
->mflock
);
216 /* don't use bp pointer! */
219 ConvertSToRLock(&tdc
->mflock
);
220 while (!code
&& tdc
->mflags
& DFFetchReq
) {
221 afs_Trace4(afs_iclSetp
, CM_TRACE_DCACHEWAIT
,
222 ICL_TYPE_STRING
, __FILE__
, ICL_TYPE_INT32
,
223 __LINE__
, ICL_TYPE_POINTER
, tdc
,
224 ICL_TYPE_INT32
, tdc
->dflags
);
225 /* don't need waiting flag on this one */
226 ReleaseReadLock(&tdc
->mflock
);
227 ReleaseReadLock(&tdc
->lock
);
228 ReleaseReadLock(&avc
->lock
);
229 code
= afs_osi_SleepSig(&tdc
->validPos
);
230 ObtainReadLock(&avc
->lock
);
231 ObtainReadLock(&tdc
->lock
);
232 ObtainReadLock(&tdc
->mflock
);
234 ReleaseReadLock(&tdc
->mflock
);
241 /* now data may have started flowing in (if DFFetching is on). If
242 * data is now streaming in, then wait for some interesting stuff.
245 while (!code
&& (tdc
->dflags
& DFFetching
)
246 && tdc
->validPos
<= filePos
) {
247 /* too early: wait for DFFetching flag to vanish,
248 * or data to appear */
249 afs_Trace4(afs_iclSetp
, CM_TRACE_DCACHEWAIT
, ICL_TYPE_STRING
,
250 __FILE__
, ICL_TYPE_INT32
, __LINE__
,
251 ICL_TYPE_POINTER
, tdc
, ICL_TYPE_INT32
,
253 ReleaseReadLock(&tdc
->lock
);
254 ReleaseReadLock(&avc
->lock
);
255 code
= afs_osi_SleepSig(&tdc
->validPos
);
256 ObtainReadLock(&avc
->lock
);
257 ObtainReadLock(&tdc
->lock
);
263 /* fetching flag gone, data is here, or we never tried
264 * (BBusy for instance) */
265 if (tdc
->dflags
& DFFetching
) {
266 /* still fetching, some new data is here:
267 * compute length and offset */
268 offset
= filePos
- AFS_CHUNKTOBASE(tdc
->f
.chunk
);
269 len
= tdc
->validPos
- filePos
;
271 /* no longer fetching, verify data version
272 * (avoid new GetDCache call) */
273 if (hsame(avc
->f
.m
.DataVersion
, tdc
->f
.versionNo
)
274 && ((len
= tdc
->validPos
- filePos
) > 0)) {
275 offset
= filePos
- AFS_CHUNKTOBASE(tdc
->f
.chunk
);
277 /* don't have current data, so get it below */
278 afs_Trace3(afs_iclSetp
, CM_TRACE_VERSIONNO
,
279 ICL_TYPE_INT64
, ICL_HANDLE_OFFSET(filePos
),
280 ICL_TYPE_HYPER
, &avc
->f
.m
.DataVersion
,
281 ICL_TYPE_HYPER
, &tdc
->f
.versionNo
);
282 ReleaseReadLock(&tdc
->lock
);
289 /* If we get, it was not possible to start the
290 * background daemon. With flag == 1 afs_GetDCache
291 * does the FetchData rpc synchronously.
293 ReleaseReadLock(&avc
->lock
);
294 tdc
= afs_GetDCache(avc
, filePos
, treq
, &offset
, &len
, 1);
295 ObtainReadLock(&avc
->lock
);
297 ObtainReadLock(&tdc
->lock
);
301 afs_Trace3(afs_iclSetp
, CM_TRACE_VNODEREAD
, ICL_TYPE_POINTER
, tdc
,
302 ICL_TYPE_OFFSET
, ICL_HANDLE_OFFSET(offset
),
303 ICL_TYPE_OFFSET
, ICL_HANDLE_OFFSET(len
));
315 if (len
> totalLength
)
316 len
= totalLength
; /* will read len bytes */
317 if (len
<= 0) { /* shouldn't get here if DFFetching is on */
318 /* read past the end of a chunk, may not be at next chunk yet, and yet
319 * also not at eof, so may have to supply fake zeros */
320 len
= AFS_CHUNKTOSIZE(tdc
->f
.chunk
) - offset
; /* bytes left in chunk addr space */
321 if (len
> totalLength
)
322 len
= totalLength
; /* and still within xfr request */
323 tlen
= avc
->f
.m
.Length
- offset
; /* and still within file */
327 len
= sizeof(afs_zeros
); /* and in 0 buffer */
329 tuiop
= afsio_partialcopy(auio
, trimlen
);
330 AFS_UIOMOVE(afs_zeros
, trimlen
, UIO_READ
, tuiop
, code
);
336 /* get the data from the cache */
338 /* mung uio structure to be right for this transfer */
340 tuiop
= afsio_partialcopy(auio
, trimlen
);
341 AFS_UIO_SETOFFSET(tuiop
, offset
);
343 code
= (*(afs_cacheType
->vreadUIO
))(&tdc
->f
.inode
, tuiop
);
350 /* otherwise we've read some, fixup length, etc and continue with next seg */
351 len
= len
- AFS_UIO_RESID(tuiop
); /* compute amount really transferred */
353 afsio_skip(auio
, trimlen
); /* update input uio structure */
355 transferLength
+= len
;
359 break; /* surprise eof */
364 } /* the whole while loop */
369 * tdc->lock(R) if tdc
372 /* if we make it here with tdc non-zero, then it is the last chunk we
373 * dealt with, and we have to release it when we're done. We hold on
374 * to it in case we need to do a prefetch.
377 ReleaseReadLock(&tdc
->lock
);
378 #if !defined(AFS_VM_RDWR_ENV)
379 /* try to queue prefetch, if needed */
381 if (!(tdc
->mflags
&DFNextStarted
))
382 afs_PrefetchChunk(avc
, tdc
, acred
, treq
);
388 ReleaseReadLock(&avc
->lock
);
390 code
= afs_CheckCode(error
, treq
, 10);
397 afs_DestroyReq(treq
);
401 /* called with the dcache entry triggering the fetch, the vcache entry involved,
402 * and a vrequest for the read call. Marks the dcache entry as having already
403 * triggered a prefetch, starts the prefetch going and sets the DFFetchReq
404 * flag in the prefetched block, so that the next call to read knows to wait
405 * for the daemon to start doing things.
407 * This function must be called with the vnode at least read-locked, and
408 * no locks on the dcache, because it plays around with dcache entries.
411 afs_PrefetchChunk(struct vcache
*avc
, struct dcache
*adc
,
412 afs_ucred_t
*acred
, struct vrequest
*areq
)
416 afs_size_t j1
, j2
; /* junk vbls for GetDCache to trash */
418 offset
= adc
->f
.chunk
+ 1; /* next chunk we'll need */
419 offset
= AFS_CHUNKTOBASE(offset
); /* base of next chunk */
420 ObtainReadLock(&adc
->lock
);
421 ObtainSharedLock(&adc
->mflock
, 662);
422 if (offset
< avc
->f
.m
.Length
&& !(adc
->mflags
& DFNextStarted
)
426 UpgradeSToWLock(&adc
->mflock
, 663);
427 adc
->mflags
|= DFNextStarted
; /* we've tried to prefetch for this guy */
428 ReleaseWriteLock(&adc
->mflock
);
429 ReleaseReadLock(&adc
->lock
);
431 tdc
= afs_GetDCache(avc
, offset
, areq
, &j1
, &j2
, 2); /* type 2 never returns 0 */
433 * In disconnected mode, type 2 can return 0 because it doesn't
434 * make any sense to allocate a dcache we can never fill
439 ObtainSharedLock(&tdc
->mflock
, 651);
440 if (!(tdc
->mflags
& DFFetchReq
)) {
441 /* ask the daemon to do the work */
442 UpgradeSToWLock(&tdc
->mflock
, 652);
443 tdc
->mflags
|= DFFetchReq
; /* guaranteed to be cleared by BKG or GetDCache */
444 /* last parm (1) tells bkg daemon to do an afs_PutDCache when it is done,
445 * since we don't want to wait for it to finish before doing so ourselves.
447 bp
= afs_BQueue(BOP_FETCH
, avc
, B_DONTWAIT
, 0, acred
,
448 (afs_size_t
) offset
, (afs_size_t
) 1, tdc
,
449 (void *)0, (void *)0);
451 /* Bkg table full; just abort non-important prefetching to avoid deadlocks */
452 tdc
->mflags
&= ~DFFetchReq
;
453 ReleaseWriteLock(&tdc
->mflock
);
457 * DCLOCKXXX: This is a little sketchy, since someone else
458 * could have already started a prefetch.. In practice,
459 * this probably doesn't matter; at most it would cause an
460 * extra slot in the BKG table to be used up when someone
461 * prefetches this for the second time.
463 ObtainReadLock(&adc
->lock
);
464 ObtainWriteLock(&adc
->mflock
, 664);
465 adc
->mflags
&= ~DFNextStarted
;
466 ReleaseWriteLock(&adc
->mflock
);
467 ReleaseReadLock(&adc
->lock
);
469 ReleaseWriteLock(&tdc
->mflock
);
472 ReleaseSharedLock(&tdc
->mflock
);
476 ReleaseSharedLock(&adc
->mflock
);
477 ReleaseReadLock(&adc
->lock
);
482 afs_UFSReadUIO(afs_dcache_id_t
*cacheId
, struct uio
*tuiop
)
485 struct osi_file
*tfile
;
487 tfile
= (struct osi_file
*) osi_UFSOpen(cacheId
);
491 #if defined(AFS_AIX41_ENV)
494 VNOP_RDWR(tfile
->vnode
, UIO_READ
, FREAD
, tuiop
, NULL
, NULL
,
495 NULL
, afs_osi_credp
);
497 #elif defined(AFS_AIX32_ENV)
499 VNOP_RDWR(tfile
->vnode
, UIO_READ
, FREAD
, tuiop
, NULL
, NULL
);
500 /* Flush all JFS pages now for big performance gain in big file cases
501 * If we do something like this, must check to be sure that AFS file
502 * isn't mmapped... see afs_gn_map() for why.
505 if (tfile->vnode->v_gnode && tfile->vnode->v_gnode->gn_seg) {
506 any different ways to do similar things:
507 so far, the best performing one is #2, but #1 might match it if we
508 straighten out the confusion regarding which pages to flush. It
510 1. vm_flushp(tfile->vnode->v_gnode->gn_seg, 0, len/PAGESIZE - 1);
511 2. vm_releasep(tfile->vnode->v_gnode->gn_seg, offset/PAGESIZE,
512 (len + PAGESIZE-1)/PAGESIZE);
513 3. vms_inactive(tfile->vnode->v_gnode->gn_seg) Doesn't work correctly
514 4. vms_delete(tfile->vnode->v_gnode->gn_seg) probably also fails
515 tfile->vnode->v_gnode->gn_seg = NULL;
519 Unfortunately, this seems to cause frequent "cache corruption" episodes.
520 vm_releasep(tfile->vnode->v_gnode->gn_seg, offset/PAGESIZE,
521 (len + PAGESIZE-1)/PAGESIZE);
524 #elif defined(AFS_AIX_ENV)
526 VNOP_RDWR(tfile
->vnode
, UIO_READ
, FREAD
, (off_t
) & offset
,
527 tuiop
, NULL
, NULL
, -1);
528 #elif defined(AFS_SUN5_ENV)
530 #ifdef AFS_SUN510_ENV
531 VOP_RWLOCK(tfile
->vnode
, 0, NULL
);
532 code
= VOP_READ(tfile
->vnode
, tuiop
, 0, afs_osi_credp
, NULL
);
533 VOP_RWUNLOCK(tfile
->vnode
, 0, NULL
);
535 VOP_RWLOCK(tfile
->vnode
, 0);
536 code
= VOP_READ(tfile
->vnode
, tuiop
, 0, afs_osi_credp
);
537 VOP_RWUNLOCK(tfile
->vnode
, 0);
540 #elif defined(AFS_SGI_ENV)
542 AFS_VOP_RWLOCK(tfile
->vnode
, VRWLOCK_READ
);
543 AFS_VOP_READ(tfile
->vnode
, tuiop
, IO_ISLOCKED
, afs_osi_credp
,
545 AFS_VOP_RWUNLOCK(tfile
->vnode
, VRWLOCK_READ
);
547 #elif defined(AFS_HPUX100_ENV)
549 code
= VOP_RDWR(tfile
->vnode
, tuiop
, UIO_READ
, 0, afs_osi_credp
);
551 #elif defined(AFS_LINUX20_ENV)
553 code
= osi_rdwr(tfile
, tuiop
, UIO_READ
);
555 #elif defined(AFS_DARWIN80_ENV)
557 code
= VNOP_READ(tfile
->vnode
, tuiop
, 0, afs_osi_ctxtp
);
559 #elif defined(AFS_DARWIN_ENV)
561 VOP_LOCK(tfile
->vnode
, LK_EXCLUSIVE
, current_proc());
562 code
= VOP_READ(tfile
->vnode
, tuiop
, 0, afs_osi_credp
);
563 VOP_UNLOCK(tfile
->vnode
, 0, current_proc());
565 #elif defined(AFS_FBSD80_ENV)
567 VOP_LOCK(tfile
->vnode
, LK_EXCLUSIVE
);
568 code
= VOP_READ(tfile
->vnode
, tuiop
, 0, afs_osi_credp
);
569 VOP_UNLOCK(tfile
->vnode
, 0);
571 #elif defined(AFS_FBSD_ENV)
573 VOP_LOCK(tfile
->vnode
, LK_EXCLUSIVE
, curthread
);
574 code
= VOP_READ(tfile
->vnode
, tuiop
, 0, afs_osi_credp
);
575 VOP_UNLOCK(tfile
->vnode
, 0, curthread
);
577 #elif defined(AFS_NBSD_ENV)
578 tuiop
->uio_rw
= UIO_READ
;
580 VOP_LOCK(tfile
->vnode
, LK_EXCLUSIVE
);
581 code
= VOP_READ(tfile
->vnode
, tuiop
, 0, afs_osi_credp
);
582 # if defined(AFS_NBSD60_ENV)
583 VOP_UNLOCK(tfile
->vnode
);
585 VOP_UNLOCK(tfile
->vnode
, 0);
588 #elif defined(AFS_XBSD_ENV)
590 VOP_LOCK(tfile
->vnode
, LK_EXCLUSIVE
, curproc
);
591 code
= VOP_READ(tfile
->vnode
, tuiop
, 0, afs_osi_credp
);
592 VOP_UNLOCK(tfile
->vnode
, 0, curproc
);
595 code
= VOP_RDWR(tfile
->vnode
, tuiop
, UIO_READ
, 0, afs_osi_credp
);