aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2007-04-26 03:12:04 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-04-27 13:57:32 -0400
commit523ded71de0c5e66973335bf99a80edfda9f401b (patch)
tree20f47e8ed91018977d9fb7f4169a6ef8db407b82
parentfa1a8c23eb7d3ded8a3c6d0e653339a2bc7fca9e (diff)
device_schedule_callback() needs a module reference
This patch (as896b) fixes an oversight in the design of device_schedule_callback(). It is necessary to acquire a reference to the module owning the callback routine, to prevent the module from being unloaded before the callback can run. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Cc: Satyam Sharma <satyam.sharma@gmail.com> Cc: Neil Brown <neilb@suse.de> Cc: Cornelia Huck <cornelia.huck@de.ibm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/base/core.c16
-rw-r--r--fs/sysfs/file.c14
-rw-r--r--include/linux/device.h8
-rw-r--r--include/linux/sysfs.h4
4 files changed, 29 insertions, 13 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c
index f69305c7269d..8aa090da1cd7 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -480,9 +480,10 @@ void device_remove_bin_file(struct device *dev, struct bin_attribute *attr)
480EXPORT_SYMBOL_GPL(device_remove_bin_file); 480EXPORT_SYMBOL_GPL(device_remove_bin_file);
481 481
482/** 482/**
483 * device_schedule_callback - helper to schedule a callback for a device 483 * device_schedule_callback_owner - helper to schedule a callback for a device
484 * @dev: device. 484 * @dev: device.
485 * @func: callback function to invoke later. 485 * @func: callback function to invoke later.
486 * @owner: module owning the callback routine
486 * 487 *
487 * Attribute methods must not unregister themselves or their parent device 488 * Attribute methods must not unregister themselves or their parent device
488 * (which would amount to the same thing). Attempts to do so will deadlock, 489 * (which would amount to the same thing). Attempts to do so will deadlock,
@@ -493,20 +494,23 @@ EXPORT_SYMBOL_GPL(device_remove_bin_file);
493 * argument in the workqueue's process context. @dev will be pinned until 494 * argument in the workqueue's process context. @dev will be pinned until
494 * @func returns. 495 * @func returns.
495 * 496 *
497 * This routine is usually called via the inline device_schedule_callback(),
498 * which automatically sets @owner to THIS_MODULE.
499 *
496 * Returns 0 if the request was submitted, -ENOMEM if storage could not 500 * Returns 0 if the request was submitted, -ENOMEM if storage could not
497 * be allocated. 501 * be allocated, -ENODEV if a reference to @owner isn't available.
498 * 502 *
499 * NOTE: This routine won't work if CONFIG_SYSFS isn't set! It uses an 503 * NOTE: This routine won't work if CONFIG_SYSFS isn't set! It uses an
500 * underlying sysfs routine (since it is intended for use by attribute 504 * underlying sysfs routine (since it is intended for use by attribute
501 * methods), and if sysfs isn't available you'll get nothing but -ENOSYS. 505 * methods), and if sysfs isn't available you'll get nothing but -ENOSYS.
502 */ 506 */
503int device_schedule_callback(struct device *dev, 507int device_schedule_callback_owner(struct device *dev,
504 void (*func)(struct device *)) 508 void (*func)(struct device *), struct module *owner)
505{ 509{
506 return sysfs_schedule_callback(&dev->kobj, 510 return sysfs_schedule_callback(&dev->kobj,
507 (void (*)(void *)) func, dev); 511 (void (*)(void *)) func, dev, owner);
508} 512}
509EXPORT_SYMBOL_GPL(device_schedule_callback); 513EXPORT_SYMBOL_GPL(device_schedule_callback_owner);
510 514
511static void klist_children_get(struct klist_node *n) 515static void klist_children_get(struct klist_node *n)
512{ 516{
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index fc4633378dc0..db0413a411d6 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -633,6 +633,7 @@ struct sysfs_schedule_callback_struct {
633 struct kobject *kobj; 633 struct kobject *kobj;
634 void (*func)(void *); 634 void (*func)(void *);
635 void *data; 635 void *data;
636 struct module *owner;
636 struct work_struct work; 637 struct work_struct work;
637}; 638};
638 639
@@ -643,6 +644,7 @@ static void sysfs_schedule_callback_work(struct work_struct *work)
643 644
644 (ss->func)(ss->data); 645 (ss->func)(ss->data);
645 kobject_put(ss->kobj); 646 kobject_put(ss->kobj);
647 module_put(ss->owner);
646 kfree(ss); 648 kfree(ss);
647} 649}
648 650
@@ -651,6 +653,7 @@ static void sysfs_schedule_callback_work(struct work_struct *work)
651 * @kobj: object we're acting for. 653 * @kobj: object we're acting for.
652 * @func: callback function to invoke later. 654 * @func: callback function to invoke later.
653 * @data: argument to pass to @func. 655 * @data: argument to pass to @func.
656 * @owner: module owning the callback code
654 * 657 *
655 * sysfs attribute methods must not unregister themselves or their parent 658 * sysfs attribute methods must not unregister themselves or their parent
656 * kobject (which would amount to the same thing). Attempts to do so will 659 * kobject (which would amount to the same thing). Attempts to do so will
@@ -663,20 +666,25 @@ static void sysfs_schedule_callback_work(struct work_struct *work)
663 * until @func returns. 666 * until @func returns.
664 * 667 *
665 * Returns 0 if the request was submitted, -ENOMEM if storage could not 668 * Returns 0 if the request was submitted, -ENOMEM if storage could not
666 * be allocated. 669 * be allocated, -ENODEV if a reference to @owner isn't available.
667 */ 670 */
668int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *), 671int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *),
669 void *data) 672 void *data, struct module *owner)
670{ 673{
671 struct sysfs_schedule_callback_struct *ss; 674 struct sysfs_schedule_callback_struct *ss;
672 675
676 if (!try_module_get(owner))
677 return -ENODEV;
673 ss = kmalloc(sizeof(*ss), GFP_KERNEL); 678 ss = kmalloc(sizeof(*ss), GFP_KERNEL);
674 if (!ss) 679 if (!ss) {
680 module_put(owner);
675 return -ENOMEM; 681 return -ENOMEM;
682 }
676 kobject_get(kobj); 683 kobject_get(kobj);
677 ss->kobj = kobj; 684 ss->kobj = kobj;
678 ss->func = func; 685 ss->func = func;
679 ss->data = data; 686 ss->data = data;
687 ss->owner = owner;
680 INIT_WORK(&ss->work, sysfs_schedule_callback_work); 688 INIT_WORK(&ss->work, sysfs_schedule_callback_work);
681 schedule_work(&ss->work); 689 schedule_work(&ss->work);
682 return 0; 690 return 0;
diff --git a/include/linux/device.h b/include/linux/device.h
index af603a137690..8511d14071b3 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -367,8 +367,12 @@ extern int __must_check device_create_bin_file(struct device *dev,
367 struct bin_attribute *attr); 367 struct bin_attribute *attr);
368extern void device_remove_bin_file(struct device *dev, 368extern void device_remove_bin_file(struct device *dev,
369 struct bin_attribute *attr); 369 struct bin_attribute *attr);
370extern int device_schedule_callback(struct device *dev, 370extern int device_schedule_callback_owner(struct device *dev,
371 void (*func)(struct device *)); 371 void (*func)(struct device *), struct module *owner);
372
373/* This is a macro to avoid include problems with THIS_MODULE */
374#define device_schedule_callback(dev, func) \
375 device_schedule_callback_owner(dev, func, THIS_MODULE)
372 376
373/* device resource management */ 377/* device resource management */
374typedef void (*dr_release_t)(struct device *dev, void *res); 378typedef void (*dr_release_t)(struct device *dev, void *res);
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index fea9a6b3fb7b..7d5d1ec95c2e 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -80,7 +80,7 @@ struct sysfs_ops {
80#ifdef CONFIG_SYSFS 80#ifdef CONFIG_SYSFS
81 81
82extern int sysfs_schedule_callback(struct kobject *kobj, 82extern int sysfs_schedule_callback(struct kobject *kobj,
83 void (*func)(void *), void *data); 83 void (*func)(void *), void *data, struct module *owner);
84 84
85extern int __must_check 85extern int __must_check
86sysfs_create_dir(struct kobject *, struct dentry *); 86sysfs_create_dir(struct kobject *, struct dentry *);
@@ -137,7 +137,7 @@ extern int __must_check sysfs_init(void);
137#else /* CONFIG_SYSFS */ 137#else /* CONFIG_SYSFS */
138 138
139static inline int sysfs_schedule_callback(struct kobject *kobj, 139static inline int sysfs_schedule_callback(struct kobject *kobj,
140 void (*func)(void *), void *data) 140 void (*func)(void *), void *data, struct module *owner)
141{ 141{
142 return -ENOSYS; 142 return -ENOSYS;
143} 143}