aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/base/core.c33
-rw-r--r--fs/sysfs/file.c92
-rw-r--r--include/linux/device.h11
-rw-r--r--include/linux/sysfs.h9
4 files changed, 1 insertions, 144 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 9db57afcf81f..4195364f9fdd 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -615,39 +615,6 @@ void device_remove_bin_file(struct device *dev,
615} 615}
616EXPORT_SYMBOL_GPL(device_remove_bin_file); 616EXPORT_SYMBOL_GPL(device_remove_bin_file);
617 617
618/**
619 * device_schedule_callback_owner - helper to schedule a callback for a device
620 * @dev: device.
621 * @func: callback function to invoke later.
622 * @owner: module owning the callback routine
623 *
624 * Attribute methods must not unregister themselves or their parent device
625 * (which would amount to the same thing). Attempts to do so will deadlock,
626 * since unregistration is mutually exclusive with driver callbacks.
627 *
628 * Instead methods can call this routine, which will attempt to allocate
629 * and schedule a workqueue request to call back @func with @dev as its
630 * argument in the workqueue's process context. @dev will be pinned until
631 * @func returns.
632 *
633 * This routine is usually called via the inline device_schedule_callback(),
634 * which automatically sets @owner to THIS_MODULE.
635 *
636 * Returns 0 if the request was submitted, -ENOMEM if storage could not
637 * be allocated, -ENODEV if a reference to @owner isn't available.
638 *
639 * NOTE: This routine won't work if CONFIG_SYSFS isn't set! It uses an
640 * underlying sysfs routine (since it is intended for use by attribute
641 * methods), and if sysfs isn't available you'll get nothing but -ENOSYS.
642 */
643int device_schedule_callback_owner(struct device *dev,
644 void (*func)(struct device *), struct module *owner)
645{
646 return sysfs_schedule_callback(&dev->kobj,
647 (void (*)(void *)) func, dev, owner);
648}
649EXPORT_SYMBOL_GPL(device_schedule_callback_owner);
650
651static void klist_children_get(struct klist_node *n) 618static void klist_children_get(struct klist_node *n)
652{ 619{
653 struct device_private *p = to_device_private_parent(n); 620 struct device_private *p = to_device_private_parent(n);
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index 1b8b91b67fdb..28cc1acd5439 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -453,95 +453,3 @@ void sysfs_remove_bin_file(struct kobject *kobj,
453 kernfs_remove_by_name(kobj->sd, attr->attr.name); 453 kernfs_remove_by_name(kobj->sd, attr->attr.name);
454} 454}
455EXPORT_SYMBOL_GPL(sysfs_remove_bin_file); 455EXPORT_SYMBOL_GPL(sysfs_remove_bin_file);
456
457struct sysfs_schedule_callback_struct {
458 struct list_head workq_list;
459 struct kobject *kobj;
460 void (*func)(void *);
461 void *data;
462 struct module *owner;
463 struct work_struct work;
464};
465
466static struct workqueue_struct *sysfs_workqueue;
467static DEFINE_MUTEX(sysfs_workq_mutex);
468static LIST_HEAD(sysfs_workq);
469static void sysfs_schedule_callback_work(struct work_struct *work)
470{
471 struct sysfs_schedule_callback_struct *ss = container_of(work,
472 struct sysfs_schedule_callback_struct, work);
473
474 (ss->func)(ss->data);
475 kobject_put(ss->kobj);
476 module_put(ss->owner);
477 mutex_lock(&sysfs_workq_mutex);
478 list_del(&ss->workq_list);
479 mutex_unlock(&sysfs_workq_mutex);
480 kfree(ss);
481}
482
483/**
484 * sysfs_schedule_callback - helper to schedule a callback for a kobject
485 * @kobj: object we're acting for.
486 * @func: callback function to invoke later.
487 * @data: argument to pass to @func.
488 * @owner: module owning the callback code
489 *
490 * sysfs attribute methods must not unregister themselves or their parent
491 * kobject (which would amount to the same thing). Attempts to do so will
492 * deadlock, since unregistration is mutually exclusive with driver
493 * callbacks.
494 *
495 * Instead methods can call this routine, which will attempt to allocate
496 * and schedule a workqueue request to call back @func with @data as its
497 * argument in the workqueue's process context. @kobj will be pinned
498 * until @func returns.
499 *
500 * Returns 0 if the request was submitted, -ENOMEM if storage could not
501 * be allocated, -ENODEV if a reference to @owner isn't available,
502 * -EAGAIN if a callback has already been scheduled for @kobj.
503 */
504int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *),
505 void *data, struct module *owner)
506{
507 struct sysfs_schedule_callback_struct *ss, *tmp;
508
509 if (!try_module_get(owner))
510 return -ENODEV;
511
512 mutex_lock(&sysfs_workq_mutex);
513 list_for_each_entry_safe(ss, tmp, &sysfs_workq, workq_list)
514 if (ss->kobj == kobj) {
515 module_put(owner);
516 mutex_unlock(&sysfs_workq_mutex);
517 return -EAGAIN;
518 }
519 mutex_unlock(&sysfs_workq_mutex);
520
521 if (sysfs_workqueue == NULL) {
522 sysfs_workqueue = create_singlethread_workqueue("sysfsd");
523 if (sysfs_workqueue == NULL) {
524 module_put(owner);
525 return -ENOMEM;
526 }
527 }
528
529 ss = kmalloc(sizeof(*ss), GFP_KERNEL);
530 if (!ss) {
531 module_put(owner);
532 return -ENOMEM;
533 }
534 kobject_get(kobj);
535 ss->kobj = kobj;
536 ss->func = func;
537 ss->data = data;
538 ss->owner = owner;
539 INIT_WORK(&ss->work, sysfs_schedule_callback_work);
540 INIT_LIST_HEAD(&ss->workq_list);
541 mutex_lock(&sysfs_workq_mutex);
542 list_add_tail(&ss->workq_list, &sysfs_workq);
543 mutex_unlock(&sysfs_workq_mutex);
544 queue_work(sysfs_workqueue, &ss->work);
545 return 0;
546}
547EXPORT_SYMBOL_GPL(sysfs_schedule_callback);
diff --git a/include/linux/device.h b/include/linux/device.h
index 1ff3f1697513..fb1ba13f7665 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -566,12 +566,6 @@ extern int __must_check device_create_bin_file(struct device *dev,
566 const struct bin_attribute *attr); 566 const struct bin_attribute *attr);
567extern void device_remove_bin_file(struct device *dev, 567extern void device_remove_bin_file(struct device *dev,
568 const struct bin_attribute *attr); 568 const struct bin_attribute *attr);
569extern int device_schedule_callback_owner(struct device *dev,
570 void (*func)(struct device *dev), struct module *owner);
571
572/* This is a macro to avoid include problems with THIS_MODULE */
573#define device_schedule_callback(dev, func) \
574 device_schedule_callback_owner(dev, func, THIS_MODULE)
575 569
576/* device resource management */ 570/* device resource management */
577typedef void (*dr_release_t)(struct device *dev, void *res); 571typedef void (*dr_release_t)(struct device *dev, void *res);
@@ -931,10 +925,7 @@ extern int device_online(struct device *dev);
931extern struct device *__root_device_register(const char *name, 925extern struct device *__root_device_register(const char *name,
932 struct module *owner); 926 struct module *owner);
933 927
934/* 928/* This is a macro to avoid include problems with THIS_MODULE */
935 * This is a macro to avoid include problems with THIS_MODULE,
936 * just as per what is done for device_schedule_callback() above.
937 */
938#define root_device_register(name) \ 929#define root_device_register(name) \
939 __root_device_register(name, THIS_MODULE) 930 __root_device_register(name, THIS_MODULE)
940 931
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index bd96c603ab6c..14df05415af9 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -178,9 +178,6 @@ struct sysfs_ops {
178 178
179#ifdef CONFIG_SYSFS 179#ifdef CONFIG_SYSFS
180 180
181int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *),
182 void *data, struct module *owner);
183
184int __must_check sysfs_create_dir_ns(struct kobject *kobj, const void *ns); 181int __must_check sysfs_create_dir_ns(struct kobject *kobj, const void *ns);
185void sysfs_remove_dir(struct kobject *kobj); 182void sysfs_remove_dir(struct kobject *kobj);
186int __must_check sysfs_rename_dir_ns(struct kobject *kobj, const char *new_name, 183int __must_check sysfs_rename_dir_ns(struct kobject *kobj, const char *new_name,
@@ -249,12 +246,6 @@ int __must_check sysfs_init(void);
249 246
250#else /* CONFIG_SYSFS */ 247#else /* CONFIG_SYSFS */
251 248
252static inline int sysfs_schedule_callback(struct kobject *kobj,
253 void (*func)(void *), void *data, struct module *owner)
254{
255 return -ENOSYS;
256}
257
258static inline int sysfs_create_dir_ns(struct kobject *kobj, const void *ns) 249static inline int sysfs_create_dir_ns(struct kobject *kobj, const void *ns)
259{ 250{
260 return 0; 251 return 0;