Date: Fri, 11 Mar 2011 16:14:06 +0000 (UTC) From: John Baldwin <jhb@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org Subject: svn commit: r219503 - stable/8/sys/kern Message-ID: <201103111614.p2BGE6MX085718@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201103111614.p2BGE6MX085718>