diff options
Diffstat (limited to 'fs/sysfs/file.c')
-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 { struct kobject *kobj; void (*func)(void *); void *data; + struct module *owner; struct work_struct work; }; @@ -643,6 +644,7 @@ static void sysfs_schedule_callback_work(struct work_struct *work) (ss->func)(ss->data); kobject_put(ss->kobj); + module_put(ss->owner); kfree(ss); } @@ -651,6 +653,7 @@ static void sysfs_schedule_callback_work(struct work_struct *work) * @kobj: object we're acting for. * @func: callback function to invoke later. * @data: argument to pass to @func. + * @owner: module owning the callback code * * sysfs attribute methods must not unregister themselves or their parent * 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) * until @func returns. * * Returns 0 if the request was submitted, -ENOMEM if storage could not - * be allocated. + * be allocated, -ENODEV if a reference to @owner isn't available. */ int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *), - void *data) + void *data, struct module *owner) { struct sysfs_schedule_callback_struct *ss; + if (!try_module_get(owner)) + return -ENODEV; ss = kmalloc(sizeof(*ss), GFP_KERNEL); - if (!ss) + if (!ss) { + module_put(owner); return -ENOMEM; + } kobject_get(kobj); ss->kobj = kobj; ss->func = func; ss->data = data; + ss->owner = owner; INIT_WORK(&ss->work, sysfs_schedule_callback_work); schedule_work(&ss->work); return 0; |