diff options
author | attilio <attilio@FreeBSD.org> | 2009-08-02 14:28:40 +0000 |
---|---|---|
committer | attilio <attilio@FreeBSD.org> | 2009-08-02 14:28:40 +0000 |
commit | 7f42e47a67ad2835fbc404253f835223020256d4 (patch) | |
tree | c00d808d1df8000c2086c86613be9ec8536a5e28 /sys/kern | |
parent | ea03af42ccd07d2533707afe4d1ba08f34bdb2e9 (diff) | |
download | FreeBSD-src-7f42e47a67ad2835fbc404253f835223020256d4.zip FreeBSD-src-7f42e47a67ad2835fbc404253f835223020256d4.tar.gz |
Make the newbus subsystem Giant free by adding the new newbus sxlock.
The newbus lock is responsible for protecting newbus internIal structures,
device states and devclass flags. It is necessary to hold it when all
such datas are accessed. For the other operations, softc locking should
ensure enough protection to avoid races.
Newbus lock is automatically held when virtual operations on the device
and bus are invoked when loading the driver or when the suspend/resume
take place. For other 'spourious' operations trying to access/modify
the newbus topology, newbus lock needs to be automatically acquired and
dropped.
For the moment Giant is also acquired in some key point (modules subsystem)
in order to avoid problems before the 8.0 release as module handlers could
make assumptions about it. This Giant locking should go just after
the release happens.
Please keep in mind that the public interface can be expanded in order
to provide more support, if there are really necessities at some point
and also some bugs could arise as long as the patch needs a bit of
further testing.
Bump __FreeBSD_version in order to reflect the newbus lock introduction.
Reviewed by: ed, hps, jhb, imp, mav, scottl
No answer by: ariff, thompsa, yongari
Tested by: pho,
G. Trematerra <giovanni dot trematerra at gmail dot com>,
Brandon Gooch <jamesbrandongooch at gmail dot com>
Sponsored by: Yahoo! Incorporated
Approved by: re (ksmith)
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/subr_bus.c | 89 |
1 files changed, 82 insertions, 7 deletions
diff --git a/sys/kern/subr_bus.c b/sys/kern/subr_bus.c index 2964b8c..67f0918 100644 --- a/sys/kern/subr_bus.c +++ b/sys/kern/subr_bus.c @@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$"); #include <sys/rman.h> #include <sys/selinfo.h> #include <sys/signalvar.h> +#include <sys/sx.h> #include <sys/sysctl.h> #include <sys/systm.h> #include <sys/uio.h> @@ -192,6 +193,54 @@ void print_devclass_list(void); #endif /* + * Newbus locking facilities. + */ +static struct sx newbus_lock; + +#define NBL_LOCK_INIT() sx_init(&newbus_lock, "newbus") +#define NBL_LOCK_DESTROY() sx_destroy(&newbus_lock) +#define NBL_XLOCK() sx_xlock(&newbus_lock) +#define NBL_SLOCK() sx_slock(&newbus_lock) +#define NBL_XUNLOCK() sx_xunlock(&newbus_lock) +#define NBL_SUNLOCK() sx_sunlock(&newbus_lock) +#ifdef INVARIANTS +#define NBL_ASSERT(what) do { \ + if (cold == 0) \ + sx_assert(&newbus_lock, (what)); \ +} while (0) +#else +#define NBL_ASSERT(what) +#endif + +void +newbus_xlock() +{ + + NBL_XLOCK(); +} + +void +newbus_slock() +{ + + NBL_SLOCK(); +} + +void +newbus_xunlock() +{ + + NBL_XUNLOCK(); +} + +void +newbus_sunlock() +{ + + NBL_SUNLOCK(); +} + +/* * dev sysctl tree */ @@ -364,7 +413,6 @@ static d_poll_t devpoll; static struct cdevsw dev_cdevsw = { .d_version = D_VERSION, - .d_flags = D_NEEDGIANT, .d_open = devopen, .d_close = devclose, .d_read = devread, @@ -1061,6 +1109,7 @@ devclass_delete_driver(devclass_t busclass, driver_t *driver) int i; int error; + NBL_ASSERT(SA_XLOCKED); PDEBUG(("%s from devclass %s", driver->name, DEVCLANAME(busclass))); if (!dc) @@ -1759,6 +1808,7 @@ device_delete_child(device_t dev, device_t child) int error; device_t grandchild; + NBL_ASSERT(SA_XLOCKED); PDEBUG(("%s from %s", DEVICENAME(child), DEVICENAME(dev))); /* remove children first */ @@ -1857,7 +1907,7 @@ device_probe_child(device_t dev, device_t child) int result, pri = 0; int hasclass = (child->devclass != NULL); - GIANT_REQUIRED; + NBL_ASSERT(SA_XLOCKED); dc = dev->devclass; if (!dc) @@ -2508,7 +2558,7 @@ device_probe(device_t dev) { int error; - GIANT_REQUIRED; + NBL_ASSERT(SA_XLOCKED); if (dev->state >= DS_ALIVE && (dev->flags & DF_REBID) == 0) return (-1); @@ -2542,7 +2592,7 @@ device_probe_and_attach(device_t dev) { int error; - GIANT_REQUIRED; + NBL_ASSERT(SA_XLOCKED); error = device_probe(dev); if (error == -1) @@ -2576,6 +2626,8 @@ device_attach(device_t dev) { int error; + NBL_ASSERT(SA_XLOCKED); + device_sysctl_init(dev); if (!device_is_quiet(dev)) device_print_child(dev->parent, dev); @@ -2617,7 +2669,7 @@ device_detach(device_t dev) { int error; - GIANT_REQUIRED; + NBL_ASSERT(SA_XLOCKED); PDEBUG(("%s", DEVICENAME(dev))); if (dev->state == DS_BUSY) @@ -2661,6 +2713,8 @@ int device_quiesce(device_t dev) { + NBL_ASSERT(SA_XLOCKED); + PDEBUG(("%s", DEVICENAME(dev))); if (dev->state == DS_BUSY) return (EBUSY); @@ -2681,6 +2735,7 @@ device_quiesce(device_t dev) int device_shutdown(device_t dev) { + if (dev->state < DS_ATTACHED) return (0); return (DEVICE_SHUTDOWN(dev)); @@ -3096,6 +3151,8 @@ bus_generic_attach(device_t dev) { device_t child; + NBL_ASSERT(SA_XLOCKED); + TAILQ_FOREACH(child, &dev->children, link) { device_probe_and_attach(child); } @@ -3116,6 +3173,8 @@ bus_generic_detach(device_t dev) device_t child; int error; + NBL_ASSERT(SA_XLOCKED); + if (dev->state != DS_ATTACHED) return (EBUSY); @@ -3996,6 +4055,7 @@ root_bus_module_handler(module_t mod, int what, void* arg) switch (what) { case MOD_LOAD: TAILQ_INIT(&bus_data_devices); + NBL_LOCK_INIT(); kobj_class_compile((kobj_class_t) &root_driver); root_bus = make_device(NULL, "root", 0); root_bus->desc = "System root bus"; @@ -4055,14 +4115,28 @@ driver_module_handler(module_t mod, int what, void *arg) kobj_class_t driver; int error, pass; + error = 0; dmd = (struct driver_module_data *)arg; + + /* + * If MOD_SHUTDOWN is passed, return immediately in order to + * avoid unnecessary locking and a LOR with the modules sx lock. + */ + if (what == MOD_SHUTDOWN) + return (EOPNOTSUPP); + NBL_XLOCK(); bus_devclass = devclass_find_internal(dmd->dmd_busname, NULL, TRUE); - error = 0; + if (bus_devclass == NULL) { + NBL_XUNLOCK(); + return (ENOMEM); + } - switch (what) { + switch (what) { case MOD_LOAD: if (dmd->dmd_chainevh) error = dmd->dmd_chainevh(mod,what,dmd->dmd_chainarg); + if (error != 0) + break; pass = dmd->dmd_pass; driver = dmd->dmd_driver; @@ -4115,6 +4189,7 @@ driver_module_handler(module_t mod, int what, void *arg) error = EOPNOTSUPP; break; } + NBL_XUNLOCK(); return (error); } |