diff options
Diffstat (limited to 'drivers/base/core.c')
-rw-r--r-- | drivers/base/core.c | 29 |
1 files changed, 29 insertions, 0 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c index f191afe62b4..ad0f4a2f25c 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -407,6 +407,35 @@ void device_remove_bin_file(struct device *dev, struct bin_attribute *attr) } EXPORT_SYMBOL_GPL(device_remove_bin_file); +/** + * device_schedule_callback - helper to schedule a callback for a device + * @dev: device. + * @func: callback function to invoke later. + * + * Attribute methods must not unregister themselves or their parent device + * (which would amount to the same thing). Attempts to do so will deadlock, + * since unregistration is mutually exclusive with driver callbacks. + * + * Instead methods can call this routine, which will attempt to allocate + * and schedule a workqueue request to call back @func with @dev as its + * argument in the workqueue's process context. @dev will be pinned until + * @func returns. + * + * Returns 0 if the request was submitted, -ENOMEM if storage could not + * be allocated. + * + * NOTE: This routine won't work if CONFIG_SYSFS isn't set! It uses an + * underlying sysfs routine (since it is intended for use by attribute + * methods), and if sysfs isn't available you'll get nothing but -ENOSYS. + */ +int device_schedule_callback(struct device *dev, + void (*func)(struct device *)) +{ + return sysfs_schedule_callback(&dev->kobj, + (void (*)(void *)) func, dev); +} +EXPORT_SYMBOL_GPL(device_schedule_callback); + static void klist_children_get(struct klist_node *n) { struct device *dev = container_of(n, struct device, knode_parent); |