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)) |
