From owner-p4-projects@FreeBSD.ORG Sun Jun 7 14:37:58 2009 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 719A91065677; Sun, 7 Jun 2009 14:37:58 +0000 (UTC) Delivered-To: perforce@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 28D331065675 for ; Sun, 7 Jun 2009 14:37:58 +0000 (UTC) (envelope-from scottl@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 0DA338FC16 for ; Sun, 7 Jun 2009 14:37:58 +0000 (UTC) (envelope-from scottl@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.3/8.14.3) with ESMTP id n57EbugX016846 for ; Sun, 7 Jun 2009 14:37:56 GMT (envelope-from scottl@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.3/8.14.3/Submit) id n57EbuLu016844 for perforce@freebsd.org; Sun, 7 Jun 2009 14:37:56 GMT (envelope-from scottl@freebsd.org) Date: Sun, 7 Jun 2009 14:37:56 GMT Message-Id: <200906071437.n57EbuLu016844@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to scottl@freebsd.org using -f From: Scott Long To: Perforce Change Reviews Cc: Subject: PERFORCE change 163715 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 07 Jun 2009 14:37:59 -0000 http://perforce.freebsd.org/chv.cgi?CH=163715 Change 163715 by scottl@scottl-deimos on 2009/06/07 14:37:21 Initial locking for devclass using the global devclasses_mtx lock. Reference counts are added for device_t and devclass objects so that the global lock can be dropped when engresses out of the subsystem. Refcounting is still incomplete. Affected files ... .. //depot/projects/scottl-camlock/src/sys/kern/subr_bus.c#22 edit Differences ... ==== //depot/projects/scottl-camlock/src/sys/kern/subr_bus.c#22 (text+ko) ==== @@ -66,6 +66,7 @@ struct driverlink { kobj_class_t driver; TAILQ_ENTRY(driverlink) link; /* list of drivers in devclass */ + TAILQ_ENTRY(driverlink) probe_link; }; /* @@ -87,8 +88,14 @@ struct sysctl_ctx_list sysctl_ctx; struct sysctl_oid *sysctl_tree; + + int class_ref; + int class_busy; }; +#define DC_REF(dc) (dc)->class_ref++ +#define DC_UNREF(dc) (dc)->class_ref-- + /** * @brief Implementation of device. */ @@ -134,8 +141,14 @@ struct sysctl_ctx_list sysctl_ctx; /**< state for sysctl variables */ struct sysctl_oid *sysctl_tree; /**< state for sysctl variables */ + + int device_ref; + int device_busy; }; +#define DT_REF(dt) (dt)->device_ref++ +#define DT_UNREF(dt) (dt)->device_ref-- + static MALLOC_DEFINE(M_BUS, "bus", "Bus data structures"); static MALLOC_DEFINE(M_BUS_SC, "bus-sc", "Bus data structures, softc"); @@ -890,15 +903,34 @@ static void devclass_driver_added(devclass_t dc, driver_t *driver) { + device_t *devlist; devclass_t parent; - int i; + int i, maxunit = 0; + + mtx_assert(&devclasses_mtx, MA_OWNED); /* * Call BUS_DRIVER_ADDED for any existing busses in this class. */ - for (i = 0; i < dc->maxunit; i++) - if (dc->devices[i]) - BUS_DRIVER_ADDED(dc->devices[i], driver); + devlist = malloc(sizeof(device_t)*dc->maxunit, M_BUS, M_NOWAIT|M_ZERO); + if (devlist == NULL) + /* XXX error? */ + return; + + for (i = 0; i < dc->maxunit; i++) { + if (dc->devices[i]) { + DT_REF(dc->devices[i]); + devlist[maxunit++] = dc->devices[i]; + } + } + + mtx_unlock(&devclasses_mtx); + for (i = 0; i < maxunit; i++) { + BUS_DRIVER_ADDED(devlist[i], driver); + DT_UNREF(devlist[i]); + } + free(devlist, M_BUS); + mtx_lock(&devclasses_mtx); /* * Walk through the children classes. Since we only keep a @@ -912,8 +944,11 @@ return; parent = dc; TAILQ_FOREACH(dc, &devclasses, link) { - if (dc->parent == parent) + if (dc->parent == parent) { + DC_REF(dc); devclass_driver_added(dc, driver); + DC_UNREF(dc); + } } } @@ -945,19 +980,23 @@ * goes. This means we can safely use static methods and avoids a * double-free in devclass_delete_driver. */ + mtx_lock(&devclasses_mtx); kobj_class_compile((kobj_class_t) driver); /* * Make sure the devclass which the driver is implementing exists. */ - devclass_find_internal(driver->name, NULL, TRUE); + devclass_find_internal_locked(driver->name, NULL, TRUE); dl->driver = driver; TAILQ_INSERT_TAIL(&dc->drivers, dl, link); driver->refs++; /* XXX: kobj_mtx */ + DC_REF(dc); devclass_driver_added(dc, driver); + DC_UNREF(dc); bus_data_generation_update(); + mtx_unlock(&devclasses_mtx); return (0); } @@ -980,8 +1019,8 @@ { devclass_t dc = devclass_find(driver->name); driverlink_t dl; - device_t dev; - int i; + device_t *devlist, dev; + int i, maxunit = 0; int error; PDEBUG(("%s from devclass %s", driver->name, DEVCLANAME(busclass))); @@ -992,6 +1031,7 @@ /* * Find the link structure in the bus' list of drivers. */ + mtx_lock(&devclasses_mtx); TAILQ_FOREACH(dl, &busclass->drivers, link) { if (dl->driver == driver) break; @@ -1000,6 +1040,7 @@ if (!dl) { PDEBUG(("%s not found in %s list", driver->name, busclass->name)); + mtx_unlock(&devclasses_mtx); return (ENOENT); } @@ -1013,18 +1054,39 @@ * should not detach devices which are not children of devices in * the affected devclass. */ + devlist = malloc(sizeof(device_t)*dc->maxunit, M_BUS, M_NOWAIT|M_ZERO); + if (devlist == NULL) { + mtx_unlock(&devclasses_mtx); + return (ENOMEM); + } + 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); + DT_REF(dev); + devlist[maxunit++] = dev; } } } + mtx_unlock(&devclasses_mtx); + error = 0; + for (i = 0; i < maxunit; i++) { + dev = devlist[i]; + if ((error = device_detach(dev)) != 0) { + DT_UNREF(dev); + break; + } + device_set_driver(dev, NULL); + DT_UNREF(dev); + } + free(devlist, M_BUS); + if (error) + return (error); + + mtx_lock(&devclasses_mtx); TAILQ_REMOVE(&busclass->drivers, dl, link); free(dl, M_BUS); @@ -1034,6 +1096,7 @@ kobj_class_free((kobj_class_t) driver); bus_data_generation_update(); + mtx_unlock(&devclasses_mtx); return (0); } @@ -1055,8 +1118,8 @@ { devclass_t dc = devclass_find(driver->name); driverlink_t dl; - device_t dev; - int i; + device_t *devlist, dev; + int i, maxunit = 0; int error; PDEBUG(("%s from devclass %s", driver->name, DEVCLANAME(busclass))); @@ -1067,6 +1130,7 @@ /* * Find the link structure in the bus' list of drivers. */ + mtx_lock(&devclasses_mtx); TAILQ_FOREACH(dl, &busclass->drivers, link) { if (dl->driver == driver) break; @@ -1075,6 +1139,7 @@ if (!dl) { PDEBUG(("%s not found in %s list", driver->name, busclass->name)); + mtx_unlock(&devclasses_mtx); return (ENOENT); } @@ -1088,18 +1153,35 @@ * should not quiesce devices which are not children of * devices in the affected devclass. */ + devlist = malloc(sizeof(device_t)*dc->maxunit, M_BUS, M_NOWAIT|M_ZERO); + if (devlist == NULL) { + mtx_unlock(&devclasses_mtx); + return (ENOMEM); + } + 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_quiesce(dev)) != 0) - return (error); + DT_REF(dev); + devlist[maxunit++] = dev; } } } + mtx_unlock(&devclasses_mtx); + + error = 0; + for (i = 0; i < maxunit; i++) { + dev = devlist[i]; + error = device_quiesce(dev); + DT_UNREF(dev); + if (error) + break; + } - return (0); + free(devlist, M_BUS); + return (error); } /** @@ -1112,6 +1194,8 @@ PDEBUG(("%s in devclass %s", classname, DEVCLANAME(dc))); + mtx_assert(&devclasses_mtx, MA_OWNED); + TAILQ_FOREACH(dl, &dc->drivers, link) { if (!strcmp(dl->driver->name, classname)) return (dl); @@ -1136,7 +1220,9 @@ { driverlink_t dl; + mtx_lock(&devclasses_mtx); dl = devclass_find_driver_internal(dc, classname); + mtx_unlock(&devclasses_mtx); if (dl) return (dl->driver); return (NULL); @@ -1163,9 +1249,17 @@ device_t devclass_get_device(devclass_t dc, int unit) { + device_t dev; + if (dc == NULL || unit < 0 || unit >= dc->maxunit) return (NULL); - return (dc->devices[unit]); + + mtx_lock(&devclasses_mtx); + dev = dc->devices[unit]; + DT_REF(dev); + mtx_unlock(&devclasses_mtx); + + return (dev); } /** @@ -1182,12 +1276,17 @@ devclass_get_softc(devclass_t dc, int unit) { device_t dev; + void *sc; dev = devclass_get_device(dc, unit); if (!dev) return (NULL); - return (device_get_softc(dev)); + sc = device_get_softc(dev); + mtx_lock(&devclasses_mtx); + DT_UNREF(dev); + mtx_unlock(&devclasses_mtx); + return (sc); } /** @@ -1210,20 +1309,27 @@ devclass_get_devices(devclass_t dc, device_t **devlistp, int *devcountp) { int count, i; + device_t dev; device_t *list; count = devclass_get_count(dc); list = malloc(count * sizeof(device_t), M_TEMP, M_NOWAIT|M_ZERO); - if (!list) + if (!list) { + mtx_unlock(&devclasses_mtx); return (ENOMEM); + } count = 0; + mtx_lock(&devclasses_mtx); for (i = 0; i < dc->maxunit; i++) { - if (dc->devices[i]) { - list[count] = dc->devices[i]; + dev = dc->devices[i]; + if (dev) { + DT_REF(dev); + list[count] = dev; count++; } } + mtx_unlock(&devclasses_mtx); *devlistp = list; *devcountp = count; @@ -1255,17 +1361,21 @@ int count; count = 0; + mtx_lock(&devclasses_mtx); TAILQ_FOREACH(dl, &dc->drivers, link) count++; list = malloc(count * sizeof(driver_t *), M_TEMP, M_NOWAIT); - if (list == NULL) + if (list == NULL) { + mtx_unlock(&devclasses_mtx); return (ENOMEM); + } count = 0; TAILQ_FOREACH(dl, &dc->drivers, link) { list[count] = dl->driver; count++; } + mtx_unlock(&devclasses_mtx); *listp = list; *countp = count; @@ -1283,9 +1393,11 @@ int count, i; count = 0; + mtx_lock(&devclasses_mtx); for (i = 0; i < dc->maxunit; i++) if (dc->devices[i]) count++; + mtx_unlock(&devclasses_mtx); return (count); } @@ -1798,6 +1910,7 @@ devclass_t dc; driverlink_t best = NULL; driverlink_t dl; + driver_list_t dllist; int result, pri = 0; int hasclass = (child->devclass != NULL); @@ -1814,10 +1927,20 @@ if (child->state == DS_ALIVE && (child->flags & DF_REBID) == 0) return (0); + mtx_lock(&devclasses_mtx); + TAILQ_INIT(&dllist); for (; dc; dc = dc->parent) { for (dl = first_matching_driver(dc, child); dl; dl = next_matching_driver(dc, child, dl)) { + TAILQ_INSERT_TAIL(&dllist, dl, probe_link); + } + } + mtx_unlock(&devclasses_mtx); + + while ((dl = TAILQ_FIRST(&dllist)) != NULL) { + TAILQ_REMOVE(&dllist, dl, probe_link); + { PDEBUG(("Trying %s", DRIVERNAME(dl->driver))); device_set_driver(child, dl->driver); if (!hasclass) {