summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorMatthew Dempsky <matthew@cvs.openbsd.org>2011-07-06 05:09:02 +0000
committerMatthew Dempsky <matthew@cvs.openbsd.org>2011-07-06 05:09:02 +0000
commitf3f666a75b35617b422413c23685155bcbd49f33 (patch)
treef98cc868b25baf24edb9f92ed9a510dc5a56b1a1 /sys/dev
parent7d234422c9c97bd73d581a8badf326e45ba9a2a4 (diff)
vndstrategy() should fail if VNF_HAVELABEL isn't set. This simplifies
the logic slightly and makes vnd(4) more like any other disk driver. To avoid races, this means vndopen() can only set VNF_HAVELABEL if dk_openmask == 0. Otherwise, it's possible for userspace to open rvnd0c, call VNDIOCSET, open vnd0a, then while vndreaddisklabel() (via vndstrategy) is waiting for VOP_READ() to finish, you could issue a read or write on the still open rvnd0c and have VNF_HAVELABEL set but the disklabel might be in a weird state. Note that this makes VNF_HAVELABEL nicely analogous to sd(4)/cd(4)'s SDEV_MEDIA_LOADED flag, which is handled similarly in {sd,cd}{open,close,strategy}. ok dlg@, krw@, deraadt@
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/vnd.c33
1 files changed, 14 insertions, 19 deletions
diff --git a/sys/dev/vnd.c b/sys/dev/vnd.c
index 7f391bc3157..d16cf1aaaef 100644
--- a/sys/dev/vnd.c
+++ b/sys/dev/vnd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vnd.c,v 1.138 2011/07/06 04:49:36 matthew Exp $ */
+/* $OpenBSD: vnd.c,v 1.139 2011/07/06 05:09:01 matthew Exp $ */
/* $NetBSD: vnd.c,v 1.26 1996/03/30 23:06:11 christos Exp $ */
/*
@@ -52,13 +52,11 @@
#include <sys/errno.h>
#include <sys/buf.h>
#include <sys/malloc.h>
-#include <sys/pool.h>
#include <sys/ioctl.h>
#include <sys/disklabel.h>
#include <sys/device.h>
#include <sys/disk.h>
#include <sys/stat.h>
-#include <sys/mount.h>
#include <sys/vnode.h>
#include <sys/file.h>
#include <sys/uio.h>
@@ -186,13 +184,13 @@ vndopen(dev_t dev, int flags, int mode, struct proc *p)
}
if ((sc->sc_flags & VNF_INITED) &&
- (sc->sc_flags & VNF_HAVELABEL) == 0) {
+ (sc->sc_flags & VNF_HAVELABEL) == 0 &&
+ sc->sc_dk.dk_openmask == 0) {
sc->sc_flags |= VNF_HAVELABEL;
vndgetdisklabel(dev, sc, sc->sc_dk.dk_label, 0);
}
part = DISKPART(dev);
-
error = disk_openpart(&sc->sc_dk, part, mode,
(sc->sc_flags & VNF_HAVELABEL) != 0);
@@ -250,6 +248,9 @@ vndclose(dev_t dev, int flags, int mode, struct proc *p)
disk_closepart(&sc->sc_dk, part, mode);
+ if (sc->sc_dk.dk_openmask == 0)
+ sc->sc_flags &= ~VNF_HAVELABEL;
+
disk_unlock(&sc->sc_dk);
return (0);
}
@@ -268,7 +269,7 @@ vndstrategy(struct buf *bp)
DNPRINTF(VDB_FOLLOW, "vndstrategy(%p): unit %d\n", bp, unit);
- if ((sc->sc_flags & VNF_INITED) == 0) {
+ if ((sc->sc_flags & VNF_HAVELABEL) == 0) {
bp->b_error = ENXIO;
bp->b_flags |= B_ERROR;
goto done;
@@ -290,21 +291,15 @@ vndstrategy(struct buf *bp)
goto done;
}
- /* If we have a label, do a boundary check. */
- if (sc->sc_flags & VNF_HAVELABEL) {
- if (bounds_check_with_label(bp, sc->sc_dk.dk_label) == -1)
- goto done;
+ if (bounds_check_with_label(bp, sc->sc_dk.dk_label) == -1)
+ goto done;
- /*
- * bounds_check_with_label() changes bp->b_resid, reset it
- */
- bp->b_resid = bp->b_bcount;
- }
+ /*
+ * bounds_check_with_label() changes bp->b_resid, reset it
+ */
+ bp->b_resid = bp->b_bcount;
- if (sc->sc_flags & VNF_HAVELABEL)
- sz = howmany(bp->b_bcount, sc->sc_dk.dk_label->d_secsize);
- else
- sz = howmany(bp->b_bcount, DEV_BSIZE);
+ sz = howmany(bp->b_bcount, sc->sc_dk.dk_label->d_secsize);
part = DISKPART(bp->b_dev);
off = DL_SECTOBLK(sc->sc_dk.dk_label,