summaryrefslogtreecommitdiffstats
path: root/sys/fs
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>1999-10-04 11:23:10 +0000
committerphk <phk@FreeBSD.org>1999-10-04 11:23:10 +0000
commit8b06d6a2fb370e84bcaea363717c70eaa36c7408 (patch)
treee4bc785f7af7f745b073ce17e028b224e9c0f43a /sys/fs
parent32722204f79ff5877e53e1620b0f2a915dba2c2f (diff)
downloadFreeBSD-src-8b06d6a2fb370e84bcaea363717c70eaa36c7408.zip
FreeBSD-src-8b06d6a2fb370e84bcaea363717c70eaa36c7408.tar.gz
Move the buffered read/write code out of spec_{read|write} and into
two new functions spec_buf{read|write}. Add sysctl vfs.bdev_buffered which defaults to 1 == true. This sysctl can be used to experimentally turn buffered behaviour for bdevs off. I should not be changed while any blockdevices are open. Remove the misplaced sysctl vfs.enable_userblk_io. No other changes in behaviour.
Diffstat (limited to 'sys/fs')
-rw-r--r--sys/fs/specfs/spec_vnops.c391
1 files changed, 210 insertions, 181 deletions
diff --git a/sys/fs/specfs/spec_vnops.c b/sys/fs/specfs/spec_vnops.c
index f3e264c..3ee0f0b 100644
--- a/sys/fs/specfs/spec_vnops.c
+++ b/sys/fs/specfs/spec_vnops.c
@@ -46,6 +46,7 @@
#include <sys/fcntl.h>
#include <sys/disklabel.h>
#include <sys/vmmeter.h>
+#include <sys/sysctl.h>
#include <sys/tty.h>
#include <vm/vm.h>
@@ -70,8 +71,10 @@ static int spec_open __P((struct vop_open_args *));
static int spec_poll __P((struct vop_poll_args *));
static int spec_print __P((struct vop_print_args *));
static int spec_read __P((struct vop_read_args *));
+static int spec_bufread __P((struct vop_read_args *));
static int spec_strategy __P((struct vop_strategy_args *));
static int spec_write __P((struct vop_write_args *));
+static int spec_bufwrite __P((struct vop_write_args *));
vop_t **spec_vnodeop_p;
static struct vnodeopv_entry_desc spec_vnodeop_entries[] = {
@@ -114,6 +117,8 @@ static struct vnodeopv_desc spec_vnodeop_opv_desc =
VNODEOP_SET(spec_vnodeop_opv_desc);
+static int bdev_buffered = 1;
+SYSCTL_INT(_vfs, OID_AUTO, bdev_buffered, CTLFLAG_RW, &bdev_buffered, 0, "");
int
spec_vnoperate(ap)
@@ -159,7 +164,7 @@ spec_open(ap)
struct proc *p = ap->a_p;
struct vnode *bvp, *vp = ap->a_vp;
dev_t bdev, dev = vp->v_rdev;
- int error, maxio;
+ int error;
struct cdevsw *dsw;
/*
@@ -267,18 +272,10 @@ spec_read(ap)
struct ucred *a_cred;
} */ *ap;
{
- register struct vnode *vp = ap->a_vp;
- register struct uio *uio = ap->a_uio;
+ struct vnode *vp = ap->a_vp;
+ struct uio *uio = ap->a_uio;
struct proc *p = uio->uio_procp;
- struct buf *bp;
- daddr_t bn, nextbn;
- long bsize, bscale;
- struct partinfo dpart;
- int n, on;
- d_ioctl_t *ioctl;
int error = 0;
- int seqcount = ap->a_ioflag >> 16;
- dev_t dev;
#ifdef DIAGNOSTIC
if (uio->uio_rw != UIO_READ)
@@ -289,83 +286,103 @@ spec_read(ap)
if (uio->uio_resid == 0)
return (0);
- switch (vp->v_type) {
-
- case VCHR:
+ if (vp->v_type == VCHR || (bdev_buffered == 0)) {
VOP_UNLOCK(vp, 0, p);
error = (*devsw(vp->v_rdev)->d_read)
(vp->v_rdev, uio, ap->a_ioflag);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
return (error);
+ } else {
+ return (spec_bufread(ap));
+ }
+}
- case VBLK:
- if (enable_userblk_io == 0)
- return (EINVAL);
- if (uio->uio_offset < 0)
- return (EINVAL);
- dev = vp->v_rdev;
- /*
- * Calculate block size for block device. The block size must
- * be larger then the physical minimum.
- */
+/* Vnode op for buffered read */
+/* ARGSUSED */
+static int
+spec_bufread(ap)
+ struct vop_read_args /* {
+ struct vnode *a_vp;
+ struct uio *a_uio;
+ int a_ioflag;
+ struct ucred *a_cred;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+ struct uio *uio = ap->a_uio;
+ struct proc *p = uio->uio_procp;
+ struct buf *bp;
+ daddr_t bn, nextbn;
+ long bsize, bscale;
+ struct partinfo dpart;
+ int n, on;
+ d_ioctl_t *ioctl;
+ int error = 0;
+ int seqcount = ap->a_ioflag >> 16;
+ dev_t dev;
- bsize = vp->v_rdev->si_bsize_best;
- if (bsize < vp->v_rdev->si_bsize_phys)
- bsize = vp->v_rdev->si_bsize_phys;
- if (bsize < BLKDEV_IOSIZE)
- bsize = BLKDEV_IOSIZE;
+ if (uio->uio_offset < 0)
+ return (EINVAL);
+ dev = vp->v_rdev;
- if ((ioctl = devsw(dev)->d_ioctl) != NULL &&
- (*ioctl)(dev, DIOCGPART, (caddr_t)&dpart, FREAD, p) == 0 &&
- dpart.part->p_fstype == FS_BSDFFS &&
- dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
- bsize = dpart.part->p_frag * dpart.part->p_fsize;
- bscale = btodb(bsize);
- do {
- bn = btodb(uio->uio_offset) & ~(bscale - 1);
- on = uio->uio_offset % bsize;
- if (seqcount > 1) {
- nextbn = bn + bscale;
- error = breadn(vp, bn, (int)bsize, &nextbn,
- (int *)&bsize, 1, NOCRED, &bp);
- } else {
- error = bread(vp, bn, (int)bsize, NOCRED, &bp);
- }
+ /*
+ * Calculate block size for block device. The block size must
+ * be larger then the physical minimum.
+ */
- /*
- * Figure out how much of the buffer is valid relative
- * to our offset into the buffer, which may be negative
- * if we are beyond the EOF.
- *
- * The valid size of the buffer is based on
- * bp->b_bcount (which may have been truncated by
- * dscheck or the device) minus bp->b_resid, which
- * may be indicative of an I/O error if non-zero.
- */
- if (error == 0) {
- n = bp->b_bcount - on;
- if (n < 0) {
- error = EINVAL;
- } else {
- n = min(n, bp->b_bcount - bp->b_resid - on);
- if (n < 0)
- error = EIO;
- }
- }
- if (error) {
- brelse(bp);
- return (error);
+ bsize = vp->v_rdev->si_bsize_best;
+ if (bsize < vp->v_rdev->si_bsize_phys)
+ bsize = vp->v_rdev->si_bsize_phys;
+ if (bsize < BLKDEV_IOSIZE)
+ bsize = BLKDEV_IOSIZE;
+
+ if ((ioctl = devsw(dev)->d_ioctl) != NULL &&
+ (*ioctl)(dev, DIOCGPART, (caddr_t)&dpart, FREAD, p) == 0 &&
+ dpart.part->p_fstype == FS_BSDFFS &&
+ dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
+ bsize = dpart.part->p_frag * dpart.part->p_fsize;
+ bscale = btodb(bsize);
+ do {
+ bn = btodb(uio->uio_offset) & ~(bscale - 1);
+ on = uio->uio_offset % bsize;
+ if (seqcount > 1) {
+ nextbn = bn + bscale;
+ error = breadn(vp, bn, (int)bsize, &nextbn,
+ (int *)&bsize, 1, NOCRED, &bp);
+ } else {
+ error = bread(vp, bn, (int)bsize, NOCRED, &bp);
+ }
+
+ /*
+ * Figure out how much of the buffer is valid relative
+ * to our offset into the buffer, which may be negative
+ * if we are beyond the EOF.
+ *
+ * The valid size of the buffer is based on
+ * bp->b_bcount (which may have been truncated by
+ * dscheck or the device) minus bp->b_resid, which
+ * may be indicative of an I/O error if non-zero.
+ */
+ if (error == 0) {
+ n = bp->b_bcount - on;
+ if (n < 0) {
+ error = EINVAL;
+ } else {
+ n = min(n, bp->b_bcount - bp->b_resid - on);
+ if (n < 0)
+ error = EIO;
}
- n = min(n, uio->uio_resid);
- error = uiomove((char *)bp->b_data + on, n, uio);
+ }
+ if (error) {
brelse(bp);
- } while (error == 0 && uio->uio_resid > 0 && n != 0);
- return (error);
-
- default:
- panic("spec_read type");
- }
+ return (error);
+ }
+ n = min(n, uio->uio_resid);
+ error = uiomove((char *)bp->b_data + on, n, uio);
+ brelse(bp);
+ } while (error == 0 && uio->uio_resid > 0 && n != 0);
+ return (error);
/* NOTREACHED */
}
@@ -382,14 +399,9 @@ spec_write(ap)
struct ucred *a_cred;
} */ *ap;
{
- register struct vnode *vp = ap->a_vp;
- register struct uio *uio = ap->a_uio;
+ struct vnode *vp = ap->a_vp;
+ struct uio *uio = ap->a_uio;
struct proc *p = uio->uio_procp;
- struct buf *bp;
- daddr_t bn;
- int bsize, blkmask;
- struct partinfo dpart;
- register int n, on;
int error = 0;
#ifdef DIAGNOSTIC
@@ -399,98 +411,114 @@ spec_write(ap)
panic("spec_write proc");
#endif
- switch (vp->v_type) {
-
- case VCHR:
+ if (vp->v_type == VCHR || (bdev_buffered == 0)) {
VOP_UNLOCK(vp, 0, p);
error = (*devsw(vp->v_rdev)->d_write)
(vp->v_rdev, uio, ap->a_ioflag);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
return (error);
+ } else {
+ return (spec_bufwrite(ap));
+ }
+}
- case VBLK:
- if (enable_userblk_io == 0)
- return (EINVAL);
- if (uio->uio_resid == 0)
- return (0);
- if (uio->uio_offset < 0)
- return (EINVAL);
+
+/* Vnode op for buffered write */
+/* ARGSUSED */
+static int
+spec_bufwrite(ap)
+ struct vop_write_args /* {
+ struct vnode *a_vp;
+ struct uio *a_uio;
+ int a_ioflag;
+ struct ucred *a_cred;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+ struct uio *uio = ap->a_uio;
+ struct proc *p = uio->uio_procp;
+ struct buf *bp;
+ daddr_t bn;
+ int bsize, blkmask;
+ struct partinfo dpart;
+ register int n, on;
+ int error = 0;
+
+ if (uio->uio_resid == 0)
+ return (0);
+ if (uio->uio_offset < 0)
+ return (EINVAL);
+
+ /*
+ * Calculate block size for block device. The block size must
+ * be larger then the physical minimum.
+ */
+ bsize = vp->v_rdev->si_bsize_best;
+ if (bsize < vp->v_rdev->si_bsize_phys)
+ bsize = vp->v_rdev->si_bsize_phys;
+ if (bsize < BLKDEV_IOSIZE)
+ bsize = BLKDEV_IOSIZE;
+
+ if ((*devsw(vp->v_rdev)->d_ioctl)(vp->v_rdev, DIOCGPART,
+ (caddr_t)&dpart, FREAD, p) == 0) {
+ if (dpart.part->p_fstype == FS_BSDFFS &&
+ dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
+ bsize = dpart.part->p_frag *
+ dpart.part->p_fsize;
+ }
+ blkmask = btodb(bsize) - 1;
+ do {
+ bn = btodb(uio->uio_offset) & ~blkmask;
+ on = uio->uio_offset % bsize;
/*
- * Calculate block size for block device. The block size must
- * be larger then the physical minimum.
+ * Calculate potential request size, determine
+ * if we can avoid a read-before-write.
*/
- bsize = vp->v_rdev->si_bsize_best;
- if (bsize < vp->v_rdev->si_bsize_phys)
- bsize = vp->v_rdev->si_bsize_phys;
- if (bsize < BLKDEV_IOSIZE)
- bsize = BLKDEV_IOSIZE;
-
- if ((*devsw(vp->v_rdev)->d_ioctl)(vp->v_rdev, DIOCGPART,
- (caddr_t)&dpart, FREAD, p) == 0) {
- if (dpart.part->p_fstype == FS_BSDFFS &&
- dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
- bsize = dpart.part->p_frag *
- dpart.part->p_fsize;
- }
- blkmask = btodb(bsize) - 1;
- do {
- bn = btodb(uio->uio_offset) & ~blkmask;
- on = uio->uio_offset % bsize;
-
- /*
- * Calculate potential request size, determine
- * if we can avoid a read-before-write.
- */
- n = min((unsigned)(bsize - on), uio->uio_resid);
- if (n == bsize)
- bp = getblk(vp, bn, bsize, 0, 0);
- else
- error = bread(vp, bn, bsize, NOCRED, &bp);
+ n = min((unsigned)(bsize - on), uio->uio_resid);
+ if (n == bsize)
+ bp = getblk(vp, bn, bsize, 0, 0);
+ else
+ error = bread(vp, bn, bsize, NOCRED, &bp);
- /*
- * n is the amount of effective space in the buffer
- * that we wish to write relative to our offset into
- * the buffer. We have to truncate it to the valid
- * size of the buffer relative to our offset into
- * the buffer (which may end up being negative if
- * we are beyond the EOF).
- *
- * The valid size of the buffer is based on
- * bp->b_bcount (which may have been truncated by
- * dscheck or the device) minus bp->b_resid, which
- * may be indicative of an I/O error if non-zero.
- *
- * XXX In a newly created buffer, b_bcount == bsize
- * and, being asynchronous, we have no idea of the
- * EOF.
- */
- if (error == 0) {
- n = min(n, bp->b_bcount - on);
- if (n < 0) {
- error = EINVAL;
- } else {
- n = min(n, bp->b_bcount - bp->b_resid - on);
- if (n < 0)
- error = EIO;
- }
- }
- if (error) {
- brelse(bp);
- return (error);
+ /*
+ * n is the amount of effective space in the buffer
+ * that we wish to write relative to our offset into
+ * the buffer. We have to truncate it to the valid
+ * size of the buffer relative to our offset into
+ * the buffer (which may end up being negative if
+ * we are beyond the EOF).
+ *
+ * The valid size of the buffer is based on
+ * bp->b_bcount (which may have been truncated by
+ * dscheck or the device) minus bp->b_resid, which
+ * may be indicative of an I/O error if non-zero.
+ *
+ * XXX In a newly created buffer, b_bcount == bsize
+ * and, being asynchronous, we have no idea of the
+ * EOF.
+ */
+ if (error == 0) {
+ n = min(n, bp->b_bcount - on);
+ if (n < 0) {
+ error = EINVAL;
+ } else {
+ n = min(n, bp->b_bcount - bp->b_resid - on);
+ if (n < 0)
+ error = EIO;
}
- error = uiomove((char *)bp->b_data + on, n, uio);
- if (n + on == bsize)
- bawrite(bp);
- else
- bdwrite(bp);
- } while (error == 0 && uio->uio_resid > 0 && n != 0);
- return (error);
-
- default:
- panic("spec_write type");
- }
- /* NOTREACHED */
+ }
+ if (error) {
+ brelse(bp);
+ return (error);
+ }
+ error = uiomove((char *)bp->b_data + on, n, uio);
+ if (n + on == bsize)
+ bawrite(bp);
+ else
+ bdwrite(bp);
+ } while (error == 0 && uio->uio_resid > 0 && n != 0);
+ return (error);
}
/*
@@ -707,7 +735,8 @@ spec_close(ap)
struct proc *a_p;
} */ *ap;
{
- register struct vnode *vp = ap->a_vp;
+ struct vnode *vp = ap->a_vp;
+ struct proc *p = ap->a_p;
dev_t dev = vp->v_rdev;
int mode, error;
@@ -723,27 +752,27 @@ spec_close(ap)
* if the reference count is 2 (this last descriptor
* plus the session), release the reference from the session.
*/
- if (vcount(vp) == 2 && ap->a_p &&
- (vp->v_flag & VXLOCK) == 0 &&
- vp == ap->a_p->p_session->s_ttyvp) {
+ if (vcount(vp) == 2 && p && (vp->v_flag & VXLOCK) == 0 &&
+ vp == p->p_session->s_ttyvp) {
vrele(vp);
- ap->a_p->p_session->s_ttyvp = NULL;
+ p->p_session->s_ttyvp = NULL;
}
mode = S_IFCHR;
break;
case VBLK:
- /*
- * On last close of a block device (that isn't mounted)
- * we must invalidate any in core blocks, so that
- * we can, for instance, change floppy disks.
- */
- vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, ap->a_p);
- error = vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 0, 0);
- VOP_UNLOCK(vp, 0, ap->a_p);
- if (error)
- return (error);
-
+ if (bdev_buffered) {
+ /*
+ * On last close of a block device (that isn't mounted)
+ * we must invalidate any in core blocks, so that
+ * we can, for instance, change floppy disks.
+ */
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
+ error = vinvalbuf(vp, V_SAVE, ap->a_cred, p, 0, 0);
+ VOP_UNLOCK(vp, 0, p);
+ if (error)
+ return (error);
+ }
mode = S_IFBLK;
break;
@@ -766,7 +795,7 @@ spec_close(ap)
} else if (vcount(vp) > 1) {
return (0);
}
- return (devsw(dev)->d_close(dev, ap->a_fflag, mode, ap->a_p));
+ return (devsw(dev)->d_close(dev, ap->a_fflag, mode, p));
}
/*
OpenPOWER on IntegriCloud