diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2007-04-26 03:12:04 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-04-27 13:57:32 -0400 |
commit | 523ded71de0c5e66973335bf99a80edfda9f401b (patch) | |
tree | 20f47e8ed91018977d9fb7f4169a6ef8db407b82 /fs | |
parent | fa1a8c23eb7d3ded8a3c6d0e653339a2bc7fca9e (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>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/sysfs/file.c | 14 |
1 files changed, 11 insertions, 3 deletions
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 | */ |
668 | int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *), | 671 | int 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; |