summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authordyoung <dyoung@NetBSD.org>2009-04-30 20:34:08 +0000
committerdyoung <dyoung@NetBSD.org>2009-04-30 20:34:08 +0000
commitc968789de1bdcd642155ef3713d70b5de07b4c82 (patch)
treec58a211b050256f7af765a0f3b336a02c7b2225b /sys/dev
parent3c1f169a5912afbef3d04ac250f2414331966e30 (diff)
Flesh out vnd_detach(). Let the system detach vnd(4) at shutdown. Stop
vnd_ioctl(VNDIOCCLR) from racing with vndopen() to call vndclear().
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/vnd.c99
1 files changed, 63 insertions, 36 deletions
diff --git a/sys/dev/vnd.c b/sys/dev/vnd.c
index a4dd4d18577..68064a01870 100644
--- a/sys/dev/vnd.c
+++ b/sys/dev/vnd.c
@@ -1,4 +1,4 @@
-/* $NetBSD: vnd.c,v 1.198 2009/04/30 16:38:12 dyoung Exp $ */
+/* $NetBSD: vnd.c,v 1.199 2009/04/30 20:34:08 dyoung Exp $ */
/*-
* Copyright (c) 1996, 1997, 1998, 2008 The NetBSD Foundation, Inc.
@@ -130,7 +130,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vnd.c,v 1.198 2009/04/30 16:38:12 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vnd.c,v 1.199 2009/04/30 20:34:08 dyoung Exp $");
#if defined(_KERNEL_OPT)
#include "fs_nfs.h"
@@ -198,6 +198,7 @@ struct vndxfer {
void vndattach(int);
static void vndclear(struct vnd_softc *, int);
+static int vnddoclear(struct vnd_softc *, int, int, bool);
static int vndsetcred(struct vnd_softc *, kauth_cred_t);
static void vndthrottle(struct vnd_softc *, struct vnode *);
static void vndiodone(struct buf *);
@@ -246,8 +247,8 @@ static int vnd_match(device_t, cfdata_t, void *);
static void vnd_attach(device_t, device_t, void *);
static int vnd_detach(device_t, int);
-CFATTACH_DECL_NEW(vnd, sizeof(struct vnd_softc),
- vnd_match, vnd_attach, vnd_detach, NULL);
+CFATTACH_DECL3_NEW(vnd, sizeof(struct vnd_softc),
+ vnd_match, vnd_attach, vnd_detach, NULL, NULL, NULL, DVF_DETACH_SHUTDOWN);
extern struct cfdriver vnd_cd;
static struct vnd_softc *vnd_spawn(int);
@@ -289,9 +290,14 @@ vnd_attach(device_t parent, device_t self, void *aux)
static int
vnd_detach(device_t self, int flags)
{
+ int error;
struct vnd_softc *sc = device_private(self);
- if (sc->sc_flags & VNF_INITED)
- return EBUSY;
+
+ if (sc->sc_flags & VNF_INITED) {
+ error = vnddoclear(sc, 0, -1, (flags & DETACH_FORCE) != 0);
+ if (error != 0)
+ return error;
+ }
pmf_device_deregister(self);
bufq_free(sc->sc_tab);
@@ -350,6 +356,9 @@ vndopen(dev_t dev, int flags, int mode, struct lwp *l)
if ((error = vndlock(sc)) != 0)
return error;
+ if ((sc->sc_flags & VNF_CLEARING) != 0)
+ return ENXIO;
+
lp = sc->sc_dkdev.dk_label;
part = DISKPART(dev);
@@ -948,10 +957,55 @@ vnd_cget(struct lwp *l, int unit, int *un, struct vattr *va)
return VOP_GETATTR(vnd->sc_vp, va, l->l_cred);
}
+static int
+vnddoclear(struct vnd_softc *vnd, int pmask, int minor, bool force)
+{
+ int error;
+
+ if ((error = vndlock(vnd)) != 0)
+ return error;
+
+ /*
+ * Don't unconfigure if any other partitions are open
+ * or if both the character and block flavors of this
+ * partition are open.
+ */
+ if (((vnd->sc_dkdev.dk_openmask & ~pmask) ||
+ ((vnd->sc_dkdev.dk_bopenmask & pmask) &&
+ (vnd->sc_dkdev.dk_copenmask & pmask))) && !force) {
+ vndunlock(vnd);
+ return EBUSY;
+ }
+
+ /*
+ * XXX vndclear() might call vndclose() implicitly;
+ * release lock to avoid recursion
+ *
+ * Set VNF_CLEARING to prevent vndopen() from
+ * sneaking in after we vndunlock().
+ */
+ vnd->sc_flags |= VNF_CLEARING;
+ vndunlock(vnd);
+ vndclear(vnd, minor);
+#ifdef DEBUG
+ if (vnddebug & VDB_INIT)
+ printf("vndioctl: CLRed\n");
+#endif
+
+ /* Destroy the xfer and buffer pools. */
+ pool_destroy(&vnd->sc_vxpool);
+
+ /* Detach the disk. */
+ disk_detach(&vnd->sc_dkdev);
+
+ return 0;
+}
+
/* ARGSUSED */
static int
vndioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
{
+ bool force;
int unit = vndunit(dev);
struct vnd_softc *vnd;
struct vnd_ioctl *vio;
@@ -1274,40 +1328,13 @@ unlock_and_exit:
return error;
case VNDIOCCLR:
- if ((error = vndlock(vnd)) != 0)
- return error;
-
- /*
- * Don't unconfigure if any other partitions are open
- * or if both the character and block flavors of this
- * partition are open.
- */
part = DISKPART(dev);
pmask = (1 << part);
- if (((vnd->sc_dkdev.dk_openmask & ~pmask) ||
- ((vnd->sc_dkdev.dk_bopenmask & pmask) &&
- (vnd->sc_dkdev.dk_copenmask & pmask))) &&
- !(vio->vnd_flags & VNDIOF_FORCE)) {
- vndunlock(vnd);
- return EBUSY;
- }
+ force = (vio->vnd_flags & VNDIOF_FORCE) != 0;
- /*
- * XXX vndclear() might call vndclose() implicitly;
- * release lock to avoid recursion
- */
- vndunlock(vnd);
- vndclear(vnd, minor(dev));
-#ifdef DEBUG
- if (vnddebug & VDB_INIT)
- printf("vndioctl: CLRed\n");
-#endif
-
- /* Destroy the xfer and buffer pools. */
- pool_destroy(&vnd->sc_vxpool);
+ if ((error = vnddoclear(vnd, pmask, minor(dev), force)) != 0)
+ return error;
- /* Detach the disk. */
- disk_detach(&vnd->sc_dkdev);
break;
#ifdef COMPAT_30