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 0dd65281cc65..20da3ad1696b 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -614,39 +614,6 @@ void device_remove_bin_file(struct device *dev,
614} 614}
615EXPORT_SYMBOL_GPL(device_remove_bin_file); 615EXPORT_SYMBOL_GPL(device_remove_bin_file);
616 616
617/**
618 * device_schedule_callback_owner - helper to schedule a callback for a device
619 * @dev: device.
620 * @func: callback function to invoke later.
621 * @owner: module owning the callback routine
622 *
623 * Attribute methods must not unregister themselves or their parent device
624 * (which would amount to the same thing). Attempts to do so will deadlock,
625 * since unregistration is mutually exclusive with driver callbacks.
626 *
627 * Instead methods can call this routine, which will attempt to allocate
628 * and schedule a workqueue request to call back @func with @dev as its
629 * argument in the workqueue's process context. @dev will be pinned until
630 * @func returns.
631 *
632 * This routine is usually called via the inline device_schedule_callback(),
633 * which automatically sets @owner to THIS_MODULE.
634 *
635 * Returns 0 if the request was submitted, -ENOMEM if storage could not
636 * be allocated, -ENODEV if a reference to @owner isn't available.
637 *
638 * NOTE: This routine won't work if CONFIG_SYSFS isn't set! It uses an
639 * underlying sysfs routine (since it is intended for use by attribute
640 * methods), and if sysfs isn't available you'll get nothing but -ENOSYS.
641 */
642int device_schedule_callback_owner(struct device *dev,
643 void (*func)(struct device *), struct module *owner)
644{
645 return sysfs_schedule_callback(&dev->kobj,
646 (void (*)(void *)) func, dev, owner);
647}
648EXPORT_SYMBOL_GPL(device_schedule_callback_owner);
649
650static void klist_children_get(struct klist_node *n) 617static void klist_children_get(struct klist_node *n)
651{ 618{
652 struct device_private *p = to_device_private_parent(n); 619 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 233bbbeb768d..d1d1c055b48e 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);
@@ -932,10 +926,7 @@ extern int device_online(struct device *dev);
932extern struct device *__root_device_register(const char *name, 926extern struct device *__root_device_register(const char *name,
933 struct module *owner); 927 struct module *owner);
934 928
935/* 929/* This is a macro to avoid include problems with THIS_MODULE */
936 * This is a macro to avoid include problems with THIS_MODULE,
937 * just as per what is done for device_schedule_callback() above.
938 */
939#define root_device_register(name) \ 930#define root_device_register(name) \
940 __root_device_register(name, THIS_MODULE) 931 __root_device_register(name, THIS_MODULE)
941 932
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index 084354b0e814..5ffaa3443712 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -179,9 +179,6 @@ struct sysfs_ops {
179 179
180#ifdef CONFIG_SYSFS 180#ifdef CONFIG_SYSFS
181 181
182int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *),
183 void *data, struct module *owner);
184
185int __must_check sysfs_create_dir_ns(struct kobject *kobj, const void *ns); 182int __must_check sysfs_create_dir_ns(struct kobject *kobj, const void *ns);
186void sysfs_remove_dir(struct kobject *kobj); 183void sysfs_remove_dir(struct kobject *kobj);
187int __must_check sysfs_rename_dir_ns(struct kobject *kobj, const char *new_name, 184int __must_check sysfs_rename_dir_ns(struct kobject *kobj, const char *new_name,
@@ -255,12 +252,6 @@ static inline void sysfs_enable_ns(struct kernfs_node *kn)
255 252
256#else /* CONFIG_SYSFS */ 253#else /* CONFIG_SYSFS */
257 254
258static inline int sysfs_schedule_callback(struct kobject *kobj,
259 void (*func)(void *), void *data, struct module *owner)
260{
261 return -ENOSYS;
262}
263
264static inline int sysfs_create_dir_ns(struct kobject *kobj, const void *ns) 255static inline int sysfs_create_dir_ns(struct kobject *kobj, const void *ns)
265{ 256{
266 return 0; 257 return 0;