diff options
author | jhb <jhb@FreeBSD.org> | 2012-04-11 20:57:41 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2012-04-11 20:57:41 +0000 |
commit | 294ae9574dbae2eb396badbd71d53759f665a50e (patch) | |
tree | 01fe2ebbcc44439ae8b4b463d26d707df4166b48 | |
parent | 31bc0a8bff2a66718684b68012fa4be1ed30f522 (diff) | |
download | FreeBSD-src-294ae9574dbae2eb396badbd71d53759f665a50e.zip FreeBSD-src-294ae9574dbae2eb396badbd71d53759f665a50e.tar.gz |
Allow device_busy() and device_unbusy() to be invoked while a device is
being attached. This is implemented by adding a new DS_ATTACHING state
while a device's DEVICE_ATTACH() method is being invoked. A driver is
required to not fail an attach of a busy device. The device's state will
be promoted to DS_BUSY rather than DS_ACTIVE() if the device was marked
busy during DEVICE_ATTACH().
Reviewed by: kib
MFC after: 1 week
-rw-r--r-- | sys/kern/subr_bus.c | 18 | ||||
-rw-r--r-- | sys/sys/bus.h | 1 |
2 files changed, 14 insertions, 5 deletions
diff --git a/sys/kern/subr_bus.c b/sys/kern/subr_bus.c index d485b9f..e72ab77 100644 --- a/sys/kern/subr_bus.c +++ b/sys/kern/subr_bus.c @@ -2472,12 +2472,13 @@ device_disable(device_t dev) void device_busy(device_t dev) { - if (dev->state < DS_ATTACHED) + if (dev->state < DS_ATTACHING) panic("device_busy: called for unattached device"); if (dev->busy == 0 && dev->parent) device_busy(dev->parent); dev->busy++; - dev->state = DS_BUSY; + if (dev->state == DS_ATTACHED) + dev->state = DS_BUSY; } /** @@ -2486,14 +2487,16 @@ device_busy(device_t dev) void device_unbusy(device_t dev) { - if (dev->state != DS_BUSY) + if (dev->busy != 0 && dev->state != DS_BUSY && + dev->state != DS_ATTACHING) panic("device_unbusy: called for non-busy device %s", device_get_nameunit(dev)); dev->busy--; if (dev->busy == 0) { if (dev->parent) device_unbusy(dev->parent); - dev->state = DS_ATTACHED; + if (dev->state == DS_BUSY) + dev->state = DS_ATTACHED; } } @@ -2729,6 +2732,7 @@ device_attach(device_t dev) device_sysctl_init(dev); if (!device_is_quiet(dev)) device_print_child(dev->parent, dev); + dev->state = DS_ATTACHING; if ((error = DEVICE_ATTACH(dev)) != 0) { printf("device_attach: %s%d attach returned %d\n", dev->driver->name, dev->unit, error); @@ -2736,11 +2740,15 @@ device_attach(device_t dev) devclass_delete_device(dev->devclass, dev); (void)device_set_driver(dev, NULL); device_sysctl_fini(dev); + KASSERT(dev->busy == 0, ("attach failed but busy")); dev->state = DS_NOTPRESENT; return (error); } device_sysctl_update(dev); - dev->state = DS_ATTACHED; + if (dev->busy) + dev->state = DS_BUSY; + else + dev->state = DS_ATTACHED; dev->flags &= ~DF_DONENOMATCH; devadded(dev); return (0); diff --git a/sys/sys/bus.h b/sys/sys/bus.h index 1c16bd6..fff745c 100644 --- a/sys/sys/bus.h +++ b/sys/sys/bus.h @@ -52,6 +52,7 @@ struct u_businfo { typedef enum device_state { DS_NOTPRESENT = 10, /**< @brief not probed or probe failed */ DS_ALIVE = 20, /**< @brief probe succeeded */ + DS_ATTACHING = 25, /**< @brief currently attaching */ DS_ATTACHED = 30, /**< @brief attach method called */ DS_BUSY = 40 /**< @brief device is open */ } device_state_t; |