diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-28 23:27:09 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-28 23:27:09 +0200 |
commit | d25413efa9536e2f425ea45c7720598035c597bc (patch) | |
tree | 97dcd459a7ec23c9438983fe14a23aef03b09bad | |
parent | Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmo... (diff) | |
parent | module: Remove module size limit (diff) | |
download | linux-d25413efa9536e2f425ea45c7720598035c597bc.tar.xz linux-d25413efa9536e2f425ea45c7720598035c597bc.zip |
Merge git://github.com/rustyrussell/linux
Pull module and param updates from Rusty Russell:
"I'm getting married next week, and then honeymoon until 6th May. I'll
be offline from next week, except to post the compulsory pictures if
Alex shaves her head..."
I'm sure Rusty can take time off from his honeymoon if something comes
up. And here's the explanation about head shaving:
http://baldalex.org/
in case you wondered and wanted to support another insane caper or
Rusty's involving shaving.
What *is* it with Rusty and shaving, anyway?
* git://github.com/rustyrussell/linux:
module: Remove module size limit
module: move __module_get and try_module_get() out of line.
params: <level>_initcall-like kernel parameters
module_param: remove support for bool parameters which are really int.
module: add kernel param to force disable module load
-rw-r--r-- | Documentation/kernel-parameters.txt | 2 | ||||
-rw-r--r-- | arch/powerpc/mm/hugetlbpage.c | 3 | ||||
-rw-r--r-- | include/asm-generic/vmlinux.lds.h | 35 | ||||
-rw-r--r-- | include/linux/module.h | 32 | ||||
-rw-r--r-- | include/linux/moduleparam.h | 58 | ||||
-rw-r--r-- | init/main.c | 65 | ||||
-rw-r--r-- | kernel/module.c | 37 | ||||
-rw-r--r-- | kernel/params.c | 39 |
8 files changed, 172 insertions, 99 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 58eac231fe69..e2f8c297a8a4 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1869,6 +1869,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted. shutdown the other cpus. Instead use the REBOOT_VECTOR irq. + nomodule Disable module load + nopat [X86] Disable PAT (page attribute table extension of pagetables) support. diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index 57c7465e656e..a3e628727697 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -310,7 +310,8 @@ void __init reserve_hugetlb_gpages(void) int i; strlcpy(cmdline, boot_command_line, COMMAND_LINE_SIZE); - parse_args("hugetlb gpages", cmdline, NULL, 0, &do_gpage_early_setup); + parse_args("hugetlb gpages", cmdline, NULL, 0, 0, 0, + &do_gpage_early_setup); /* * Walk gpage list in reverse, allocating larger page sizes first. diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 798603e8ec38..8aeadf6b553a 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -616,30 +616,23 @@ *(.init.setup) \ VMLINUX_SYMBOL(__setup_end) = .; -#define INITCALLS \ - *(.initcallearly.init) \ - VMLINUX_SYMBOL(__early_initcall_end) = .; \ - *(.initcall0.init) \ - *(.initcall0s.init) \ - *(.initcall1.init) \ - *(.initcall1s.init) \ - *(.initcall2.init) \ - *(.initcall2s.init) \ - *(.initcall3.init) \ - *(.initcall3s.init) \ - *(.initcall4.init) \ - *(.initcall4s.init) \ - *(.initcall5.init) \ - *(.initcall5s.init) \ - *(.initcallrootfs.init) \ - *(.initcall6.init) \ - *(.initcall6s.init) \ - *(.initcall7.init) \ - *(.initcall7s.init) +#define INIT_CALLS_LEVEL(level) \ + VMLINUX_SYMBOL(__initcall##level##_start) = .; \ + *(.initcall##level##.init) \ + *(.initcall##level##s.init) \ #define INIT_CALLS \ VMLINUX_SYMBOL(__initcall_start) = .; \ - INITCALLS \ + *(.initcallearly.init) \ + INIT_CALLS_LEVEL(0) \ + INIT_CALLS_LEVEL(1) \ + INIT_CALLS_LEVEL(2) \ + INIT_CALLS_LEVEL(3) \ + INIT_CALLS_LEVEL(4) \ + INIT_CALLS_LEVEL(5) \ + INIT_CALLS_LEVEL(rootfs) \ + INIT_CALLS_LEVEL(6) \ + INIT_CALLS_LEVEL(7) \ VMLINUX_SYMBOL(__initcall_end) = .; #define CON_INITCALL \ diff --git a/include/linux/module.h b/include/linux/module.h index 4598bf03e98b..fbcafe2ee13e 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -21,8 +21,6 @@ #include <linux/percpu.h> #include <asm/module.h> -#include <trace/events/module.h> - /* Not Yet Implemented */ #define MODULE_SUPPORTED_DEVICE(name) @@ -452,33 +450,11 @@ void symbol_put_addr(void *addr); /* Sometimes we know we already have a refcount, and it's easier not to handle the error case (which only happens with rmmod --wait). */ -static inline void __module_get(struct module *module) -{ - if (module) { - preempt_disable(); - __this_cpu_inc(module->refptr->incs); - trace_module_get(module, _THIS_IP_); - preempt_enable(); - } -} - -static inline int try_module_get(struct module *module) -{ - int ret = 1; - - if (module) { - preempt_disable(); +extern void __module_get(struct module *module); - if (likely(module_is_live(module))) { - __this_cpu_inc(module->refptr->incs); - trace_module_get(module, _THIS_IP_); - } else - ret = 0; - - preempt_enable(); - } - return ret; -} +/* This is the Right Way to get a module: if it fails, it's being removed, + * so pretend it's not there. */ +extern bool try_module_get(struct module *module); extern void module_put(struct module *module); diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h index c47f4d60db0b..ea36486378d8 100644 --- a/include/linux/moduleparam.h +++ b/include/linux/moduleparam.h @@ -47,14 +47,11 @@ struct kernel_param_ops { void (*free)(void *arg); }; -/* Flag bits for kernel_param.flags */ -#define KPARAM_ISBOOL 2 - struct kernel_param { const char *name; const struct kernel_param_ops *ops; u16 perm; - u16 flags; + s16 level; union { void *arg; const struct kparam_string *str; @@ -131,8 +128,40 @@ struct kparam_array * The ops can have NULL set or get functions. */ #define module_param_cb(name, ops, arg, perm) \ - __module_param_call(MODULE_PARAM_PREFIX, \ - name, ops, arg, __same_type((arg), bool *), perm) + __module_param_call(MODULE_PARAM_PREFIX, name, ops, arg, perm, 0) + +/** + * <level>_param_cb - general callback for a module/cmdline parameter + * to be evaluated before certain initcall level + * @name: a valid C identifier which is the parameter name. + * @ops: the set & get operations for this parameter. + * @perm: visibility in sysfs. + * + * The ops can have NULL set or get functions. + */ +#define __level_param_cb(name, ops, arg, perm, level) \ + __module_param_call(MODULE_PARAM_PREFIX, name, ops, arg, perm, level) + +#define core_param_cb(name, ops, arg, perm) \ + __level_param_cb(name, ops, arg, perm, 1) + +#define postcore_param_cb(name, ops, arg, perm) \ + __level_param_cb(name, ops, arg, perm, 2) + +#define arch_param_cb(name, ops, arg, perm) \ + __level_param_cb(name, ops, arg, perm, 3) + +#define subsys_param_cb(name, ops, arg, perm) \ + __level_param_cb(name, ops, arg, perm, 4) + +#define fs_param_cb(name, ops, arg, perm) \ + __level_param_cb(name, ops, arg, perm, 5) + +#define device_param_cb(name, ops, arg, perm) \ + __level_param_cb(name, ops, arg, perm, 6) + +#define late_param_cb(name, ops, arg, perm) \ + __level_param_cb(name, ops, arg, perm, 7) /* On alpha, ia64 and ppc64 relocations to global data cannot go into read-only sections (which is part of respective UNIX ABI on these @@ -146,7 +175,7 @@ struct kparam_array /* This is the fundamental function for registering boot/module parameters. */ -#define __module_param_call(prefix, name, ops, arg, isbool, perm) \ +#define __module_param_call(prefix, name, ops, arg, perm, level) \ /* Default value instead of permissions? */ \ static int __param_perm_check_##name __attribute__((unused)) = \ BUILD_BUG_ON_ZERO((perm) < 0 || (perm) > 0777 || ((perm) & 2)) \ @@ -155,8 +184,7 @@ struct kparam_array static struct kernel_param __moduleparam_const __param_##name \ __used \ __attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \ - = { __param_str_##name, ops, perm, isbool ? KPARAM_ISBOOL : 0, \ - { arg } } + = { __param_str_##name, ops, perm, level, { arg } } /* Obsolete - use module_param_cb() */ #define module_param_call(name, set, get, arg, perm) \ @@ -164,8 +192,7 @@ struct kparam_array { (void *)set, (void *)get }; \ __module_param_call(MODULE_PARAM_PREFIX, \ name, &__param_ops_##name, arg, \ - __same_type(arg, bool *), \ - (perm) + sizeof(__check_old_set_param(set))*0) + (perm) + sizeof(__check_old_set_param(set))*0, 0) /* We don't get oldget: it's often a new-style param_get_uint, etc. */ static inline int @@ -245,8 +272,7 @@ static inline void __kernel_param_unlock(void) */ #define core_param(name, var, type, perm) \ param_check_##type(name, &(var)); \ - __module_param_call("", name, ¶m_ops_##type, \ - &var, __same_type(var, bool), perm) + __module_param_call("", name, ¶m_ops_##type, &var, perm, 0) #endif /* !MODULE */ /** @@ -264,7 +290,7 @@ static inline void __kernel_param_unlock(void) = { len, string }; \ __module_param_call(MODULE_PARAM_PREFIX, name, \ ¶m_ops_string, \ - .str = &__param_string_##name, 0, perm); \ + .str = &__param_string_##name, perm, 0); \ __MODULE_PARM_TYPE(name, "string") /** @@ -292,6 +318,8 @@ extern int parse_args(const char *name, char *args, const struct kernel_param *params, unsigned num, + s16 level_min, + s16 level_max, int (*unknown)(char *param, char *val)); /* Called by module remove. */ @@ -403,7 +431,7 @@ extern int param_set_bint(const char *val, const struct kernel_param *kp); __module_param_call(MODULE_PARAM_PREFIX, name, \ ¶m_array_ops, \ .arr = &__param_arr_##name, \ - __same_type(array[0], bool), perm); \ + perm, 0); \ __MODULE_PARM_TYPE(name, "array of " #type) extern struct kernel_param_ops param_array_ops; diff --git a/init/main.c b/init/main.c index c24805c824b9..439715858ba0 100644 --- a/init/main.c +++ b/init/main.c @@ -400,7 +400,7 @@ static int __init do_early_param(char *param, char *val) void __init parse_early_options(char *cmdline) { - parse_args("early options", cmdline, NULL, 0, do_early_param); + parse_args("early options", cmdline, NULL, 0, 0, 0, do_early_param); } /* Arch code calls this early on, or if not, just before other parsing. */ @@ -503,7 +503,7 @@ asmlinkage void __init start_kernel(void) parse_early_param(); parse_args("Booting kernel", static_command_line, __start___param, __stop___param - __start___param, - &unknown_bootoption); + 0, 0, &unknown_bootoption); jump_label_init(); @@ -699,16 +699,69 @@ int __init_or_module do_one_initcall(initcall_t fn) } -extern initcall_t __initcall_start[], __initcall_end[], __early_initcall_end[]; +extern initcall_t __initcall_start[]; +extern initcall_t __initcall0_start[]; +extern initcall_t __initcall1_start[]; +extern initcall_t __initcall2_start[]; +extern initcall_t __initcall3_start[]; +extern initcall_t __initcall4_start[]; +extern initcall_t __initcall5_start[]; +extern initcall_t __initcall6_start[]; +extern initcall_t __initcall7_start[]; +extern initcall_t __initcall_end[]; + +static initcall_t *initcall_levels[] __initdata = { + __initcall0_start, + __initcall1_start, + __initcall2_start, + __initcall3_start, + __initcall4_start, + __initcall5_start, + __initcall6_start, + __initcall7_start, + __initcall_end, +}; + +static char *initcall_level_names[] __initdata = { + "early parameters", + "core parameters", + "postcore parameters", + "arch parameters", + "subsys parameters", + "fs parameters", + "device parameters", + "late parameters", +}; + +static int __init ignore_unknown_bootoption(char *param, char *val) +{ + return 0; +} -static void __init do_initcalls(void) +static void __init do_initcall_level(int level) { + extern const struct kernel_param __start___param[], __stop___param[]; initcall_t *fn; - for (fn = __early_initcall_end; fn < __initcall_end; fn++) + strcpy(static_command_line, saved_command_line); + parse_args(initcall_level_names[level], + static_command_line, __start___param, + __stop___param - __start___param, + level, level, + ignore_unknown_bootoption); + + for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++) do_one_initcall(*fn); } +static void __init do_initcalls(void) +{ + int level; + + for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++) + do_initcall_level(level); +} + /* * Ok, the machine is now initialized. None of the devices * have been touched yet, but the CPU subsystem is up and @@ -732,7 +785,7 @@ static void __init do_pre_smp_initcalls(void) { initcall_t *fn; - for (fn = __initcall_start; fn < __early_initcall_end; fn++) + for (fn = __initcall_start; fn < __initcall0_start; fn++) do_one_initcall(*fn); } diff --git a/kernel/module.c b/kernel/module.c index 2c932760fd33..78ac6ec1e425 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -105,6 +105,7 @@ struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */ /* Block module loading/unloading? */ int modules_disabled = 0; +core_param(nomodule, modules_disabled, bint, 0); /* Waiting for a module to finish initializing? */ static DECLARE_WAIT_QUEUE_HEAD(module_wq); @@ -903,6 +904,36 @@ static ssize_t show_refcnt(struct module_attribute *mattr, static struct module_attribute modinfo_refcnt = __ATTR(refcnt, 0444, show_refcnt, NULL); +void __module_get(struct module *module) +{ + if (module) { + preempt_disable(); + __this_cpu_inc(module->refptr->incs); + trace_module_get(module, _RET_IP_); + preempt_enable(); + } +} +EXPORT_SYMBOL(__module_get); + +bool try_module_get(struct module *module) +{ + bool ret = true; + + if (module) { + preempt_disable(); + + if (likely(module_is_live(module))) { + __this_cpu_inc(module->refptr->incs); + trace_module_get(module, _RET_IP_); + } else + ret = false; + + preempt_enable(); + } + return ret; +} +EXPORT_SYMBOL(try_module_get); + void module_put(struct module *module) { if (module) { @@ -2380,8 +2411,7 @@ static int copy_and_check(struct load_info *info, return -ENOEXEC; /* Suck in entire file: we'll want most of it. */ - /* vmalloc barfs on "unusual" numbers. Check here */ - if (len > 64 * 1024 * 1024 || (hdr = vmalloc(len)) == NULL) + if ((hdr = vmalloc(len)) == NULL) return -ENOMEM; if (copy_from_user(hdr, umod, len) != 0) { @@ -2922,7 +2952,8 @@ static struct module *load_module(void __user *umod, mutex_unlock(&module_mutex); /* Module is ready to execute: parsing args may do that. */ - err = parse_args(mod->name, mod->args, mod->kp, mod->num_kp, NULL); + err = parse_args(mod->name, mod->args, mod->kp, mod->num_kp, + -32768, 32767, NULL); if (err < 0) goto unlink; diff --git a/kernel/params.c b/kernel/params.c index 47f5bf12434a..f37d82631347 100644 --- a/kernel/params.c +++ b/kernel/params.c @@ -87,6 +87,8 @@ static int parse_one(char *param, char *val, const struct kernel_param *params, unsigned num_params, + s16 min_level, + s16 max_level, int (*handle_unknown)(char *param, char *val)) { unsigned int i; @@ -95,6 +97,9 @@ static int parse_one(char *param, /* Find parameter */ for (i = 0; i < num_params; i++) { if (parameq(param, params[i].name)) { + if (params[i].level < min_level + || params[i].level > max_level) + return 0; /* No one handled NULL, so do it here. */ if (!val && params[i].ops->set != param_set_bool && params[i].ops->set != param_set_bint) @@ -174,6 +179,8 @@ int parse_args(const char *name, char *args, const struct kernel_param *params, unsigned num, + s16 min_level, + s16 max_level, int (*unknown)(char *param, char *val)) { char *param, *val; @@ -189,7 +196,8 @@ int parse_args(const char *name, args = next_arg(args, ¶m, &val); irq_was_disabled = irqs_disabled(); - ret = parse_one(param, val, params, num, unknown); + ret = parse_one(param, val, params, num, + min_level, max_level, unknown); if (irq_was_disabled && !irqs_disabled()) { printk(KERN_WARNING "parse_args(): option '%s' enabled " "irq's!\n", param); @@ -297,35 +305,18 @@ EXPORT_SYMBOL(param_ops_charp); /* Actually could be a bool or an int, for historical reasons. */ int param_set_bool(const char *val, const struct kernel_param *kp) { - bool v; - int ret; - /* No equals means "set"... */ if (!val) val = "1"; /* One of =[yYnN01] */ - ret = strtobool(val, &v); - if (ret) - return ret; - - if (kp->flags & KPARAM_ISBOOL) - *(bool *)kp->arg = v; - else - *(int *)kp->arg = v; - return 0; + return strtobool(val, kp->arg); } EXPORT_SYMBOL(param_set_bool); int param_get_bool(char *buffer, const struct kernel_param *kp) { - bool val; - if (kp->flags & KPARAM_ISBOOL) - val = *(bool *)kp->arg; - else - val = *(int *)kp->arg; - /* Y and N chosen as being relatively non-coder friendly */ - return sprintf(buffer, "%c", val ? 'Y' : 'N'); + return sprintf(buffer, "%c", *(bool *)kp->arg ? 'Y' : 'N'); } EXPORT_SYMBOL(param_get_bool); @@ -343,7 +334,6 @@ int param_set_invbool(const char *val, const struct kernel_param *kp) struct kernel_param dummy; dummy.arg = &boolval; - dummy.flags = KPARAM_ISBOOL; ret = param_set_bool(val, &dummy); if (ret == 0) *(bool *)kp->arg = !boolval; @@ -372,7 +362,6 @@ int param_set_bint(const char *val, const struct kernel_param *kp) /* Match bool exactly, by re-using it. */ boolkp = *kp; boolkp.arg = &v; - boolkp.flags |= KPARAM_ISBOOL; ret = param_set_bool(val, &boolkp); if (ret == 0) @@ -393,7 +382,7 @@ static int param_array(const char *name, unsigned int min, unsigned int max, void *elem, int elemsize, int (*set)(const char *, const struct kernel_param *kp), - u16 flags, + s16 level, unsigned int *num) { int ret; @@ -403,7 +392,7 @@ static int param_array(const char *name, /* Get the name right for errors. */ kp.name = name; kp.arg = elem; - kp.flags = flags; + kp.level = level; *num = 0; /* We expect a comma-separated list of values. */ @@ -444,7 +433,7 @@ static int param_array_set(const char *val, const struct kernel_param *kp) unsigned int temp_num; return param_array(kp->name, val, 1, arr->max, arr->elem, - arr->elemsize, arr->ops->set, kp->flags, + arr->elemsize, arr->ops->set, kp->level, arr->num ?: &temp_num); } |