modules: de-mutex more symbol lookup paths in the module code

Kyle McMartin reports sysrq_timer_list_show() can hit the module mutex
from hard interrupt context.  These paths don't need to though, since we
long ago changed all the module list manipulation to occur via
stop_machine().

Disabling preemption is enough.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Kyle McMartin <kyle@mcmartin.ca>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Rusty Russell 2008-01-14 00:55:03 -08:00 committed by Linus Torvalds
parent 1a1b285c24
commit cb2a52052c
1 changed files with 18 additions and 11 deletions

View File

@ -2214,29 +2214,34 @@ static const char *get_ksymbol(struct module *mod,
/* For kallsyms to ask for address resolution. NULL means not found. /* For kallsyms to ask for address resolution. NULL means not found.
We don't lock, as this is used for oops resolution and races are a We don't lock, as this is used for oops resolution and races are a
lesser concern. */ lesser concern. */
/* FIXME: Risky: returns a pointer into a module w/o lock */
const char *module_address_lookup(unsigned long addr, const char *module_address_lookup(unsigned long addr,
unsigned long *size, unsigned long *size,
unsigned long *offset, unsigned long *offset,
char **modname) char **modname)
{ {
struct module *mod; struct module *mod;
const char *ret = NULL;
preempt_disable();
list_for_each_entry(mod, &modules, list) { list_for_each_entry(mod, &modules, list) {
if (within(addr, mod->module_init, mod->init_size) if (within(addr, mod->module_init, mod->init_size)
|| within(addr, mod->module_core, mod->core_size)) { || within(addr, mod->module_core, mod->core_size)) {
if (modname) if (modname)
*modname = mod->name; *modname = mod->name;
return get_ksymbol(mod, addr, size, offset); ret = get_ksymbol(mod, addr, size, offset);
break;
} }
} }
return NULL; preempt_enable();
return ret;
} }
int lookup_module_symbol_name(unsigned long addr, char *symname) int lookup_module_symbol_name(unsigned long addr, char *symname)
{ {
struct module *mod; struct module *mod;
mutex_lock(&module_mutex); preempt_disable();
list_for_each_entry(mod, &modules, list) { list_for_each_entry(mod, &modules, list) {
if (within(addr, mod->module_init, mod->init_size) || if (within(addr, mod->module_init, mod->init_size) ||
within(addr, mod->module_core, mod->core_size)) { within(addr, mod->module_core, mod->core_size)) {
@ -2246,12 +2251,12 @@ int lookup_module_symbol_name(unsigned long addr, char *symname)
if (!sym) if (!sym)
goto out; goto out;
strlcpy(symname, sym, KSYM_NAME_LEN); strlcpy(symname, sym, KSYM_NAME_LEN);
mutex_unlock(&module_mutex); preempt_enable();
return 0; return 0;
} }
} }
out: out:
mutex_unlock(&module_mutex); preempt_enable();
return -ERANGE; return -ERANGE;
} }
@ -2260,7 +2265,7 @@ int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size,
{ {
struct module *mod; struct module *mod;
mutex_lock(&module_mutex); preempt_disable();
list_for_each_entry(mod, &modules, list) { list_for_each_entry(mod, &modules, list) {
if (within(addr, mod->module_init, mod->init_size) || if (within(addr, mod->module_init, mod->init_size) ||
within(addr, mod->module_core, mod->core_size)) { within(addr, mod->module_core, mod->core_size)) {
@ -2273,12 +2278,12 @@ int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size,
strlcpy(modname, mod->name, MODULE_NAME_LEN); strlcpy(modname, mod->name, MODULE_NAME_LEN);
if (name) if (name)
strlcpy(name, sym, KSYM_NAME_LEN); strlcpy(name, sym, KSYM_NAME_LEN);
mutex_unlock(&module_mutex); preempt_enable();
return 0; return 0;
} }
} }
out: out:
mutex_unlock(&module_mutex); preempt_enable();
return -ERANGE; return -ERANGE;
} }
@ -2287,7 +2292,7 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
{ {
struct module *mod; struct module *mod;
mutex_lock(&module_mutex); preempt_disable();
list_for_each_entry(mod, &modules, list) { list_for_each_entry(mod, &modules, list) {
if (symnum < mod->num_symtab) { if (symnum < mod->num_symtab) {
*value = mod->symtab[symnum].st_value; *value = mod->symtab[symnum].st_value;
@ -2296,12 +2301,12 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
KSYM_NAME_LEN); KSYM_NAME_LEN);
strlcpy(module_name, mod->name, MODULE_NAME_LEN); strlcpy(module_name, mod->name, MODULE_NAME_LEN);
*exported = is_exported(name, mod); *exported = is_exported(name, mod);
mutex_unlock(&module_mutex); preempt_enable();
return 0; return 0;
} }
symnum -= mod->num_symtab; symnum -= mod->num_symtab;
} }
mutex_unlock(&module_mutex); preempt_enable();
return -ERANGE; return -ERANGE;
} }
@ -2324,6 +2329,7 @@ unsigned long module_kallsyms_lookup_name(const char *name)
unsigned long ret = 0; unsigned long ret = 0;
/* Don't lock: we're in enough trouble already. */ /* Don't lock: we're in enough trouble already. */
preempt_disable();
if ((colon = strchr(name, ':')) != NULL) { if ((colon = strchr(name, ':')) != NULL) {
*colon = '\0'; *colon = '\0';
if ((mod = find_module(name)) != NULL) if ((mod = find_module(name)) != NULL)
@ -2334,6 +2340,7 @@ unsigned long module_kallsyms_lookup_name(const char *name)
if ((ret = mod_find_symname(mod, name)) != 0) if ((ret = mod_find_symname(mod, name)) != 0)
break; break;
} }
preempt_enable();
return ret; return ret;
} }
#endif /* CONFIG_KALLSYMS */ #endif /* CONFIG_KALLSYMS */