diff options
| -rw-r--r-- | include/linux/module.h | 4 | ||||
| -rw-r--r-- | include/linux/moduleparam.h | 10 | ||||
| -rw-r--r-- | kernel/module.c | 14 | ||||
| -rw-r--r-- | kernel/params.c | 26 |
4 files changed, 47 insertions, 7 deletions
diff --git a/include/linux/module.h b/include/linux/module.h index 145a75528cc1..08e5e75d6122 100644 --- a/include/linux/module.h +++ b/include/linux/module.h | |||
| @@ -248,6 +248,10 @@ struct module | |||
| 248 | const unsigned long *crcs; | 248 | const unsigned long *crcs; |
| 249 | unsigned int num_syms; | 249 | unsigned int num_syms; |
| 250 | 250 | ||
| 251 | /* Kernel parameters. */ | ||
| 252 | struct kernel_param *kp; | ||
| 253 | unsigned int num_kp; | ||
| 254 | |||
| 251 | /* GPL-only exported symbols. */ | 255 | /* GPL-only exported symbols. */ |
| 252 | unsigned int num_gpl_syms; | 256 | unsigned int num_gpl_syms; |
| 253 | const struct kernel_symbol *gpl_syms; | 257 | const struct kernel_symbol *gpl_syms; |
diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h index e4af3399ef48..a4f0b931846c 100644 --- a/include/linux/moduleparam.h +++ b/include/linux/moduleparam.h | |||
| @@ -138,6 +138,16 @@ extern int parse_args(const char *name, | |||
| 138 | unsigned num, | 138 | unsigned num, |
| 139 | int (*unknown)(char *param, char *val)); | 139 | int (*unknown)(char *param, char *val)); |
| 140 | 140 | ||
| 141 | /* Called by module remove. */ | ||
| 142 | #ifdef CONFIG_SYSFS | ||
| 143 | extern void destroy_params(const struct kernel_param *params, unsigned num); | ||
| 144 | #else | ||
| 145 | static inline void destroy_params(const struct kernel_param *params, | ||
| 146 | unsigned num) | ||
| 147 | { | ||
| 148 | } | ||
| 149 | #endif /* !CONFIG_SYSFS */ | ||
| 150 | |||
| 141 | /* All the helper functions */ | 151 | /* All the helper functions */ |
| 142 | /* The macros to do compile-time type checking stolen from Jakub | 152 | /* The macros to do compile-time type checking stolen from Jakub |
| 143 | Jelinek, who IIRC came up with this idea for the 2.4 module init code. */ | 153 | Jelinek, who IIRC came up with this idea for the 2.4 module init code. */ |
diff --git a/kernel/module.c b/kernel/module.c index f77ac320d0b5..b862fdb6a372 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
| @@ -1491,6 +1491,9 @@ static void free_module(struct module *mod) | |||
| 1491 | /* Module unload stuff */ | 1491 | /* Module unload stuff */ |
| 1492 | module_unload_free(mod); | 1492 | module_unload_free(mod); |
| 1493 | 1493 | ||
| 1494 | /* Free any allocated parameters. */ | ||
| 1495 | destroy_params(mod->kp, mod->num_kp); | ||
| 1496 | |||
| 1494 | /* release any pointers to mcount in this module */ | 1497 | /* release any pointers to mcount in this module */ |
| 1495 | ftrace_release(mod->module_core, mod->core_size); | 1498 | ftrace_release(mod->module_core, mod->core_size); |
| 1496 | 1499 | ||
| @@ -1898,8 +1901,7 @@ static noinline struct module *load_module(void __user *umod, | |||
| 1898 | unsigned int symindex = 0; | 1901 | unsigned int symindex = 0; |
| 1899 | unsigned int strindex = 0; | 1902 | unsigned int strindex = 0; |
| 1900 | unsigned int modindex, versindex, infoindex, pcpuindex; | 1903 | unsigned int modindex, versindex, infoindex, pcpuindex; |
| 1901 | unsigned int num_kp, num_mcount; | 1904 | unsigned int num_mcount; |
| 1902 | struct kernel_param *kp; | ||
| 1903 | struct module *mod; | 1905 | struct module *mod; |
| 1904 | long err = 0; | 1906 | long err = 0; |
| 1905 | void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */ | 1907 | void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */ |
| @@ -2144,8 +2146,8 @@ static noinline struct module *load_module(void __user *umod, | |||
| 2144 | 2146 | ||
| 2145 | /* Now we've got everything in the final locations, we can | 2147 | /* Now we've got everything in the final locations, we can |
| 2146 | * find optional sections. */ | 2148 | * find optional sections. */ |
| 2147 | kp = section_objs(hdr, sechdrs, secstrings, "__param", sizeof(*kp), | 2149 | mod->kp = section_objs(hdr, sechdrs, secstrings, "__param", |
| 2148 | &num_kp); | 2150 | sizeof(*mod->kp), &mod->num_kp); |
| 2149 | mod->syms = section_objs(hdr, sechdrs, secstrings, "__ksymtab", | 2151 | mod->syms = section_objs(hdr, sechdrs, secstrings, "__ksymtab", |
| 2150 | sizeof(*mod->syms), &mod->num_syms); | 2152 | sizeof(*mod->syms), &mod->num_syms); |
| 2151 | mod->crcs = section_addr(hdr, sechdrs, secstrings, "__kcrctab"); | 2153 | mod->crcs = section_addr(hdr, sechdrs, secstrings, "__kcrctab"); |
| @@ -2291,11 +2293,11 @@ static noinline struct module *load_module(void __user *umod, | |||
| 2291 | */ | 2293 | */ |
| 2292 | list_add_rcu(&mod->list, &modules); | 2294 | list_add_rcu(&mod->list, &modules); |
| 2293 | 2295 | ||
| 2294 | err = parse_args(mod->name, mod->args, kp, num_kp, NULL); | 2296 | err = parse_args(mod->name, mod->args, mod->kp, mod->num_kp, NULL); |
| 2295 | if (err < 0) | 2297 | if (err < 0) |
| 2296 | goto unlink; | 2298 | goto unlink; |
| 2297 | 2299 | ||
| 2298 | err = mod_sysfs_setup(mod, kp, num_kp); | 2300 | err = mod_sysfs_setup(mod, mod->kp, mod->num_kp); |
| 2299 | if (err < 0) | 2301 | if (err < 0) |
| 2300 | goto unlink; | 2302 | goto unlink; |
| 2301 | add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs); | 2303 | add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs); |
diff --git a/kernel/params.c b/kernel/params.c index a1e3025b19a9..de273ec85bd2 100644 --- a/kernel/params.c +++ b/kernel/params.c | |||
| @@ -24,6 +24,9 @@ | |||
| 24 | #include <linux/err.h> | 24 | #include <linux/err.h> |
| 25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
| 26 | 26 | ||
| 27 | /* We abuse the high bits of "perm" to record whether we kmalloc'ed. */ | ||
| 28 | #define KPARAM_KMALLOCED 0x80000000 | ||
| 29 | |||
| 27 | #if 0 | 30 | #if 0 |
| 28 | #define DEBUGP printk | 31 | #define DEBUGP printk |
| 29 | #else | 32 | #else |
| @@ -217,7 +220,19 @@ int param_set_charp(const char *val, struct kernel_param *kp) | |||
| 217 | return -ENOSPC; | 220 | return -ENOSPC; |
| 218 | } | 221 | } |
| 219 | 222 | ||
| 220 | *(char **)kp->arg = (char *)val; | 223 | if (kp->perm & KPARAM_KMALLOCED) |
| 224 | kfree(*(char **)kp->arg); | ||
| 225 | |||
| 226 | /* This is a hack. We can't need to strdup in early boot, and we | ||
| 227 | * don't need to; this mangled commandline is preserved. */ | ||
| 228 | if (slab_is_available()) { | ||
| 229 | kp->perm |= KPARAM_KMALLOCED; | ||
| 230 | *(char **)kp->arg = kstrdup(val, GFP_KERNEL); | ||
| 231 | if (!kp->arg) | ||
| 232 | return -ENOMEM; | ||
| 233 | } else | ||
| 234 | *(const char **)kp->arg = val; | ||
| 235 | |||
| 221 | return 0; | 236 | return 0; |
| 222 | } | 237 | } |
| 223 | 238 | ||
| @@ -571,6 +586,15 @@ void module_param_sysfs_remove(struct module *mod) | |||
| 571 | } | 586 | } |
| 572 | #endif | 587 | #endif |
| 573 | 588 | ||
| 589 | void destroy_params(const struct kernel_param *params, unsigned num) | ||
| 590 | { | ||
| 591 | unsigned int i; | ||
| 592 | |||
| 593 | for (i = 0; i < num; i++) | ||
| 594 | if (params[i].perm & KPARAM_KMALLOCED) | ||
| 595 | kfree(*(char **)params[i].arg); | ||
| 596 | } | ||
| 597 | |||
| 574 | static void __init kernel_add_sysfs_param(const char *name, | 598 | static void __init kernel_add_sysfs_param(const char *name, |
| 575 | struct kernel_param *kparam, | 599 | struct kernel_param *kparam, |
| 576 | unsigned int name_skip) | 600 | unsigned int name_skip) |
