aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-03-25 23:54:57 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-03-25 23:54:57 -0400
commit72099304eeb316c4b00df3ae83efe4375729bd78 (patch)
tree3d4a7dbe61ad9bbaeb767b1fb43e190901bcb70b
parentb7ce40cff0b9f6597f8318fd761accd92727f61f (diff)
Revert "sysfs, driver-core: remove unused {sysfs|device}_schedule_callback_owner()"
This reverts commit d1ba277e79889085a2faec3b68b91ce89c63f888. As reported by Stephen, this patch breaks linux-next as a ppc patch suddenly (after 2 years) started using this old api call. So revert it for now, it will go away in 3.15-rc2 when we can change the PPC call to the new api. Reported-by: Stephen Rothwell <sfr@canb.auug.org.au> Cc: Tejun Heo <tj@kernel.org> Cc: Stewart Smith <stewart@linux.vnet.ibm.com> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-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, 144 insertions, 1 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 20da3ad1696b..0dd65281cc65 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -614,6 +614,39 @@ 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
617static void klist_children_get(struct klist_node *n) 650static void klist_children_get(struct klist_node *n)
618{ 651{
619 struct device_private *p = to_device_private_parent(n); 652 struct device_private *p = to_device_private_parent(n);
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index 28cc1acd5439..1b8b91b67fdb 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -453,3 +453,95 @@ 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 fb1ba13f7665..1ff3f1697513 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -566,6 +566,12 @@ 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)
569 575
570/* device resource management */ 576/* device resource management */
571typedef void (*dr_release_t)(struct device *dev, void *res); 577typedef void (*dr_release_t)(struct device *dev, void *res);
@@ -925,7 +931,10 @@ extern int device_online(struct device *dev);
925extern struct device *__root_device_register(const char *name, 931extern struct device *__root_device_register(const char *name,
926 struct module *owner); 932 struct module *owner);
927 933
928/* This is a macro to avoid include problems with THIS_MODULE */ 934/*
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 */
929#define root_device_register(name) \ 938#define root_device_register(name) \
930 __root_device_register(name, THIS_MODULE) 939 __root_device_register(name, THIS_MODULE)
931 940
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index fdaa0c6fc7a2..e0bf210ddffd 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -178,6 +178,9 @@ 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
181int __must_check sysfs_create_dir_ns(struct kobject *kobj, const void *ns); 184int __must_check sysfs_create_dir_ns(struct kobject *kobj, const void *ns);
182void sysfs_remove_dir(struct kobject *kobj); 185void sysfs_remove_dir(struct kobject *kobj);
183int __must_check sysfs_rename_dir_ns(struct kobject *kobj, const char *new_name, 186int __must_check sysfs_rename_dir_ns(struct kobject *kobj, const char *new_name,
@@ -251,6 +254,12 @@ static inline void sysfs_enable_ns(struct kernfs_node *kn)
251 254
252#else /* CONFIG_SYSFS */ 255#else /* CONFIG_SYSFS */
253 256
257static inline int sysfs_schedule_callback(struct kobject *kobj,
258 void (*func)(void *), void *data, struct module *owner)
259{
260 return -ENOSYS;
261}
262
254static inline int sysfs_create_dir_ns(struct kobject *kobj, const void *ns) 263static inline int sysfs_create_dir_ns(struct kobject *kobj, const void *ns)
255{ 264{
256 return 0; 265 return 0;