summaryrefslogtreecommitdiffstats
path: root/sys/dev/vn
diff options
context:
space:
mode:
authordillon <dillon@FreeBSD.org>1999-09-20 18:06:17 +0000
committerdillon <dillon@FreeBSD.org>1999-09-20 18:06:17 +0000
commitbeea8c578659a0aa0f59a617bfb1cc980614561f (patch)
treea4b4bb6138c331638047fe2bf2d8f97c852029c6 /sys/dev/vn
parent59bdedf6a05dfca2d3a1e662e26f4fe967766c62 (diff)
downloadFreeBSD-src-beea8c578659a0aa0f59a617bfb1cc980614561f.zip
FreeBSD-src-beea8c578659a0aa0f59a617bfb1cc980614561f.tar.gz
Fix the situation where an I/O crosses the EOF point. We need to properly
adjust the bp->b_bcount the same way for unlabeled VN access as dscheck does for labeled access. We also increase the block size to at least 8K for efficiency. Reviewed by: Tor.Egge@fast.no
Diffstat (limited to 'sys/dev/vn')
-rw-r--r--sys/dev/vn/vn.c33
1 files changed, 29 insertions, 4 deletions
diff --git a/sys/dev/vn/vn.c b/sys/dev/vn/vn.c
index f20c661..4fafe84 100644
--- a/sys/dev/vn/vn.c
+++ b/sys/dev/vn/vn.c
@@ -98,6 +98,8 @@ static d_strategy_t vnstrategy;
#define CDEV_MAJOR 43
#define BDEV_MAJOR 15
+#define VN_BSIZE_BEST 8192
+
/*
* cdevsw
* D_DISK we want to look like a disk
@@ -222,10 +224,16 @@ vnopen(dev_t dev, int flags, int mode, struct proc *p)
* Update si_bsize fields for device. This data will be overriden by
* the slice/parition code for vn accesses through partitions, and
* used directly if you open the 'whole disk' device.
+ *
+ * si_bsize_best must be reinitialized in case VN has been
+ * reconfigured, plus make it at least VN_BSIZE_BEST for efficiency.
*/
dev->si_bsize_phys = vn->sc_secsize;
+ dev->si_bsize_best = vn->sc_secsize;
+ if (dev->si_bsize_best < VN_BSIZE_BEST)
+ dev->si_bsize_best = VN_BSIZE_BEST;
- if (flags & FWRITE && vn->sc_flags & VNF_READONLY)
+ if ((flags & FWRITE) && (vn->sc_flags & VNF_READONLY))
return (EACCES);
IFOPT(vn, VN_FOLLOW)
@@ -281,7 +289,6 @@ vnstrategy(struct buf *bp)
struct vn_softc *vn;
int error;
int isvplocked = 0;
- long sz;
struct uio auio;
struct iovec aiov;
@@ -310,11 +317,16 @@ vnstrategy(struct buf *bp)
}
} else {
int pbn; /* in sc_secsize chunks */
+ long sz; /* in sc_secsize chunks */
pbn = bp->b_blkno / (vn->sc_secsize / DEV_BSIZE);
sz = howmany(bp->b_bcount, vn->sc_secsize);
- if (pbn < 0 || pbn + sz > vn->sc_size) {
+ /*
+ * If out of bounds return an error. If at the EOF point,
+ * simply read or write less.
+ */
+ if (pbn < 0 || pbn >= vn->sc_size) {
if (pbn != vn->sc_size) {
bp->b_error = EINVAL;
bp->b_flags |= B_ERROR | B_INVAL;
@@ -322,6 +334,15 @@ vnstrategy(struct buf *bp)
biodone(bp);
return;
}
+
+ /*
+ * If the request crosses EOF, truncate the request.
+ */
+ if (pbn + sz > vn->sc_size) {
+ bp->b_bcount -= (pbn + sz - vn->sc_size) *
+ vn->sc_secsize;
+ bp->b_resid = bp->b_bcount;
+ }
bp->b_pblkno = pbn;
}
@@ -333,6 +354,10 @@ vnstrategy(struct buf *bp)
} else if (vn->sc_vp) {
/*
* VNODE I/O
+ *
+ * If an error occurs, we set B_ERROR but we do not set
+ * B_INVAL because (for a write anyway), the buffer is
+ * still valid.
*/
aiov.iov_base = bp->b_data;
aiov.iov_len = bp->b_bcount;
@@ -360,7 +385,7 @@ vnstrategy(struct buf *bp)
}
bp->b_resid = auio.uio_resid;
- if( error ) {
+ if (error) {
bp->b_error = error;
bp->b_flags |= B_ERROR;
}
OpenPOWER on IntegriCloud