svn commit: r219503 - stable/8/sys/kern
John Baldwin
jhb at FreeBSD.org
Fri Mar 11 16:14:07 UTC 2011
Author: jhb
Date: Fri Mar 11 16:14:06 2011
New Revision: 219503
URL: http://svn.freebsd.org/changeset/base/219503
Log:
MFC 219135:
Similar to 189574, properly handle subclasses of bus drivers when deleting
a driver during kldunload. Specifically, recursively walk the tree of
subclasses of a given driver attachment's bus device class detaching all
instances of that driver for each class and its subclasses.
Modified:
stable/8/sys/kern/subr_bus.c
Directory Properties:
stable/8/sys/ (props changed)
stable/8/sys/amd64/include/xen/ (props changed)
stable/8/sys/cddl/contrib/opensolaris/ (props changed)
stable/8/sys/contrib/dev/acpica/ (props changed)
stable/8/sys/contrib/pf/ (props changed)
Modified: stable/8/sys/kern/subr_bus.c
==============================================================================
--- stable/8/sys/kern/subr_bus.c Fri Mar 11 16:13:26 2011 (r219502)
+++ stable/8/sys/kern/subr_bus.c Fri Mar 11 16:14:06 2011 (r219503)
@@ -1023,10 +1023,12 @@ devclass_find(const char *classname)
* is called by devclass_add_driver to accomplish the recursive
* notification of all the children classes of dc, as well as dc.
* Each layer will have BUS_DRIVER_ADDED() called for all instances of
- * the devclass. We do a full search here of the devclass list at
- * each iteration level to save storing children-lists in the devclass
- * structure. If we ever move beyond a few dozen devices doing this,
- * we may need to reevaluate...
+ * the devclass.
+ *
+ * We do a full search here of the devclass list at each iteration
+ * level to save storing children-lists in the devclass structure. If
+ * we ever move beyond a few dozen devices doing this, we may need to
+ * reevaluate...
*
* @param dc the devclass to edit
* @param driver the driver that was just added
@@ -1121,6 +1123,78 @@ devclass_add_driver(devclass_t dc, drive
}
/**
+ * @brief Register that a device driver has been deleted from a devclass
+ *
+ * Register that a device driver has been removed from a devclass.
+ * This is called by devclass_delete_driver to accomplish the
+ * recursive notification of all the children classes of busclass, as
+ * well as busclass. Each layer will attempt to detach the driver
+ * from any devices that are children of the bus's devclass. The function
+ * will return an error if a device fails to detach.
+ *
+ * We do a full search here of the devclass list at each iteration
+ * level to save storing children-lists in the devclass structure. If
+ * we ever move beyond a few dozen devices doing this, we may need to
+ * reevaluate...
+ *
+ * @param busclass the devclass of the parent bus
+ * @param dc the devclass of the driver being deleted
+ * @param driver the driver being deleted
+ */
+static int
+devclass_driver_deleted(devclass_t busclass, devclass_t dc, driver_t *driver)
+{
+ devclass_t parent;
+ device_t dev;
+ int error, i;
+
+ /*
+ * Disassociate from any devices. We iterate through all the
+ * devices in the devclass of the driver and detach any which are
+ * using the driver and which have a parent in the devclass which
+ * we are deleting from.
+ *
+ * Note that since a driver can be in multiple devclasses, we
+ * should not detach devices which are not children of devices in
+ * the affected devclass.
+ */
+ for (i = 0; i < dc->maxunit; i++) {
+ if (dc->devices[i]) {
+ dev = dc->devices[i];
+ if (dev->driver == driver && dev->parent &&
+ dev->parent->devclass == busclass) {
+ if ((error = device_detach(dev)) != 0)
+ return (error);
+ device_set_driver(dev, NULL);
+ BUS_PROBE_NOMATCH(dev->parent, dev);
+ devnomatch(dev);
+ dev->flags |= DF_DONENOMATCH;
+ }
+ }
+ }
+
+ /*
+ * Walk through the children classes. Since we only keep a
+ * single parent pointer around, we walk the entire list of
+ * devclasses looking for children. We set the
+ * DC_HAS_CHILDREN flag when a child devclass is created on
+ * the parent, so we only walk the list for those devclasses
+ * that have children.
+ */
+ if (!(busclass->flags & DC_HAS_CHILDREN))
+ return (0);
+ parent = busclass;
+ TAILQ_FOREACH(busclass, &devclasses, link) {
+ if (busclass->parent == parent) {
+ error = devclass_driver_deleted(busclass, dc, driver);
+ if (error)
+ return (error);
+ }
+ }
+ return (0);
+}
+
+/**
* @brief Delete a device driver from a device class
*
* Delete a device driver from a devclass. This is normally called
@@ -1139,8 +1213,6 @@ devclass_delete_driver(devclass_t buscla
{
devclass_t dc = devclass_find(driver->name);
driverlink_t dl;
- device_t dev;
- int i;
int error;
PDEBUG(("%s from devclass %s", driver->name, DEVCLANAME(busclass)));
@@ -1162,30 +1234,9 @@ devclass_delete_driver(devclass_t buscla
return (ENOENT);
}
- /*
- * Disassociate from any devices. We iterate through all the
- * devices in the devclass of the driver and detach any which are
- * using the driver and which have a parent in the devclass which
- * we are deleting from.
- *
- * Note that since a driver can be in multiple devclasses, we
- * should not detach devices which are not children of devices in
- * the affected devclass.
- */
- for (i = 0; i < dc->maxunit; i++) {
- if (dc->devices[i]) {
- dev = dc->devices[i];
- if (dev->driver == driver && dev->parent &&
- dev->parent->devclass == busclass) {
- if ((error = device_detach(dev)) != 0)
- return (error);
- device_set_driver(dev, NULL);
- BUS_PROBE_NOMATCH(dev->parent, dev);
- devnomatch(dev);
- dev->flags |= DF_DONENOMATCH;
- }
- }
- }
+ error = devclass_driver_deleted(busclass, dc, driver);
+ if (error != 0)
+ return (error);
TAILQ_REMOVE(&busclass->drivers, dl, link);
free(dl, M_BUS);
More information about the svn-src-stable-8
mailing list