diff options
author | Rusty Russell <rusty@rustcorp.com.au> | 2008-07-22 20:24:28 -0400 |
---|---|---|
committer | Rusty Russell <rusty@rustcorp.com.au> | 2008-07-22 05:24:28 -0400 |
commit | 3a642e99babe0617febb6f402e1e063479f489db (patch) | |
tree | 09f7d6c7b0a4e3869d11c739113e5dd5a8ff5a2c | |
parent | 2f0f2a334bc38b61a9afca951185cd3844ee709d (diff) |
modules: Take a shortcut for checking if an address is in a module
This patch keeps track of the boundaries of module allocation, in
order to speed up module_text_address().
Inspired by Arjan's version, which required arch-specific defines:
Various pieces of the kernel (lockdep, latencytop, etc) tend
to store backtraces, sometimes at a relatively high
frequency. In itself this isn't a big performance deal (after
all you're using diagnostics features), but there have been
some complaints from people who have over 100 modules loaded
that this is a tad too slow.
This is due to the new backtracer code which looks at every
slot on the stack to see if it's a kernel/module text address,
so that's 1024 slots. 1024 times 100 modules... that's a lot
of list walking.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
-rw-r--r-- | kernel/module.c | 24 |
1 files changed, 22 insertions, 2 deletions
diff --git a/kernel/module.c b/kernel/module.c index 5c7eb0695b3c..d8b5605132a0 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -70,6 +70,9 @@ static DECLARE_WAIT_QUEUE_HEAD(module_wq); | |||
70 | 70 | ||
71 | static BLOCKING_NOTIFIER_HEAD(module_notify_list); | 71 | static BLOCKING_NOTIFIER_HEAD(module_notify_list); |
72 | 72 | ||
73 | /* Bounds of module allocation, for speeding __module_text_address */ | ||
74 | static unsigned long module_addr_min = -1UL, module_addr_max = 0; | ||
75 | |||
73 | int register_module_notifier(struct notifier_block * nb) | 76 | int register_module_notifier(struct notifier_block * nb) |
74 | { | 77 | { |
75 | return blocking_notifier_chain_register(&module_notify_list, nb); | 78 | return blocking_notifier_chain_register(&module_notify_list, nb); |
@@ -1779,6 +1782,20 @@ static inline void add_kallsyms(struct module *mod, | |||
1779 | } | 1782 | } |
1780 | #endif /* CONFIG_KALLSYMS */ | 1783 | #endif /* CONFIG_KALLSYMS */ |
1781 | 1784 | ||
1785 | static void *module_alloc_update_bounds(unsigned long size) | ||
1786 | { | ||
1787 | void *ret = module_alloc(size); | ||
1788 | |||
1789 | if (ret) { | ||
1790 | /* Update module bounds. */ | ||
1791 | if ((unsigned long)ret < module_addr_min) | ||
1792 | module_addr_min = (unsigned long)ret; | ||
1793 | if ((unsigned long)ret + size > module_addr_max) | ||
1794 | module_addr_max = (unsigned long)ret + size; | ||
1795 | } | ||
1796 | return ret; | ||
1797 | } | ||
1798 | |||
1782 | /* Allocate and load the module: note that size of section 0 is always | 1799 | /* Allocate and load the module: note that size of section 0 is always |
1783 | zero, and we rely on this for optional sections. */ | 1800 | zero, and we rely on this for optional sections. */ |
1784 | static struct module *load_module(void __user *umod, | 1801 | static struct module *load_module(void __user *umod, |
@@ -1980,7 +1997,7 @@ static struct module *load_module(void __user *umod, | |||
1980 | layout_sections(mod, hdr, sechdrs, secstrings); | 1997 | layout_sections(mod, hdr, sechdrs, secstrings); |
1981 | 1998 | ||
1982 | /* Do the allocs. */ | 1999 | /* Do the allocs. */ |
1983 | ptr = module_alloc(mod->core_size); | 2000 | ptr = module_alloc_update_bounds(mod->core_size); |
1984 | if (!ptr) { | 2001 | if (!ptr) { |
1985 | err = -ENOMEM; | 2002 | err = -ENOMEM; |
1986 | goto free_percpu; | 2003 | goto free_percpu; |
@@ -1988,7 +2005,7 @@ static struct module *load_module(void __user *umod, | |||
1988 | memset(ptr, 0, mod->core_size); | 2005 | memset(ptr, 0, mod->core_size); |
1989 | mod->module_core = ptr; | 2006 | mod->module_core = ptr; |
1990 | 2007 | ||
1991 | ptr = module_alloc(mod->init_size); | 2008 | ptr = module_alloc_update_bounds(mod->init_size); |
1992 | if (!ptr && mod->init_size) { | 2009 | if (!ptr && mod->init_size) { |
1993 | err = -ENOMEM; | 2010 | err = -ENOMEM; |
1994 | goto free_core; | 2011 | goto free_core; |
@@ -2645,6 +2662,9 @@ struct module *__module_text_address(unsigned long addr) | |||
2645 | { | 2662 | { |
2646 | struct module *mod; | 2663 | struct module *mod; |
2647 | 2664 | ||
2665 | if (addr < module_addr_min || addr > module_addr_max) | ||
2666 | return NULL; | ||
2667 | |||
2648 | list_for_each_entry(mod, &modules, list) | 2668 | list_for_each_entry(mod, &modules, list) |
2649 | if (within(addr, mod->module_init, mod->init_text_size) | 2669 | if (within(addr, mod->module_init, mod->init_text_size) |
2650 | || within(addr, mod->module_core, mod->core_text_size)) | 2670 | || within(addr, mod->module_core, mod->core_text_size)) |