Module Name: src
Committed By: dyoung
Date: Thu Nov 12 19:10:31 UTC 2009
Modified Files:
src/sys/kern: subr_autoconf.c
src/sys/sys: device.h
Log Message:
Move a device-deactivation pattern that is replicated throughout
the system into config_deactivate(dev): deactivate dev and all of
its descendants. Block all interrupts while calling each device's
activation hook, ca_activate. Now it is possible to simplify or
to delete several device-activation hooks throughout the system.
Do not deactivate a driver while detaching it! If the driver was
already deactivated (because of accidental/emergency removal), let
the driver cope with the knowledge that DVF_ACTIVE has been cleared.
Otherwise, let the driver access the underlying hardware (so that
it can flush caches, restore original register settings, et cetera)
until it exits its device-detachment hook.
Let multiple readers and writers simultaneously access the system's
device_t list, alldevs, from either interrupt or thread context:
postpone changing alldevs linkages and freeing autoconf device
structures until a garbage-collection phase that runs after all
readers & writers have left the list.
Give device iterators (deviter(9)) a consistent view of alldevs no
matter whether device_t's are added and deleted during iteration:
keep a global alldevs generation number. When an iterator enters
alldevs, record the current generation number in the iterator and
increase the global number. When a device_t is created, label it
with the current global generation number. When a device_t is
deleted, add a second label, the current global generation number.
During iteration, compare a device_t's added- and deleted-generation
with the iterator's generation and skip a device_t that was deleted
before the iterator entered the list or added after the iterator
entered the list.
The alldevs generation number is never 0. The garbage collector
reaps device_t's whose delete-generation number is non-zero.
Make alldevs private to sys/kern/subr_autoconf.c. Use deviter(9)
to access it.
To generate a diff of this commit:
cvs rdiff -u -r1.186 -r1.187 src/sys/kern/subr_autoconf.c
cvs rdiff -u -r1.124 -r1.125 src/sys/sys/device.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/kern/subr_autoconf.c
diff -u src/sys/kern/subr_autoconf.c:1.186 src/sys/kern/subr_autoconf.c:1.187
--- src/sys/kern/subr_autoconf.c:1.186 Mon Oct 12 23:33:02 2009
+++ src/sys/kern/subr_autoconf.c Thu Nov 12 19:10:30 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: subr_autoconf.c,v 1.186 2009/10/12 23:33:02 yamt Exp $ */
+/* $NetBSD: subr_autoconf.c,v 1.187 2009/11/12 19:10:30 dyoung Exp $ */
/*
* Copyright (c) 1996, 2000 Christopher G. Demetriou
@@ -77,7 +77,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: subr_autoconf.c,v 1.186 2009/10/12 23:33:02 yamt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: subr_autoconf.c,v 1.187 2009/11/12 19:10:30 dyoung Exp $");
#ifdef _KERNEL_OPT
#include "opt_ddb.h"
@@ -165,10 +165,13 @@
static char *number(char *, int);
static void mapply(struct matchinfo *, cfdata_t);
static device_t config_devalloc(const device_t, const cfdata_t, const int *);
-static void config_devdealloc(device_t);
+static void config_devdelete(device_t);
static void config_makeroom(int, struct cfdriver *);
static void config_devlink(device_t);
-static void config_devunlink(device_t);
+static void config_alldevs_unlock(int);
+static int config_alldevs_lock(void);
+
+static void config_collect_garbage(void);
static void pmflock_debug(device_t, const char *, int);
@@ -202,12 +205,12 @@
static int config_finalize_done;
/* list of all devices */
-struct devicelist alldevs = TAILQ_HEAD_INITIALIZER(alldevs);
-kcondvar_t alldevs_cv;
-kmutex_t alldevs_mtx;
-static int alldevs_nread = 0;
-static int alldevs_nwrite = 0;
-static lwp_t *alldevs_writer = NULL;
+static struct devicelist alldevs = TAILQ_HEAD_INITIALIZER(alldevs);
+static kmutex_t alldevs_mtx;
+static volatile bool alldevs_garbage = false;
+static volatile devgen_t alldevs_gen = 1;
+static volatile int alldevs_nread = 0;
+static volatile int alldevs_nwrite = 0;
static int config_pending; /* semaphore for mountroot */
static kmutex_t config_misc_lock;
@@ -238,8 +241,7 @@
KASSERT(config_initialized == false);
- mutex_init(&alldevs_mtx, MUTEX_DEFAULT, IPL_NONE);
- cv_init(&alldevs_cv, "alldevs");
+ mutex_init(&alldevs_mtx, MUTEX_DEFAULT, IPL_HIGH);
mutex_init(&config_misc_lock, MUTEX_DEFAULT, IPL_NONE);
cv_init(&config_misc_cv, "cfgmisc");
@@ -366,13 +368,21 @@
int
config_cfdriver_detach(struct cfdriver *cd)
{
- int i;
+ int i, rc = 0, s;
+ s = config_alldevs_lock();
+ config_collect_garbage();
/* Make sure there are no active instances. */
for (i = 0; i < cd->cd_ndevs; i++) {
- if (cd->cd_devs[i] != NULL)
- return EBUSY;
+ if (cd->cd_devs[i] != NULL) {
+ rc = EBUSY;
+ break;
+ }
}
+ config_alldevs_unlock(s);
+
+ if (rc != 0)
+ return rc;
/* ...and no attachments loaded. */
if (LIST_EMPTY(&cd->cd_attach) == 0)
@@ -433,19 +443,27 @@
{
struct cfdriver *cd;
device_t dev;
- int i;
+ int i, rc = 0, s;
cd = config_cfdriver_lookup(driver);
if (cd == NULL)
return ESRCH;
+ s = config_alldevs_lock();
+ config_collect_garbage();
/* Make sure there are no active instances. */
for (i = 0; i < cd->cd_ndevs; i++) {
if ((dev = cd->cd_devs[i]) == NULL)
continue;
- if (dev->dv_cfattach == ca)
- return EBUSY;
+ if (dev->dv_cfattach == ca) {
+ rc = EBUSY;
+ break;
+ }
}
+ config_alldevs_unlock(s);
+
+ if (rc != 0)
+ return rc;
LIST_REMOVE(ca, ca_list);
@@ -923,6 +941,11 @@
/*
* Expand the size of the cd_devs array if necessary.
+ *
+ * The caller must hold alldevs_mtx. config_makeroom() may release and
+ * re-acquire alldevs_mtx, so callers should re-check conditions such
+ * as alldevs_nwrite == 0 and alldevs_nread == 0 when config_makeroom()
+ * returns.
*/
static void
config_makeroom(int n, struct cfdriver *cd)
@@ -930,8 +953,11 @@
int old, new;
device_t *nsp;
+ alldevs_nwrite++;
+ mutex_exit(&alldevs_mtx);
+
if (n < cd->cd_ndevs)
- return;
+ goto out;
/*
* Need to expand the array.
@@ -943,7 +969,6 @@
new = old * 2;
while (new <= n)
new *= 2;
- cd->cd_ndevs = new;
nsp = kmem_alloc(sizeof(device_t [new]), KM_SLEEP);
if (nsp == NULL)
panic("config_attach: %sing dev array",
@@ -953,37 +978,50 @@
memcpy(nsp, cd->cd_devs, sizeof(device_t [old]));
kmem_free(cd->cd_devs, sizeof(device_t [old]));
}
+ cd->cd_ndevs = new;
cd->cd_devs = nsp;
+out:
+ mutex_enter(&alldevs_mtx);
+ alldevs_nwrite--;
}
static void
config_devlink(device_t dev)
{
struct cfdriver *cd = dev->dv_cfdriver;
+ int s;
/* put this device in the devices array */
+ s = config_alldevs_lock();
config_makeroom(dev->dv_unit, cd);
if (cd->cd_devs[dev->dv_unit])
panic("config_attach: duplicate %s", device_xname(dev));
cd->cd_devs[dev->dv_unit] = dev;
/* It is safe to add a device to the tail of the list while
- * readers are in the list, but not while a writer is in
- * the list. Wait for any writer to complete.
+ * readers and writers are in the list.
*/
- mutex_enter(&alldevs_mtx);
- while (alldevs_nwrite != 0 && alldevs_writer != curlwp)
- cv_wait(&alldevs_cv, &alldevs_mtx);
+ dev->dv_add_gen = alldevs_gen;
TAILQ_INSERT_TAIL(&alldevs, dev, dv_list); /* link up */
- cv_signal(&alldevs_cv);
- mutex_exit(&alldevs_mtx);
+ config_alldevs_unlock(s);
}
+/*
+ * Caller must hold alldevs_mtx. config_devdelete() may release and
+ * re-acquire alldevs_mtx, so callers should re-check conditions such as
+ * alldevs_nwrite == 0 && alldevs_nread == 0 after config_devdelete()
+ * returns.
+ */
static void
-config_devunlink(device_t dev)
+config_devdelete(device_t dev)
{
+ device_lock_t dvl = device_getlock(dev);
+ int priv = (dev->dv_flags & DVF_PRIV_ALLOC);
struct cfdriver *cd = dev->dv_cfdriver;
- int i;
+ device_t *devs = NULL;
+ int i, ndevs = 0;
+
+ KASSERT(mutex_owned(&alldevs_mtx));
/* Unlink from device list. */
TAILQ_REMOVE(&alldevs, dev, dv_list);
@@ -996,14 +1034,47 @@
*/
for (i = 0; i < cd->cd_ndevs; i++) {
if (cd->cd_devs[i] != NULL)
- return;
+ break;
+ }
+ /* nothing found. unlink, now. deallocate below. */
+ if (i == cd->cd_ndevs) {
+ ndevs = cd->cd_ndevs;
+ devs = cd->cd_devs;
+ cd->cd_devs = NULL;
+ cd->cd_ndevs = 0;
+ }
+
+ mutex_exit(&alldevs_mtx);
+
+ KASSERT(!mutex_owned(&alldevs_mtx));
+
+ if (devs != NULL)
+ kmem_free(devs, sizeof(device_t [ndevs]));
+
+ cv_destroy(&dvl->dvl_cv);
+ mutex_destroy(&dvl->dvl_mtx);
+
+ KASSERT(dev->dv_properties != NULL);
+ prop_object_release(dev->dv_properties);
+
+ if (dev->dv_activity_handlers)
+ panic("%s with registered handlers", __func__);
+
+ if (dev->dv_locators) {
+ size_t amount = *--dev->dv_locators;
+ kmem_free(dev->dv_locators, amount);
}
- /* nothing found; deallocate */
- kmem_free(cd->cd_devs, sizeof(device_t [cd->cd_ndevs]));
- cd->cd_devs = NULL;
- cd->cd_ndevs = 0;
+
+ if (dev->dv_cfattach->ca_devsize > 0)
+ kmem_free(dev->dv_private, dev->dv_cfattach->ca_devsize);
+ if (priv)
+ kmem_free(dev, sizeof(*dev));
+
+ KASSERT(!mutex_owned(&alldevs_mtx));
+
+ mutex_enter(&alldevs_mtx);
}
-
+
static device_t
config_devalloc(const device_t parent, const cfdata_t cf, const int *locs)
{
@@ -1011,7 +1082,7 @@
struct cfattach *ca;
size_t lname, lunit;
const char *xunit;
- int myunit;
+ int myunit, s;
char num[10];
device_t dev;
void *dev_private;
@@ -1031,6 +1102,8 @@
panic("config_devalloc: %s", cf->cf_atname);
#ifndef __BROKEN_CONFIG_UNIT_USAGE
+ s = config_alldevs_lock();
+ config_collect_garbage();
if (cf->cf_fstate == FSTATE_STAR) {
for (myunit = cf->cf_unit; myunit < cd->cd_ndevs; myunit++)
if (cd->cd_devs[myunit] == NULL)
@@ -1042,8 +1115,11 @@
} else {
myunit = cf->cf_unit;
if (myunit < cd->cd_ndevs && cd->cd_devs[myunit] != NULL)
- return NULL;
- }
+ myunit = -1;
+ }
+ config_alldevs_unlock(s);
+ if (myunit == -1)
+ return NULL;
#else
myunit = cf->cf_unit;
#endif /* ! __BROKEN_CONFIG_UNIT_USAGE */
@@ -1116,32 +1192,6 @@
return dev;
}
-static void
-config_devdealloc(device_t dev)
-{
- device_lock_t dvl = device_getlock(dev);
- int priv = (dev->dv_flags & DVF_PRIV_ALLOC);
-
- cv_destroy(&dvl->dvl_cv);
- mutex_destroy(&dvl->dvl_mtx);
-
- KASSERT(dev->dv_properties != NULL);
- prop_object_release(dev->dv_properties);
-
- if (dev->dv_activity_handlers)
- panic("config_devdealloc with registered handlers");
-
- if (dev->dv_locators) {
- size_t amount = *--dev->dv_locators;
- kmem_free(dev->dv_locators, amount);
- }
-
- if (dev->dv_cfattach->ca_devsize > 0)
- kmem_free(dev->dv_private, dev->dv_cfattach->ca_devsize);
- if (priv)
- kmem_free(dev, sizeof(*dev));
-}
-
/*
* Attach a found device.
*/
@@ -1284,6 +1334,33 @@
}
/*
+ * Caller must hold alldevs_mtx. config_collect_garbage() may
+ * release and re-acquire alldevs_mtx, so callers should re-check
+ * conditions such as alldevs_nwrite == 0 && alldevs_nread == 0 after
+ * config_collect_garbage() returns.
+ */
+static void
+config_collect_garbage(void)
+{
+ device_t dv;
+
+ KASSERT(mutex_owned(&alldevs_mtx));
+
+ while (alldevs_nwrite == 0 && alldevs_nread == 0 && alldevs_garbage) {
+ TAILQ_FOREACH(dv, &alldevs, dv_list) {
+ if (dv->dv_del_gen != 0)
+ break;
+ }
+ if (dv == NULL) {
+ alldevs_garbage = false;
+ break;
+ }
+ config_devdelete(dv);
+ }
+ KASSERT(mutex_owned(&alldevs_mtx));
+}
+
+/*
* Detach a device. Optionally forced (e.g. because of hardware
* removal) and quiet. Returns zero if successful, non-zero
* (an error code) otherwise.
@@ -1302,7 +1379,7 @@
#ifdef DIAGNOSTIC
device_t d;
#endif
- int rv = 0;
+ int rv = 0, s;
#ifdef DIAGNOSTIC
cf = dev->dv_cfdata;
@@ -1317,51 +1394,43 @@
ca = dev->dv_cfattach;
KASSERT(ca != NULL);
- KASSERT(curlwp != NULL);
- mutex_enter(&alldevs_mtx);
- if (alldevs_nwrite > 0 && alldevs_writer == NULL)
- ;
- else while (alldevs_nread != 0 ||
- (alldevs_nwrite != 0 && alldevs_writer != curlwp))
- cv_wait(&alldevs_cv, &alldevs_mtx);
- if (alldevs_nwrite++ == 0)
- alldevs_writer = curlwp;
- mutex_exit(&alldevs_mtx);
+ s = config_alldevs_lock();
+ if (dev->dv_del_gen != 0) {
+ config_alldevs_unlock(s);
+#ifdef DIAGNOSTIC
+ printf("%s: %s is already detached\n", __func__,
+ device_xname(dev));
+#endif /* DIAGNOSTIC */
+ return ENOENT;
+ }
+ alldevs_nwrite++;
+ config_alldevs_unlock(s);
- /*
- * Ensure the device is deactivated. If the device doesn't
- * have an activation entry point, we allow DVF_ACTIVE to
- * remain set. Otherwise, if DVF_ACTIVE is still set, the
- * device is busy, and the detach fails.
- */
if (!detachall &&
(flags & (DETACH_SHUTDOWN|DETACH_FORCE)) == DETACH_SHUTDOWN &&
(dev->dv_flags & DVF_DETACH_SHUTDOWN) == 0) {
rv = EOPNOTSUPP;
- } else if ((rv = config_deactivate(dev)) == EOPNOTSUPP)
- rv = 0; /* Do not treat EOPNOTSUPP as an error */
+ } else if (ca->ca_detach != NULL) {
+ rv = (*ca->ca_detach)(dev, flags);
+ } else
+ rv = EOPNOTSUPP;
/*
- * Try to detach the device. If that's not possible, then
- * we either panic() (for the forced but failed case), or
- * return an error.
+ * If it was not possible to detach the device, then we either
+ * panic() (for the forced but failed case), or return an error.
+ *
+ * If it was possible to detach the device, ensure that the
+ * device is deactivated.
*/
- if (rv == 0) {
- if (ca->ca_detach != NULL)
- rv = (*ca->ca_detach)(dev, flags);
- else
- rv = EOPNOTSUPP;
- }
- if (rv != 0) {
- if ((flags & DETACH_FORCE) == 0)
- goto out;
- else
- panic("config_detach: forced detach of %s failed (%d)",
- device_xname(dev), rv);
+ if (rv == 0)
+ dev->dv_flags &= ~DVF_ACTIVE;
+ else if ((flags & DETACH_FORCE) == 0)
+ goto out;
+ else {
+ panic("config_detach: forced detach of %s failed (%d)",
+ device_xname(dev), rv);
}
- dev->dv_flags &= ~DVF_ACTIVE;
-
/*
* The device has now been successfully detached.
*/
@@ -1378,7 +1447,7 @@
*/
for (d = TAILQ_NEXT(dev, dv_list); d != NULL;
d = TAILQ_NEXT(d, dv_list)) {
- if (d->dv_parent == dev) {
+ if (d->dv_parent == dev && d->dv_del_gen == 0) {
printf("config_detach: detached device %s"
" has children %s\n", device_xname(dev), device_xname(d));
panic("config_detach");
@@ -1416,20 +1485,24 @@
}
}
- config_devunlink(dev);
-
if (dev->dv_cfdata != NULL && (flags & DETACH_QUIET) == 0)
aprint_normal_dev(dev, "detached\n");
- config_devdealloc(dev);
-
out:
- mutex_enter(&alldevs_mtx);
+ s = config_alldevs_lock();
KASSERT(alldevs_nwrite != 0);
- if (--alldevs_nwrite == 0)
- alldevs_writer = NULL;
- cv_signal(&alldevs_cv);
- mutex_exit(&alldevs_mtx);
+ --alldevs_nwrite;
+ if (rv != 0)
+ ;
+ else if (dev->dv_del_gen != 0)
+ ;
+ else {
+ dev->dv_del_gen = alldevs_gen;
+ alldevs_garbage = true;
+ }
+ config_collect_garbage();
+ config_alldevs_unlock(s);
+
return rv;
}
@@ -1497,21 +1570,49 @@
return progress;
}
+static bool
+device_is_ancestor_of(device_t ancestor, device_t descendant)
+{
+ device_t dv;
+
+ for (dv = descendant; dv != NULL; dv = device_parent(dv)) {
+ if (device_parent(dv) == ancestor)
+ return true;
+ }
+ return false;
+}
+
int
config_deactivate(device_t dev)
{
- const struct cfattach *ca = dev->dv_cfattach;
- int rv = 0, oflags = dev->dv_flags;
+ deviter_t di;
+ const struct cfattach *ca;
+ device_t descendant;
+ int s, rv = 0, oflags;
- if (ca->ca_activate == NULL)
- return EOPNOTSUPP;
+ for (descendant = deviter_first(&di, DEVITER_F_ROOT_FIRST);
+ descendant != NULL;
+ descendant = deviter_next(&di)) {
+ if (dev != descendant &&
+ !device_is_ancestor_of(dev, descendant))
+ continue;
- if (dev->dv_flags & DVF_ACTIVE) {
- dev->dv_flags &= ~DVF_ACTIVE;
- rv = (*ca->ca_activate)(dev, DVACT_DEACTIVATE);
- if (rv)
- dev->dv_flags = oflags;
+ if ((descendant->dv_flags & DVF_ACTIVE) == 0)
+ continue;
+
+ ca = descendant->dv_cfattach;
+ oflags = descendant->dv_flags;
+
+ descendant->dv_flags &= ~DVF_ACTIVE;
+ if (ca->ca_activate == NULL)
+ continue;
+ s = splhigh();
+ rv = (*ca->ca_activate)(descendant, DVACT_DEACTIVATE);
+ splx(s);
+ if (rv != 0)
+ descendant->dv_flags = oflags;
}
+ deviter_release(&di);
return rv;
}
@@ -1740,6 +1841,23 @@
mutex_exit(&config_misc_lock);
}
+static int
+config_alldevs_lock(void)
+{
+ int s;
+
+ s = splhigh();
+ mutex_enter(&alldevs_mtx);
+ return s;
+}
+
+static void
+config_alldevs_unlock(int s)
+{
+ mutex_exit(&alldevs_mtx);
+ splx(s);
+}
+
/*
* device_lookup:
*
@@ -1748,11 +1866,20 @@
device_t
device_lookup(cfdriver_t cd, int unit)
{
+ device_t dv;
+ int s;
+ s = config_alldevs_lock();
+ config_collect_garbage();
+ KASSERT(mutex_owned(&alldevs_mtx));
if (unit < 0 || unit >= cd->cd_ndevs)
- return NULL;
-
- return cd->cd_devs[unit];
+ dv = NULL;
+ else
+ dv = cd->cd_devs[unit];
+ config_alldevs_unlock(s);
+
+ KASSERT(!mutex_owned(&alldevs_mtx));
+ return dv;
}
/*
@@ -1764,14 +1891,22 @@
device_lookup_private(cfdriver_t cd, int unit)
{
device_t dv;
+ int s;
+ void *priv;
+ s = config_alldevs_lock();
+ config_collect_garbage();
+ KASSERT(mutex_owned(&alldevs_mtx));
if (unit < 0 || unit >= cd->cd_ndevs)
- return NULL;
-
- if ((dv = cd->cd_devs[unit]) == NULL)
- return NULL;
+ priv = NULL;
+ else if ((dv = cd->cd_devs[unit]) == NULL)
+ priv = NULL;
+ else
+ priv = dv->dv_private;
+ config_alldevs_unlock(s);
- return dv->dv_private;
+ KASSERT(!mutex_owned(&alldevs_mtx));
+ return priv;
}
/*
@@ -2363,6 +2498,20 @@
old_handlers[i] = NULL;
}
+/* Return true iff the device_t `dev' exists at generation `gen'. */
+static bool
+device_exists_at(device_t dv, devgen_t gen)
+{
+ return (dv->dv_del_gen == 0 || dv->dv_del_gen > gen) &&
+ dv->dv_add_gen <= gen;
+}
+
+static bool
+deviter_visits(const deviter_t *di, device_t dv)
+{
+ return device_exists_at(dv, di->di_gen);
+}
+
/*
* Device Iteration
*
@@ -2423,43 +2572,37 @@
deviter_init(deviter_t *di, deviter_flags_t flags)
{
device_t dv;
- bool rw;
+ int s;
- mutex_enter(&alldevs_mtx);
- if ((flags & DEVITER_F_SHUTDOWN) != 0) {
- flags |= DEVITER_F_RW;
- alldevs_nwrite++;
- alldevs_writer = NULL;
- alldevs_nread = 0;
- } else {
- rw = (flags & DEVITER_F_RW) != 0;
+ memset(di, 0, sizeof(*di));
- if (alldevs_nwrite > 0 && alldevs_writer == NULL)
- ;
- else while ((alldevs_nwrite != 0 && alldevs_writer != curlwp) ||
- (rw && alldevs_nread != 0))
- cv_wait(&alldevs_cv, &alldevs_mtx);
-
- if (rw) {
- if (alldevs_nwrite++ == 0)
- alldevs_writer = curlwp;
- } else
- alldevs_nread++;
- }
- mutex_exit(&alldevs_mtx);
+ s = config_alldevs_lock();
+ if ((flags & DEVITER_F_SHUTDOWN) != 0)
+ flags |= DEVITER_F_RW;
- memset(di, 0, sizeof(*di));
+ if ((flags & DEVITER_F_RW) != 0)
+ alldevs_nwrite++;
+ else
+ alldevs_nread++;
+ di->di_gen = alldevs_gen++;
+ config_alldevs_unlock(s);
di->di_flags = flags;
switch (di->di_flags & (DEVITER_F_LEAVES_FIRST|DEVITER_F_ROOT_FIRST)) {
case DEVITER_F_LEAVES_FIRST:
- TAILQ_FOREACH(dv, &alldevs, dv_list)
+ TAILQ_FOREACH(dv, &alldevs, dv_list) {
+ if (!deviter_visits(di, dv))
+ continue;
di->di_curdepth = MAX(di->di_curdepth, dv->dv_depth);
+ }
break;
case DEVITER_F_ROOT_FIRST:
- TAILQ_FOREACH(dv, &alldevs, dv_list)
+ TAILQ_FOREACH(dv, &alldevs, dv_list) {
+ if (!deviter_visits(di, dv))
+ continue;
di->di_maxdepth = MAX(di->di_maxdepth, dv->dv_depth);
+ }
break;
default:
break;
@@ -2485,7 +2628,7 @@
}
static device_t
-deviter_next1(deviter_t *di)
+deviter_next2(deviter_t *di)
{
device_t dv;
@@ -2501,6 +2644,18 @@
return dv;
}
+static device_t
+deviter_next1(deviter_t *di)
+{
+ device_t dv;
+
+ do {
+ dv = deviter_next2(di);
+ } while (dv != NULL && !deviter_visits(di, dv));
+
+ return dv;
+}
+
device_t
deviter_next(deviter_t *di)
{
@@ -2536,20 +2691,15 @@
deviter_release(deviter_t *di)
{
bool rw = (di->di_flags & DEVITER_F_RW) != 0;
+ int s;
- mutex_enter(&alldevs_mtx);
- if (!rw) {
+ s = config_alldevs_lock();
+ if (rw)
+ --alldevs_nwrite;
+ else
--alldevs_nread;
- cv_signal(&alldevs_cv);
- } else if (alldevs_nwrite > 0 && alldevs_writer == NULL) {
- --alldevs_nwrite; /* shutting down: do not signal */
- } else {
- KASSERT(alldevs_nwrite != 0);
- if (--alldevs_nwrite == 0)
- alldevs_writer = NULL;
- cv_signal(&alldevs_cv);
- }
- mutex_exit(&alldevs_mtx);
+ /* XXX wake a garbage-collection thread */
+ config_alldevs_unlock(s);
}
static void
Index: src/sys/sys/device.h
diff -u src/sys/sys/device.h:1.124 src/sys/sys/device.h:1.125
--- src/sys/sys/device.h:1.124 Mon Sep 21 12:14:47 2009
+++ src/sys/sys/device.h Thu Nov 12 19:10:30 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: device.h,v 1.124 2009/09/21 12:14:47 pooka Exp $ */
+/* $NetBSD: device.h,v 1.125 2009/11/12 19:10:30 dyoung Exp $ */
/*
* Copyright (c) 1996, 2000 Christopher G. Demetriou
@@ -174,6 +174,9 @@
bool (*dv_class_resume)(device_t PMF_FN_PROTO);
void (*dv_class_deregister)(device_t);
+ devgen_t dv_add_gen,
+ dv_del_gen;
+
struct device_lock dv_lock;
device_suspensor_t dv_bus_suspensors[DEVICE_SUSPENSORS_MAX];
device_suspensor_t dv_driver_suspensors[DEVICE_SUSPENSORS_MAX];
@@ -205,6 +208,7 @@
deviter_flags_t di_flags;
int di_curdepth;
int di_maxdepth;
+ devgen_t di_gen;
};
typedef struct deviter deviter_t;
@@ -412,7 +416,6 @@
#ifdef _KERNEL
extern struct cfdriverlist allcfdrivers;/* list of all cfdrivers */
-extern struct devicelist alldevs; /* list of all devices */
extern struct cftablelist allcftables; /* list of all cfdata tables */
extern device_t booted_device; /* the device we booted from */
extern device_t booted_wedge; /* the wedge on that device */