diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-03-26 14:17:04 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-03-26 14:17:04 -0400 |
commit | 0c93ea4064a209cdc36de8a9a3003d43d08f46f7 (patch) | |
tree | ff19952407c523a1349ef56c05993416dd28437e /fs/sysfs/file.c | |
parent | bc2fd381d8f9dbeb181f82286cdca1567e3d0def (diff) | |
parent | e6e66b02e11563abdb7f69dcb7a2efbd8d577e77 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6: (61 commits)
Dynamic debug: fix pr_fmt() build error
Dynamic debug: allow simple quoting of words
dynamic debug: update docs
dynamic debug: combine dprintk and dynamic printk
sysfs: fix some bin_vm_ops errors
kobject: don't block for each kobject_uevent
sysfs: only allow one scheduled removal callback per kobj
Driver core: Fix device_move() vs. dpm list ordering, v2
Driver core: some cleanup on drivers/base/sys.c
Driver core: implement uevent suppress in kobject
vcs: hook sysfs devices into object lifetime instead of "binding"
driver core: fix passing platform_data
driver core: move platform_data into platform_device
sysfs: don't block indefinitely for unmapped files.
driver core: move knode_bus into private structure
driver core: move knode_driver into private structure
driver core: move klist_children into private structure
driver core: create a private portion of struct device
driver core: remove polling for driver_probe_done(v5)
sysfs: reference sysfs_dirent from sysfs inodes
...
Fixed conflicts in drivers/sh/maple/maple.c manually
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 | } |