diff options
Diffstat (limited to 'fs/sysfs/file.c')
| -rw-r--r-- | fs/sysfs/file.c | 26 |
1 files changed, 23 insertions, 3 deletions
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 1f4a3f877262..289c43a47263 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c | |||
| @@ -659,13 +659,16 @@ void sysfs_remove_file_from_group(struct kobject *kobj, | |||
| 659 | EXPORT_SYMBOL_GPL(sysfs_remove_file_from_group); | 659 | EXPORT_SYMBOL_GPL(sysfs_remove_file_from_group); |
| 660 | 660 | ||
| 661 | struct sysfs_schedule_callback_struct { | 661 | struct sysfs_schedule_callback_struct { |
| 662 | struct kobject *kobj; | 662 | struct list_head workq_list; |
| 663 | struct kobject *kobj; | ||
| 663 | void (*func)(void *); | 664 | void (*func)(void *); |
| 664 | void *data; | 665 | void *data; |
| 665 | struct module *owner; | 666 | struct module *owner; |
| 666 | struct work_struct work; | 667 | struct work_struct work; |
| 667 | }; | 668 | }; |
| 668 | 669 | ||
| 670 | static DEFINE_MUTEX(sysfs_workq_mutex); | ||
| 671 | static LIST_HEAD(sysfs_workq); | ||
| 669 | static void sysfs_schedule_callback_work(struct work_struct *work) | 672 | static void sysfs_schedule_callback_work(struct work_struct *work) |
| 670 | { | 673 | { |
| 671 | struct sysfs_schedule_callback_struct *ss = container_of(work, | 674 | struct sysfs_schedule_callback_struct *ss = container_of(work, |
| @@ -674,6 +677,9 @@ static void sysfs_schedule_callback_work(struct work_struct *work) | |||
| 674 | (ss->func)(ss->data); | 677 | (ss->func)(ss->data); |
| 675 | kobject_put(ss->kobj); | 678 | kobject_put(ss->kobj); |
| 676 | module_put(ss->owner); | 679 | module_put(ss->owner); |
| 680 | mutex_lock(&sysfs_workq_mutex); | ||
| 681 | list_del(&ss->workq_list); | ||
| 682 | mutex_unlock(&sysfs_workq_mutex); | ||
| 677 | kfree(ss); | 683 | kfree(ss); |
| 678 | } | 684 | } |
| 679 | 685 | ||
| @@ -695,15 +701,25 @@ static void sysfs_schedule_callback_work(struct work_struct *work) | |||
| 695 | * until @func returns. | 701 | * until @func returns. |
| 696 | * | 702 | * |
| 697 | * Returns 0 if the request was submitted, -ENOMEM if storage could not | 703 | * Returns 0 if the request was submitted, -ENOMEM if storage could not |
| 698 | * be allocated, -ENODEV if a reference to @owner isn't available. | 704 | * be allocated, -ENODEV if a reference to @owner isn't available, |
| 705 | * -EAGAIN if a callback has already been scheduled for @kobj. | ||
| 699 | */ | 706 | */ |
| 700 | int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *), | 707 | int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *), |
| 701 | void *data, struct module *owner) | 708 | void *data, struct module *owner) |
| 702 | { | 709 | { |
| 703 | struct sysfs_schedule_callback_struct *ss; | 710 | struct sysfs_schedule_callback_struct *ss, *tmp; |
| 704 | 711 | ||
| 705 | if (!try_module_get(owner)) | 712 | if (!try_module_get(owner)) |
| 706 | return -ENODEV; | 713 | return -ENODEV; |
| 714 | |||
| 715 | mutex_lock(&sysfs_workq_mutex); | ||
| 716 | list_for_each_entry_safe(ss, tmp, &sysfs_workq, workq_list) | ||
| 717 | if (ss->kobj == kobj) { | ||
| 718 | mutex_unlock(&sysfs_workq_mutex); | ||
| 719 | return -EAGAIN; | ||
| 720 | } | ||
| 721 | mutex_unlock(&sysfs_workq_mutex); | ||
| 722 | |||
| 707 | ss = kmalloc(sizeof(*ss), GFP_KERNEL); | 723 | ss = kmalloc(sizeof(*ss), GFP_KERNEL); |
| 708 | if (!ss) { | 724 | if (!ss) { |
| 709 | module_put(owner); | 725 | module_put(owner); |
| @@ -715,6 +731,10 @@ int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *), | |||
| 715 | ss->data = data; | 731 | ss->data = data; |
| 716 | ss->owner = owner; | 732 | ss->owner = owner; |
| 717 | INIT_WORK(&ss->work, sysfs_schedule_callback_work); | 733 | INIT_WORK(&ss->work, sysfs_schedule_callback_work); |
| 734 | INIT_LIST_HEAD(&ss->workq_list); | ||
| 735 | mutex_lock(&sysfs_workq_mutex); | ||
| 736 | list_add_tail(&ss->workq_list, &sysfs_workq); | ||
| 737 | mutex_unlock(&sysfs_workq_mutex); | ||
| 718 | schedule_work(&ss->work); | 738 | schedule_work(&ss->work); |
| 719 | return 0; | 739 | return 0; |
| 720 | } | 740 | } |
