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
This commit is contained in:
Linus Torvalds 2012-03-28 14:27:09 -07:00
commit d25413efa9
8 changed files with 173 additions and 100 deletions

View file

@ -1869,6 +1869,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
shutdown the other cpus. Instead use the REBOOT_VECTOR shutdown the other cpus. Instead use the REBOOT_VECTOR
irq. irq.
nomodule Disable module load
nopat [X86] Disable PAT (page attribute table extension of nopat [X86] Disable PAT (page attribute table extension of
pagetables) support. pagetables) support.

View file

@ -310,7 +310,8 @@ void __init reserve_hugetlb_gpages(void)
int i; int i;
strlcpy(cmdline, boot_command_line, COMMAND_LINE_SIZE); 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. * Walk gpage list in reverse, allocating larger page sizes first.

View file

@ -616,30 +616,23 @@
*(.init.setup) \ *(.init.setup) \
VMLINUX_SYMBOL(__setup_end) = .; VMLINUX_SYMBOL(__setup_end) = .;
#define INITCALLS \ #define INIT_CALLS_LEVEL(level) \
*(.initcallearly.init) \ VMLINUX_SYMBOL(__initcall##level##_start) = .; \
VMLINUX_SYMBOL(__early_initcall_end) = .; \ *(.initcall##level##.init) \
*(.initcall0.init) \ *(.initcall##level##s.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 \ #define INIT_CALLS \
VMLINUX_SYMBOL(__initcall_start) = .; \ 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) = .; VMLINUX_SYMBOL(__initcall_end) = .;
#define CON_INITCALL \ #define CON_INITCALL \

View file

@ -21,8 +21,6 @@
#include <linux/percpu.h> #include <linux/percpu.h>
#include <asm/module.h> #include <asm/module.h>
#include <trace/events/module.h>
/* Not Yet Implemented */ /* Not Yet Implemented */
#define MODULE_SUPPORTED_DEVICE(name) #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 /* Sometimes we know we already have a refcount, and it's easier not
to handle the error case (which only happens with rmmod --wait). */ to handle the error case (which only happens with rmmod --wait). */
static inline void __module_get(struct module *module) extern 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) /* This is the Right Way to get a module: if it fails, it's being removed,
{ * so pretend it's not there. */
int ret = 1; extern bool try_module_get(struct module *module);
if (module) {
preempt_disable();
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;
}
extern void module_put(struct module *module); extern void module_put(struct module *module);

View file

@ -47,14 +47,11 @@ struct kernel_param_ops {
void (*free)(void *arg); void (*free)(void *arg);
}; };
/* Flag bits for kernel_param.flags */
#define KPARAM_ISBOOL 2
struct kernel_param { struct kernel_param {
const char *name; const char *name;
const struct kernel_param_ops *ops; const struct kernel_param_ops *ops;
u16 perm; u16 perm;
u16 flags; s16 level;
union { union {
void *arg; void *arg;
const struct kparam_string *str; const struct kparam_string *str;
@ -131,8 +128,40 @@ struct kparam_array
* The ops can have NULL set or get functions. * The ops can have NULL set or get functions.
*/ */
#define module_param_cb(name, ops, arg, perm) \ #define module_param_cb(name, ops, arg, perm) \
__module_param_call(MODULE_PARAM_PREFIX, \ __module_param_call(MODULE_PARAM_PREFIX, name, ops, arg, perm, 0)
name, ops, arg, __same_type((arg), bool *), perm)
/**
* <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 /* On alpha, ia64 and ppc64 relocations to global data cannot go into
read-only sections (which is part of respective UNIX ABI on these 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 /* This is the fundamental function for registering boot/module
parameters. */ 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? */ \ /* Default value instead of permissions? */ \
static int __param_perm_check_##name __attribute__((unused)) = \ static int __param_perm_check_##name __attribute__((unused)) = \
BUILD_BUG_ON_ZERO((perm) < 0 || (perm) > 0777 || ((perm) & 2)) \ 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 \ static struct kernel_param __moduleparam_const __param_##name \
__used \ __used \
__attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \ __attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \
= { __param_str_##name, ops, perm, isbool ? KPARAM_ISBOOL : 0, \ = { __param_str_##name, ops, perm, level, { arg } }
{ arg } }
/* Obsolete - use module_param_cb() */ /* Obsolete - use module_param_cb() */
#define module_param_call(name, set, get, arg, perm) \ #define module_param_call(name, set, get, arg, perm) \
@ -164,8 +192,7 @@ struct kparam_array
{ (void *)set, (void *)get }; \ { (void *)set, (void *)get }; \
__module_param_call(MODULE_PARAM_PREFIX, \ __module_param_call(MODULE_PARAM_PREFIX, \
name, &__param_ops_##name, arg, \ name, &__param_ops_##name, arg, \
__same_type(arg, bool *), \ (perm) + sizeof(__check_old_set_param(set))*0, 0)
(perm) + sizeof(__check_old_set_param(set))*0)
/* We don't get oldget: it's often a new-style param_get_uint, etc. */ /* We don't get oldget: it's often a new-style param_get_uint, etc. */
static inline int static inline int
@ -245,8 +272,7 @@ static inline void __kernel_param_unlock(void)
*/ */
#define core_param(name, var, type, perm) \ #define core_param(name, var, type, perm) \
param_check_##type(name, &(var)); \ param_check_##type(name, &(var)); \
__module_param_call("", name, &param_ops_##type, \ __module_param_call("", name, &param_ops_##type, &var, perm, 0)
&var, __same_type(var, bool), perm)
#endif /* !MODULE */ #endif /* !MODULE */
/** /**
@ -264,7 +290,7 @@ static inline void __kernel_param_unlock(void)
= { len, string }; \ = { len, string }; \
__module_param_call(MODULE_PARAM_PREFIX, name, \ __module_param_call(MODULE_PARAM_PREFIX, name, \
&param_ops_string, \ &param_ops_string, \
.str = &__param_string_##name, 0, perm); \ .str = &__param_string_##name, perm, 0); \
__MODULE_PARM_TYPE(name, "string") __MODULE_PARM_TYPE(name, "string")
/** /**
@ -292,6 +318,8 @@ extern int parse_args(const char *name,
char *args, char *args,
const struct kernel_param *params, const struct kernel_param *params,
unsigned num, unsigned num,
s16 level_min,
s16 level_max,
int (*unknown)(char *param, char *val)); int (*unknown)(char *param, char *val));
/* Called by module remove. */ /* 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, \ __module_param_call(MODULE_PARAM_PREFIX, name, \
&param_array_ops, \ &param_array_ops, \
.arr = &__param_arr_##name, \ .arr = &__param_arr_##name, \
__same_type(array[0], bool), perm); \ perm, 0); \
__MODULE_PARM_TYPE(name, "array of " #type) __MODULE_PARM_TYPE(name, "array of " #type)
extern struct kernel_param_ops param_array_ops; extern struct kernel_param_ops param_array_ops;

View file

@ -400,7 +400,7 @@ static int __init do_early_param(char *param, char *val)
void __init parse_early_options(char *cmdline) 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. */ /* 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_early_param();
parse_args("Booting kernel", static_command_line, __start___param, parse_args("Booting kernel", static_command_line, __start___param,
__stop___param - __start___param, __stop___param - __start___param,
&unknown_bootoption); 0, 0, &unknown_bootoption);
jump_label_init(); jump_label_init();
@ -699,14 +699,67 @@ 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_initcall_level(int level)
{
extern const struct kernel_param __start___param[], __stop___param[];
initcall_t *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) static void __init do_initcalls(void)
{ {
initcall_t *fn; int level;
for (fn = __early_initcall_end; fn < __initcall_end; fn++) for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++)
do_one_initcall(*fn); do_initcall_level(level);
} }
/* /*
@ -732,7 +785,7 @@ static void __init do_pre_smp_initcalls(void)
{ {
initcall_t *fn; initcall_t *fn;
for (fn = __initcall_start; fn < __early_initcall_end; fn++) for (fn = __initcall_start; fn < __initcall0_start; fn++)
do_one_initcall(*fn); do_one_initcall(*fn);
} }

View file

@ -105,6 +105,7 @@ struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */
/* Block module loading/unloading? */ /* Block module loading/unloading? */
int modules_disabled = 0; int modules_disabled = 0;
core_param(nomodule, modules_disabled, bint, 0);
/* Waiting for a module to finish initializing? */ /* Waiting for a module to finish initializing? */
static DECLARE_WAIT_QUEUE_HEAD(module_wq); 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 = static struct module_attribute modinfo_refcnt =
__ATTR(refcnt, 0444, show_refcnt, NULL); __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) void module_put(struct module *module)
{ {
if (module) { if (module) {
@ -2380,8 +2411,7 @@ static int copy_and_check(struct load_info *info,
return -ENOEXEC; return -ENOEXEC;
/* Suck in entire file: we'll want most of it. */ /* Suck in entire file: we'll want most of it. */
/* vmalloc barfs on "unusual" numbers. Check here */ if ((hdr = vmalloc(len)) == NULL)
if (len > 64 * 1024 * 1024 || (hdr = vmalloc(len)) == NULL)
return -ENOMEM; return -ENOMEM;
if (copy_from_user(hdr, umod, len) != 0) { if (copy_from_user(hdr, umod, len) != 0) {
@ -2922,7 +2952,8 @@ static struct module *load_module(void __user *umod,
mutex_unlock(&module_mutex); mutex_unlock(&module_mutex);
/* Module is ready to execute: parsing args may do that. */ /* 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) if (err < 0)
goto unlink; goto unlink;

View file

@ -87,6 +87,8 @@ static int parse_one(char *param,
char *val, char *val,
const struct kernel_param *params, const struct kernel_param *params,
unsigned num_params, unsigned num_params,
s16 min_level,
s16 max_level,
int (*handle_unknown)(char *param, char *val)) int (*handle_unknown)(char *param, char *val))
{ {
unsigned int i; unsigned int i;
@ -95,6 +97,9 @@ static int parse_one(char *param,
/* Find parameter */ /* Find parameter */
for (i = 0; i < num_params; i++) { for (i = 0; i < num_params; i++) {
if (parameq(param, params[i].name)) { 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. */ /* No one handled NULL, so do it here. */
if (!val && params[i].ops->set != param_set_bool if (!val && params[i].ops->set != param_set_bool
&& params[i].ops->set != param_set_bint) && params[i].ops->set != param_set_bint)
@ -174,6 +179,8 @@ int parse_args(const char *name,
char *args, char *args,
const struct kernel_param *params, const struct kernel_param *params,
unsigned num, unsigned num,
s16 min_level,
s16 max_level,
int (*unknown)(char *param, char *val)) int (*unknown)(char *param, char *val))
{ {
char *param, *val; char *param, *val;
@ -189,7 +196,8 @@ int parse_args(const char *name,
args = next_arg(args, &param, &val); args = next_arg(args, &param, &val);
irq_was_disabled = irqs_disabled(); 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()) { if (irq_was_disabled && !irqs_disabled()) {
printk(KERN_WARNING "parse_args(): option '%s' enabled " printk(KERN_WARNING "parse_args(): option '%s' enabled "
"irq's!\n", param); "irq's!\n", param);
@ -297,35 +305,18 @@ EXPORT_SYMBOL(param_ops_charp);
/* Actually could be a bool or an int, for historical reasons. */ /* Actually could be a bool or an int, for historical reasons. */
int param_set_bool(const char *val, const struct kernel_param *kp) int param_set_bool(const char *val, const struct kernel_param *kp)
{ {
bool v;
int ret;
/* No equals means "set"... */ /* No equals means "set"... */
if (!val) val = "1"; if (!val) val = "1";
/* One of =[yYnN01] */ /* One of =[yYnN01] */
ret = strtobool(val, &v); return strtobool(val, kp->arg);
if (ret)
return ret;
if (kp->flags & KPARAM_ISBOOL)
*(bool *)kp->arg = v;
else
*(int *)kp->arg = v;
return 0;
} }
EXPORT_SYMBOL(param_set_bool); EXPORT_SYMBOL(param_set_bool);
int param_get_bool(char *buffer, const struct kernel_param *kp) 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 */ /* 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); 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; struct kernel_param dummy;
dummy.arg = &boolval; dummy.arg = &boolval;
dummy.flags = KPARAM_ISBOOL;
ret = param_set_bool(val, &dummy); ret = param_set_bool(val, &dummy);
if (ret == 0) if (ret == 0)
*(bool *)kp->arg = !boolval; *(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. */ /* Match bool exactly, by re-using it. */
boolkp = *kp; boolkp = *kp;
boolkp.arg = &v; boolkp.arg = &v;
boolkp.flags |= KPARAM_ISBOOL;
ret = param_set_bool(val, &boolkp); ret = param_set_bool(val, &boolkp);
if (ret == 0) if (ret == 0)
@ -393,7 +382,7 @@ static int param_array(const char *name,
unsigned int min, unsigned int max, unsigned int min, unsigned int max,
void *elem, int elemsize, void *elem, int elemsize,
int (*set)(const char *, const struct kernel_param *kp), int (*set)(const char *, const struct kernel_param *kp),
u16 flags, s16 level,
unsigned int *num) unsigned int *num)
{ {
int ret; int ret;
@ -403,7 +392,7 @@ static int param_array(const char *name,
/* Get the name right for errors. */ /* Get the name right for errors. */
kp.name = name; kp.name = name;
kp.arg = elem; kp.arg = elem;
kp.flags = flags; kp.level = level;
*num = 0; *num = 0;
/* We expect a comma-separated list of values. */ /* 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; unsigned int temp_num;
return param_array(kp->name, val, 1, arr->max, arr->elem, 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); arr->num ?: &temp_num);
} }