Module Name:    src
Committed By:   dyoung
Date:           Tue Jul 21 19:41:00 UTC 2009

Modified Files:
        src/sys/dev/dkwedge: dk.c

Log Message:
Extract a lot of code from dkwedge_del(), and move it to dkwedge_detach()
to create a comprehensive detachment hook.  Let that hook run at
shutdown.  Now, 'drvctl -d dk0' actually deletes a wedge if it is
not in-use (otherwise fails w/ EBUSY), and wedges are gracefully
detached from their "parent" at shutdown.


To generate a diff of this commit:
cvs rdiff -u -r1.46 -r1.47 src/sys/dev/dkwedge/dk.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/dkwedge/dk.c
diff -u src/sys/dev/dkwedge/dk.c:1.46 src/sys/dev/dkwedge/dk.c:1.47
--- src/sys/dev/dkwedge/dk.c:1.46	Thu Jul  2 00:56:48 2009
+++ src/sys/dev/dkwedge/dk.c	Tue Jul 21 19:41:00 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: dk.c,v 1.46 2009/07/02 00:56:48 dyoung Exp $	*/
+/*	$NetBSD: dk.c,v 1.47 2009/07/21 19:41:00 dyoung Exp $	*/
 
 /*-
  * Copyright (c) 2004, 2005, 2006, 2007 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: dk.c,v 1.46 2009/07/02 00:56:48 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dk.c,v 1.47 2009/07/21 19:41:00 dyoung Exp $");
 
 #include "opt_dkwedge.h"
 
@@ -95,6 +95,7 @@
 static void	dkrestart(void *);
 
 static int	dklastclose(struct dkwedge_softc *);
+static int	dkwedge_detach(device_t, int);
 
 static dev_type_open(dkopen);
 static dev_type_close(dkclose);
@@ -149,23 +150,10 @@
 		aprint_error_dev(self, "couldn't establish power handler\n");
 }
 
-/*
- * dkwedge_detach:
- *
- *	Autoconfiguration detach function for pseudo-device glue.
- */
-static int
-dkwedge_detach(device_t self, int flags)
-{
-
-	pmf_device_deregister(self);
-	/* Always succeeds. */
-	return (0);
-}
-
 CFDRIVER_DECL(dk, DV_DISK, NULL);
-CFATTACH_DECL_NEW(dk, 0,
-	      dkwedge_match, dkwedge_attach, dkwedge_detach, NULL);
+CFATTACH_DECL3_NEW(dk, 0,
+    dkwedge_match, dkwedge_attach, dkwedge_detach, NULL, NULL, NULL,
+    DVF_DETACH_SHUTDOWN);
 
 /*
  * dkwedge_wait_drain:
@@ -423,36 +411,111 @@
 }
 
 /*
- * dkwedge_del:		[exported function]
+ * dkwedge_find:
  *
- *	Delete a disk wedge based on the provided information.
+ *	Lookup a disk wedge based on the provided information.
  *	NOTE: We look up the wedge based on the wedge devname,
  *	not wname.
+ *
+ *	Return NULL if the wedge is not found, otherwise return
+ *	the wedge's softc.  Assign the wedge's unit number to unitp
+ *	if unitp is not NULL.
  */
-int
-dkwedge_del(struct dkwedge_info *dkw)
+static struct dkwedge_softc *
+dkwedge_find(struct dkwedge_info *dkw, u_int *unitp)
 {
 	struct dkwedge_softc *sc = NULL;
 	u_int unit;
-	int bmaj, cmaj, s;
 
 	/* Find our softc. */
 	dkw->dkw_devname[sizeof(dkw->dkw_devname) - 1] = '\0';
-	rw_enter(&dkwedges_lock, RW_WRITER);
+	rw_enter(&dkwedges_lock, RW_READER);
 	for (unit = 0; unit < ndkwedges; unit++) {
 		if ((sc = dkwedges[unit]) != NULL &&
 		    strcmp(device_xname(sc->sc_dev), dkw->dkw_devname) == 0 &&
 		    strcmp(sc->sc_parent->dk_name, dkw->dkw_parent) == 0) {
-			/* Mark the wedge as dying. */
-			sc->sc_state = DKW_STATE_DYING;
 			break;
 		}
 	}
 	rw_exit(&dkwedges_lock);
 	if (unit == ndkwedges)
+		return NULL;
+
+	if (unitp != NULL)
+		*unitp = unit;
+
+	return sc;
+}
+
+/*
+ * dkwedge_del:		[exported function]
+ *
+ *	Delete a disk wedge based on the provided information.
+ *	NOTE: We look up the wedge based on the wedge devname,
+ *	not wname.
+ */
+int
+dkwedge_del(struct dkwedge_info *dkw)
+{
+	struct dkwedge_softc *sc = NULL;
+
+	/* Find our softc. */
+	if ((sc = dkwedge_find(dkw, NULL)) == NULL)
 		return (ESRCH);
 
-	KASSERT(sc != NULL);
+	return config_detach(sc->sc_dev, DETACH_FORCE | DETACH_QUIET);
+}
+
+static int
+dkwedge_begindetach(struct dkwedge_softc *sc, int flags)
+{
+	struct disk *dk = &sc->sc_dk;
+	int rc;
+
+	rc = 0;
+	mutex_enter(&dk->dk_openlock);
+	mutex_enter(&sc->sc_parent->dk_rawlock);
+	if (dk->dk_openmask == 0)
+		;	/* nothing to do */
+	else if ((flags & DETACH_FORCE) == 0)
+		rc = EBUSY;
+	else
+		rc = dklastclose(sc);
+	mutex_exit(&sc->sc_parent->dk_rawlock);
+	mutex_exit(&dk->dk_openlock);
+
+	return rc;
+}
+
+/*
+ * dkwedge_detach:
+ *
+ *	Autoconfiguration detach function for pseudo-device glue.
+ */
+static int
+dkwedge_detach(device_t self, int flags)
+{
+	struct dkwedge_softc *sc = NULL;
+	u_int unit;
+	int bmaj, cmaj, rc, s;
+
+	rw_enter(&dkwedges_lock, RW_WRITER);
+	for (unit = 0; unit < ndkwedges; unit++) {
+		if ((sc = dkwedges[unit]) != NULL && sc->sc_dev == self)
+			break;
+	}
+	if (unit == ndkwedges)
+		rc = ENXIO;
+	else if ((rc = dkwedge_begindetach(sc, flags)) == 0) {
+		/* Mark the wedge as dying. */
+		sc->sc_state = DKW_STATE_DYING;
+	}
+	rw_exit(&dkwedges_lock);
+
+	if (rc != 0)
+		return rc;
+
+	pmf_device_deregister(self);
 
 	/* Locate the wedge major numbers. */
 	bmaj = bdevsw_lookup_major(&dk_bdevsw);
@@ -495,9 +558,6 @@
 	    sc->sc_parent->dk_name,
 	    sc->sc_wname);	/* XXX Unicode */
 
-	/* Delete our pseudo-device. */
-	(void) config_detach(sc->sc_dev, DETACH_FORCE | DETACH_QUIET);
-
 	mutex_enter(&sc->sc_parent->dk_openlock);
 	sc->sc_parent->dk_nwedges--;
 	LIST_REMOVE(sc, sc_plink);
@@ -518,7 +578,7 @@
 
 	free(sc, M_DKWEDGE);
 
-	return (0);
+	return 0;
 }
 
 /*

Reply via email to