summary refs log tree commit diff
path: root/kernel/module.c
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2010-08-05 12:59:04 -0600
committerRusty Russell <rusty@rustcorp.com.au>2010-08-05 12:59:05 +0930
commit9f85a4bbb1cf56f65b3d065a5f88204a757f2325 (patch)
tree28d674a40dcab0e0c31349736718993f1e9377d4 /kernel/module.c
parent40dd2560ec2df21036db9ec8b971f92d98fd1969 (diff)
downloadlinux-9f85a4bbb1cf56f65b3d065a5f88204a757f2325.tar.gz
module: refactor load_module part 4
Allocate references inside module_unload_init(), clean up inside
module_unload_free().

This version fixed to do allocation before __this_cpu_write, thanks to
bug reports from linux-next from Dave Young <hidave.darkstar@gmail.com>
and Stephen Rothwell <sfr@canb.auug.org.au>.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'kernel/module.c')
-rw-r--r--kernel/module.c32
1 files changed, 15 insertions, 17 deletions
diff --git a/kernel/module.c b/kernel/module.c
index d8faf35cba84..241bc41dd6be 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -524,8 +524,12 @@ static char last_unloaded_module[MODULE_NAME_LEN+1];
 EXPORT_TRACEPOINT_SYMBOL(module_get);
 
 /* Init the unload section of the module. */
-static void module_unload_init(struct module *mod)
+static int module_unload_init(struct module *mod)
 {
+	mod->refptr = alloc_percpu(struct module_ref);
+	if (!mod->refptr)
+		return -ENOMEM;
+
 	INIT_LIST_HEAD(&mod->source_list);
 	INIT_LIST_HEAD(&mod->target_list);
 
@@ -533,6 +537,8 @@ static void module_unload_init(struct module *mod)
 	__this_cpu_write(mod->refptr->incs, 1);
 	/* Backwards compatibility macros put refcount during init. */
 	mod->waiter = current;
+
+	return 0;
 }
 
 /* Does a already use b? */
@@ -612,6 +618,8 @@ static void module_unload_free(struct module *mod)
 		kfree(use);
 	}
 	mutex_unlock(&module_mutex);
+
+	free_percpu(mod->refptr);
 }
 
 #ifdef CONFIG_MODULE_FORCE_UNLOAD
@@ -885,8 +893,9 @@ int ref_module(struct module *a, struct module *b)
 }
 EXPORT_SYMBOL_GPL(ref_module);
 
-static inline void module_unload_init(struct module *mod)
+static inline int module_unload_init(struct module *mod)
 {
+	return 0;
 }
 #endif /* CONFIG_MODULE_UNLOAD */
 
@@ -1559,10 +1568,7 @@ static void free_module(struct module *mod)
 	module_free(mod, mod->module_init);
 	kfree(mod->args);
 	percpu_modfree(mod);
-#if defined(CONFIG_MODULE_UNLOAD)
-	if (mod->refptr)
-		free_percpu(mod->refptr);
-#endif
+
 	/* Free lock-classes: */
 	lockdep_free_key_range(mod->module_core, mod->core_size);
 
@@ -2442,15 +2448,10 @@ static noinline struct module *load_module(void __user *umod,
 		goto free_percpu;
 	}
 
-#if defined(CONFIG_MODULE_UNLOAD)
-	mod->refptr = alloc_percpu(struct module_ref);
-	if (!mod->refptr) {
-		err = -ENOMEM;
-		goto free_init;
-	}
-#endif
 	/* Now we've moved module, initialize linked lists, etc. */
-	module_unload_init(mod);
+	err = module_unload_init(mod);
+	if (err)
+		goto free_init;
 
 	/* Set up license info based on the info section */
 	set_license(mod, get_modinfo(sechdrs, infoindex, "license"));
@@ -2619,10 +2620,7 @@ static noinline struct module *load_module(void __user *umod,
  cleanup:
 	free_modinfo(mod);
 	module_unload_free(mod);
-#if defined(CONFIG_MODULE_UNLOAD)
-	free_percpu(mod->refptr);
  free_init:
-#endif
 	module_free(mod, mod->module_init);
 	module_free(mod, mod->module_core);
 	/* mod will be freed with core. Don't access it beyond this line! */