PERFORCE change 163715 for review
Scott Long
scottl at FreeBSD.org
Sun Jun 7 14:37:59 UTC 2009
http://perforce.freebsd.org/chv.cgi?CH=163715
Change 163715 by scottl at 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) {
More information about the p4-projects
mailing list