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:
		
				
					committed by
					
						
						Linus Torvalds
					
				
			
			
				
	
			
			
			
						parent
						
							1a1b285c24
						
					
				
				
					commit
					cb2a52052c
				
			@@ -2214,29 +2214,34 @@ static const char *get_ksymbol(struct module *mod,
 | 
			
		||||
/* 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
 | 
			
		||||
   lesser concern. */
 | 
			
		||||
/* FIXME: Risky: returns a pointer into a module w/o lock */
 | 
			
		||||
const char *module_address_lookup(unsigned long addr,
 | 
			
		||||
				  unsigned long *size,
 | 
			
		||||
				  unsigned long *offset,
 | 
			
		||||
				  char **modname)
 | 
			
		||||
{
 | 
			
		||||
	struct module *mod;
 | 
			
		||||
	const char *ret = NULL;
 | 
			
		||||
 | 
			
		||||
	preempt_disable();
 | 
			
		||||
	list_for_each_entry(mod, &modules, list) {
 | 
			
		||||
		if (within(addr, mod->module_init, mod->init_size)
 | 
			
		||||
		    || within(addr, mod->module_core, mod->core_size)) {
 | 
			
		||||
			if (modname)
 | 
			
		||||
				*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)
 | 
			
		||||
{
 | 
			
		||||
	struct module *mod;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&module_mutex);
 | 
			
		||||
	preempt_disable();
 | 
			
		||||
	list_for_each_entry(mod, &modules, list) {
 | 
			
		||||
		if (within(addr, mod->module_init, mod->init_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)
 | 
			
		||||
				goto out;
 | 
			
		||||
			strlcpy(symname, sym, KSYM_NAME_LEN);
 | 
			
		||||
			mutex_unlock(&module_mutex);
 | 
			
		||||
			preempt_enable();
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
out:
 | 
			
		||||
	mutex_unlock(&module_mutex);
 | 
			
		||||
	preempt_enable();
 | 
			
		||||
	return -ERANGE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -2260,7 +2265,7 @@ int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size,
 | 
			
		||||
{
 | 
			
		||||
	struct module *mod;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&module_mutex);
 | 
			
		||||
	preempt_disable();
 | 
			
		||||
	list_for_each_entry(mod, &modules, list) {
 | 
			
		||||
		if (within(addr, mod->module_init, mod->init_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);
 | 
			
		||||
			if (name)
 | 
			
		||||
				strlcpy(name, sym, KSYM_NAME_LEN);
 | 
			
		||||
			mutex_unlock(&module_mutex);
 | 
			
		||||
			preempt_enable();
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
out:
 | 
			
		||||
	mutex_unlock(&module_mutex);
 | 
			
		||||
	preempt_enable();
 | 
			
		||||
	return -ERANGE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -2287,7 +2292,7 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
 | 
			
		||||
{
 | 
			
		||||
	struct module *mod;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&module_mutex);
 | 
			
		||||
	preempt_disable();
 | 
			
		||||
	list_for_each_entry(mod, &modules, list) {
 | 
			
		||||
		if (symnum < mod->num_symtab) {
 | 
			
		||||
			*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);
 | 
			
		||||
			strlcpy(module_name, mod->name, MODULE_NAME_LEN);
 | 
			
		||||
			*exported = is_exported(name, mod);
 | 
			
		||||
			mutex_unlock(&module_mutex);
 | 
			
		||||
			preempt_enable();
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
		symnum -= mod->num_symtab;
 | 
			
		||||
	}
 | 
			
		||||
	mutex_unlock(&module_mutex);
 | 
			
		||||
	preempt_enable();
 | 
			
		||||
	return -ERANGE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -2324,6 +2329,7 @@ unsigned long module_kallsyms_lookup_name(const char *name)
 | 
			
		||||
	unsigned long ret = 0;
 | 
			
		||||
 | 
			
		||||
	/* Don't lock: we're in enough trouble already. */
 | 
			
		||||
	preempt_disable();
 | 
			
		||||
	if ((colon = strchr(name, ':')) != NULL) {
 | 
			
		||||
		*colon = '\0';
 | 
			
		||||
		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)
 | 
			
		||||
				break;
 | 
			
		||||
	}
 | 
			
		||||
	preempt_enable();
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
#endif /* CONFIG_KALLSYMS */
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user