Module Name: src
Committed By: dyoung
Date: Thu Apr 30 20:34:08 UTC 2009
Modified Files:
src/sys/dev: vnd.c
Log Message:
Flesh out vnd_detach(). Let the system detach vnd(4) at shutdown. Stop
vnd_ioctl(VNDIOCCLR) from racing with vndopen() to call vndclear().
To generate a diff of this commit:
cvs rdiff -u -r1.198 -r1.199 src/sys/dev/vnd.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/vnd.c
diff -u src/sys/dev/vnd.c:1.198 src/sys/dev/vnd.c:1.199
--- src/sys/dev/vnd.c:1.198 Thu Apr 30 16:38:12 2009
+++ src/sys/dev/vnd.c Thu Apr 30 20:34:08 2009
@@ -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 @@
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 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 @@
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 @@
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 @@
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 @@
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