Index: kern/subr_bus.c =================================================================== --- kern/subr_bus.c (revision 196087) +++ kern/subr_bus.c (working copy) @@ -1917,7 +1917,7 @@ device_probe_child(device_t dev, device_t child) * If the state is already probed, then return. However, don't * return if we can rebid this object. */ - if (child->state == DS_ALIVE && (child->flags & DF_REBID) == 0) + if (child->state >= DS_ALIVE && (child->flags & DF_REBID) == 0) return (0); for (; dc; dc = dc->parent) { @@ -2440,7 +2440,7 @@ device_is_enabled(device_t dev) int device_is_alive(device_t dev) { - return (dev->state >= DS_ALIVE); + return (dev->state >= DS_ALIVE && dev->state < DS_DETACHING); } /** @@ -2450,7 +2450,7 @@ device_is_alive(device_t dev) int device_is_attached(device_t dev) { - return (dev->state >= DS_ATTACHED); + return (dev->state >= DS_ATTACHED && dev->state < DS_DETACHING); } /** @@ -2628,13 +2628,20 @@ device_attach(device_t dev) NBL_ASSERT(SA_XLOCKED); + if (dev->state != DS_ALIVE) + return (0); device_sysctl_init(dev); if (!device_is_quiet(dev)) device_print_child(dev->parent, dev); + dev->state = DS_ATTACHING; + NBL_XUNLOCK(); if ((error = DEVICE_ATTACH(dev)) != 0) { printf("device_attach: %s%d attach returned %d\n", dev->driver->name, dev->unit, error); /* Unset the class; set in device_probe_child */ + NBL_XLOCK(); + KASSERT(dev->state == DS_ATTACHING, + ("%s: device state changed unappropriately", __func__)); if (dev->devclass == NULL) device_set_devclass(dev, NULL); device_set_driver(dev, NULL); @@ -2642,6 +2649,9 @@ device_attach(device_t dev) dev->state = DS_NOTPRESENT; return (error); } + NBL_XLOCK(); + KASSERT(dev->state == DS_ATTACHING, + ("%s: device state changed unappropriately", __func__)); device_sysctl_update(dev); dev->state = DS_ATTACHED; devadded(dev); @@ -2676,9 +2686,19 @@ device_detach(device_t dev) return (EBUSY); if (dev->state != DS_ATTACHED) return (0); + dev->state = DS_DETACHING; + NBL_XUNLOCK(); - if ((error = DEVICE_DETACH(dev)) != 0) + if ((error = DEVICE_DETACH(dev)) != 0) { + NBL_XLOCK(); + KASSERT(dev->state == DS_DETACHING, + ("%s: device state changed unappropriately", __func__)); + dev->state = DS_ATTACHED; return (error); + } + NBL_XLOCK(); + KASSERT(dev->state == DS_DETACHING, + ("%s: device state changed unappropriately", __func__)); devremoved(dev); if (!device_is_quiet(dev)) device_printf(dev, "detached\n"); @@ -2735,10 +2755,28 @@ device_quiesce(device_t dev) int device_shutdown(device_t dev) { + device_state_t prev; + int error; - if (dev->state < DS_ATTACHED) + NBL_ASSERT(SA_XLOCKED); + if (dev->state != DS_ATTACHED && dev->state != DS_BUSY) return (0); - return (DEVICE_SHUTDOWN(dev)); + prev = dev->state; + dev->state = DS_SHUTTINGDOWN; + NBL_XUNLOCK(); + error = DEVICE_SHUTDOWN(dev); + NBL_XLOCK(); + KASSERT(dev->state == DS_SHUTTINGDOWN, + ("%s: device state changed unappropriately", __func__)); + + /* + * System is going to reboot so we don't care about returning + * with the state on DS_SHUTTINGDOWN. Probabilly, unwinding the + * state in case of failed shutdown is paranoic. + */ + if (error != 0) + dev->state = prev; + return (error); } /** @@ -4131,7 +4169,7 @@ driver_module_handler(module_t mod, int what, void return (ENOMEM); } - switch (what) { + switch (what) { case MOD_LOAD: if (dmd->dmd_chainevh) error = dmd->dmd_chainevh(mod,what,dmd->dmd_chainarg); Index: sys/bus.h =================================================================== --- sys/bus.h (revision 196087) +++ sys/bus.h (working copy) @@ -52,8 +52,11 @@ struct u_businfo { typedef enum device_state { DS_NOTPRESENT, /**< @brief not probed or probe failed */ DS_ALIVE, /**< @brief probe succeeded */ + DS_ATTACHING, /**< @brief attaching in progress */ DS_ATTACHED, /**< @brief attach method called */ - DS_BUSY /**< @brief device is open */ + DS_BUSY, /**< @brief device is open */ + DS_DETACHING, /**< @brief detaching in progress */ + DS_SHUTTINGDOWN, /**< @brief shutdown in progress */ } device_state_t; /**