summaryrefslogtreecommitdiff
path: root/fs/sysfs/file.c
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2007-04-26 00:12:04 -0700
committerGreg Kroah-Hartman <gregkh@suse.de>2007-04-27 10:57:32 -0700
commit523ded71de0c5e66973335bf99a80edfda9f401b (patch)
tree20f47e8ed91018977d9fb7f4169a6ef8db407b82 /fs/sysfs/file.c
parentfa1a8c23eb7d3ded8a3c6d0e653339a2bc7fca9e (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/sysfs/file.c')
-rw-r--r--fs/sysfs/file.c14
1 files changed, 11 insertions, 3 deletions
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index fc4633378dc..db0413a411d 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;