On Thu, Mar 19, 2015 at 11:04:33PM +0100, Peter Zijlstra wrote: > On Thu, Mar 19, 2015 at 01:58:33PM -0700, Andrew Morton wrote: > > OK. This code is basically required to support perf/ftrace and > > modules, yes? Presumably small and space-constrained systems aren't > > using either, so they don't take the hit. > > > > However CONFIG_MODULES systems which aren't using perf/ftrace _do_ take > > a hit. How many systems are we talking here? All non-x86? > > No, there's plenty !x86 systems that have NMI and perf/ftrace, in fact, > ARM has them (FIQ) and there's event some ARM chips that use them for > perf (i.MX6 is one). > > But sure, we could make this depend on CONFIG_PERF_EVENTS || > CONFIG_TRACING.
A little something like so. Signed-off-by: Peter Zijlstra (Intel) <pet...@infradead.org> --- kernel/module.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) --- a/kernel/module.c +++ b/kernel/module.c @@ -102,6 +102,8 @@ DEFINE_MUTEX(module_mutex); EXPORT_SYMBOL_GPL(module_mutex); static LIST_HEAD(modules); +#if defined(CONFIG_PERF_EVENTS) || defined(CONFIG_TRACING) + /* * Use a latched RB-tree for __module_address(); this allows us to use * RCU-sched lookups of the address from any context. @@ -109,6 +111,10 @@ static LIST_HEAD(modules); * Because modules have two address ranges: init and core, we need two * latch_tree_nodes entries. We use the order they appear in struct module to * determine if we need to use the init or core values for the comparisons. + * + * This is conditional on PERF_EVENTS || TRACING because those can really hit + * __module_address() hard by doing a lot of stack unwinding; potentially from + * NMI context. */ static __always_inline unsigned long __mod_tree_val(struct latch_tree_node *n) @@ -185,7 +191,7 @@ static void mod_tree_remove(struct modul mod_tree_remove_init(mod); } -static struct module *mod_tree_find(unsigned long addr) +static struct module *mod_find(unsigned long addr) { struct latch_tree_node *ltn; @@ -194,6 +200,26 @@ static struct module *mod_tree_find(unsi return ltn ? ltn->priv : NULL; } +#else /* !(PERF_EVENTS || TRACING) */ + +static void mod_tree_insert(struct module *mod) { } +static void mod_tree_remove_init(struct module *mod) { } +static void mod_tree_remove(struct module *mod) { } + +static struct module *mod_find(unsigned long addr) +{ + struct module *mod; + + list_for_each_entry_rcu(mod, &modules, list) { + if (within_module(addr, mod)) + return mod; + } + + return NULL; +} + +#endif /* !(PERF_EVENTS || TRACING) */ + #ifdef CONFIG_KGDB_KDB struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */ #endif /* CONFIG_KGDB_KDB */ @@ -3939,7 +3965,7 @@ struct module *__module_address(unsigned module_assert_mutex_or_preempt(); - mod = mod_tree_find(addr); + mod = mod_find(addr); if (mod) { BUG_ON(!within_module(addr, mod)); if (mod->state == MODULE_STATE_UNFORMED) -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/