diff options
Diffstat (limited to 'fs/sysfs/file.c')
| -rw-r--r-- | fs/sysfs/file.c | 64 |
1 files changed, 59 insertions, 5 deletions
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 8d4d839a9d88..fc4633378dc0 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c | |||
| @@ -168,12 +168,12 @@ sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos) | |||
| 168 | ssize_t retval = 0; | 168 | ssize_t retval = 0; |
| 169 | 169 | ||
| 170 | down(&buffer->sem); | 170 | down(&buffer->sem); |
| 171 | if (buffer->orphaned) { | ||
| 172 | retval = -ENODEV; | ||
| 173 | goto out; | ||
| 174 | } | ||
| 175 | if (buffer->needs_read_fill) { | 171 | if (buffer->needs_read_fill) { |
| 176 | if ((retval = fill_read_buffer(file->f_path.dentry,buffer))) | 172 | if (buffer->orphaned) |
| 173 | retval = -ENODEV; | ||
| 174 | else | ||
| 175 | retval = fill_read_buffer(file->f_path.dentry,buffer); | ||
| 176 | if (retval) | ||
| 177 | goto out; | 177 | goto out; |
| 178 | } | 178 | } |
| 179 | pr_debug("%s: count = %zd, ppos = %lld, buf = %s\n", | 179 | pr_debug("%s: count = %zd, ppos = %lld, buf = %s\n", |
| @@ -629,6 +629,60 @@ void sysfs_remove_file_from_group(struct kobject *kobj, | |||
| 629 | } | 629 | } |
| 630 | EXPORT_SYMBOL_GPL(sysfs_remove_file_from_group); | 630 | EXPORT_SYMBOL_GPL(sysfs_remove_file_from_group); |
| 631 | 631 | ||
| 632 | struct sysfs_schedule_callback_struct { | ||
| 633 | struct kobject *kobj; | ||
| 634 | void (*func)(void *); | ||
| 635 | void *data; | ||
| 636 | struct work_struct work; | ||
| 637 | }; | ||
| 638 | |||
| 639 | static void sysfs_schedule_callback_work(struct work_struct *work) | ||
| 640 | { | ||
| 641 | struct sysfs_schedule_callback_struct *ss = container_of(work, | ||
| 642 | struct sysfs_schedule_callback_struct, work); | ||
| 643 | |||
| 644 | (ss->func)(ss->data); | ||
| 645 | kobject_put(ss->kobj); | ||
| 646 | kfree(ss); | ||
| 647 | } | ||
| 648 | |||
| 649 | /** | ||
| 650 | * sysfs_schedule_callback - helper to schedule a callback for a kobject | ||
| 651 | * @kobj: object we're acting for. | ||
| 652 | * @func: callback function to invoke later. | ||
| 653 | * @data: argument to pass to @func. | ||
| 654 | * | ||
| 655 | * sysfs attribute methods must not unregister themselves or their parent | ||
| 656 | * kobject (which would amount to the same thing). Attempts to do so will | ||
| 657 | * deadlock, since unregistration is mutually exclusive with driver | ||
| 658 | * callbacks. | ||
| 659 | * | ||
| 660 | * Instead methods can call this routine, which will attempt to allocate | ||
| 661 | * and schedule a workqueue request to call back @func with @data as its | ||
| 662 | * argument in the workqueue's process context. @kobj will be pinned | ||
| 663 | * until @func returns. | ||
| 664 | * | ||
| 665 | * Returns 0 if the request was submitted, -ENOMEM if storage could not | ||
| 666 | * be allocated. | ||
| 667 | */ | ||
| 668 | int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *), | ||
| 669 | void *data) | ||
| 670 | { | ||
| 671 | struct sysfs_schedule_callback_struct *ss; | ||
| 672 | |||
| 673 | ss = kmalloc(sizeof(*ss), GFP_KERNEL); | ||
| 674 | if (!ss) | ||
| 675 | return -ENOMEM; | ||
| 676 | kobject_get(kobj); | ||
| 677 | ss->kobj = kobj; | ||
| 678 | ss->func = func; | ||
| 679 | ss->data = data; | ||
| 680 | INIT_WORK(&ss->work, sysfs_schedule_callback_work); | ||
| 681 | schedule_work(&ss->work); | ||
| 682 | return 0; | ||
| 683 | } | ||
| 684 | EXPORT_SYMBOL_GPL(sysfs_schedule_callback); | ||
| 685 | |||
| 632 | 686 | ||
| 633 | EXPORT_SYMBOL_GPL(sysfs_create_file); | 687 | EXPORT_SYMBOL_GPL(sysfs_create_file); |
| 634 | EXPORT_SYMBOL_GPL(sysfs_remove_file); | 688 | EXPORT_SYMBOL_GPL(sysfs_remove_file); |
