diff options
author | delphij <delphij@FreeBSD.org> | 2009-09-28 16:59:47 +0000 |
---|---|---|
committer | delphij <delphij@FreeBSD.org> | 2009-09-28 16:59:47 +0000 |
commit | 79f2f8c774b48d4ef62f92d4a09e80af3ceaca7c (patch) | |
tree | 1cca7c0ea10e2ad0213a1d75a2c8a8fe0061f4d4 /sys/kern | |
parent | fd5f08e3e82b6caa8a7fff6a32c9e56b9212003e (diff) | |
download | FreeBSD-src-79f2f8c774b48d4ef62f92d4a09e80af3ceaca7c.zip FreeBSD-src-79f2f8c774b48d4ef62f92d4a09e80af3ceaca7c.tar.gz |
Add two new fcntls to enable/disable read-ahead:
- F_READAHEAD: specify the amount for sequential access. The amount is
specified in bytes and is rounded up to nearest block size.
- F_RDAHEAD: Darwin compatible version that use 128KB as the sequential
access size.
A third argument of zero disables the read-ahead behavior.
Please note that the read-ahead amount is also constrainted by sysctl
variable, vfs.read_max, which may need to be raised in order to better
utilize this feature.
Thanks Igor Sysoev for proposing the feature and submitting the original
version, and kib@ for his valuable comments.
Submitted by: Igor Sysoev <is rambler-co ru>
Reviewed by: kib@
MFC after: 1 month
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/kern_descrip.c | 44 | ||||
-rw-r--r-- | sys/kern/vfs_vnops.c | 3 |
2 files changed, 47 insertions, 0 deletions
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index 91733db..434f54a 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -421,6 +421,8 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) struct vnode *vp; int error, flg, tmp; int vfslocked; + u_int old, new; + uint64_t bsize; vfslocked = 0; error = 0; @@ -686,6 +688,48 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) vfslocked = 0; fdrop(fp, td); break; + + case F_RDAHEAD: + arg = arg ? 128 * 1024: 0; + /* FALLTHROUGH */ + case F_READAHEAD: + FILEDESC_SLOCK(fdp); + if ((fp = fdtofp(fd, fdp)) == NULL) { + FILEDESC_SUNLOCK(fdp); + error = EBADF; + break; + } + if (fp->f_type != DTYPE_VNODE) { + FILEDESC_SUNLOCK(fdp); + error = EBADF; + break; + } + fhold(fp); + FILEDESC_SUNLOCK(fdp); + if (arg != 0) { + vp = fp->f_vnode; + vfslocked = VFS_LOCK_GIANT(vp->v_mount); + error = vn_lock(vp, LK_SHARED); + if (error != 0) + goto readahead_vnlock_fail; + bsize = fp->f_vnode->v_mount->mnt_stat.f_iosize; + VOP_UNLOCK(vp, 0); + fp->f_seqcount = (arg + bsize - 1) / bsize; + do { + new = old = fp->f_flag; + new |= FRDAHEAD; + } while (atomic_cmpset_rel_int(&fp->f_flag, old, new) == 0); +readahead_vnlock_fail: + VFS_UNLOCK_GIANT(vfslocked); + } else { + do { + new = old = fp->f_flag; + new &= ~FRDAHEAD; + } while (atomic_cmpset_rel_int(&fp->f_flag, old, new) == 0); + } + fdrop(fp, td); + break; + default: error = EINVAL; break; diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index 1b77352..03e8d93 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -312,6 +312,9 @@ static int sequential_heuristic(struct uio *uio, struct file *fp) { + if (atomic_load_acq_int(&(fp->f_flag)) & FRDAHEAD) + return (fp->f_seqcount << IO_SEQSHIFT); + /* * Offset 0 is handled specially. open() sets f_seqcount to 1 so * that the first I/O is normally considered to be slightly |