aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Zijlstra <peterz@infradead.org>2015-05-26 21:39:38 -0400
committerRusty Russell <rusty@rustcorp.com.au>2015-05-27 22:02:09 -0400
commit4f666546d047752c17265f4641cc9470c1cbaed4 (patch)
tree119d2a7a325eccf18eedbc309a0cad7190c0a969
parentb7df4d1b23bfca830f1076412d21524686c5a441 (diff)
module: Rework module_addr_{min,max}
__module_address() does an initial bound check before doing the {list/tree} iteration to find the actual module. The bound variables are nowhere near the mod_tree cacheline, in fact they're nowhere near one another. module_addr_min lives in .data while module_addr_max lives in .bss (smarty pants GCC thinks the explicit 0 assignment is a mistake). Rectify this by moving the two variables into a structure together with the latch_tree_root to guarantee they all share the same cacheline and avoid hitting two extra cachelines for the lookup. While reworking the bounds code, move the bound update from allocation to insertion time, this avoids updating the bounds for a few error paths. Cc: Rusty Russell <rusty@rustcorp.com.au> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
-rw-r--r--kernel/module.c80
1 files changed, 52 insertions, 28 deletions
diff --git a/kernel/module.c b/kernel/module.c
index 293dfaf4ce52..c8da2a59ebf7 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -170,7 +170,26 @@ static const struct latch_tree_ops mod_tree_ops = {
170 .comp = mod_tree_comp, 170 .comp = mod_tree_comp,
171}; 171};
172 172
173static struct latch_tree_root mod_tree __cacheline_aligned; 173static struct mod_tree_root {
174 struct latch_tree_root root;
175 unsigned long addr_min;
176 unsigned long addr_max;
177} mod_tree __cacheline_aligned = {
178 .addr_min = -1UL,
179};
180
181#define module_addr_min mod_tree.addr_min
182#define module_addr_max mod_tree.addr_max
183
184static noinline void __mod_tree_insert(struct mod_tree_node *node)
185{
186 latch_tree_insert(&node->node, &mod_tree.root, &mod_tree_ops);
187}
188
189static void __mod_tree_remove(struct mod_tree_node *node)
190{
191 latch_tree_erase(&node->node, &mod_tree.root, &mod_tree_ops);
192}
174 193
175/* 194/*
176 * These modifications: insert, remove_init and remove; are serialized by the 195 * These modifications: insert, remove_init and remove; are serialized by the
@@ -181,20 +200,20 @@ static void mod_tree_insert(struct module *mod)
181 mod->mtn_core.mod = mod; 200 mod->mtn_core.mod = mod;
182 mod->mtn_init.mod = mod; 201 mod->mtn_init.mod = mod;
183 202
184 latch_tree_insert(&mod->mtn_core.node, &mod_tree, &mod_tree_ops); 203 __mod_tree_insert(&mod->mtn_core);
185 if (mod->init_size) 204 if (mod->init_size)
186 latch_tree_insert(&mod->mtn_init.node, &mod_tree, &mod_tree_ops); 205 __mod_tree_insert(&mod->mtn_init);
187} 206}
188 207
189static void mod_tree_remove_init(struct module *mod) 208static void mod_tree_remove_init(struct module *mod)
190{ 209{
191 if (mod->init_size) 210 if (mod->init_size)
192 latch_tree_erase(&mod->mtn_init.node, &mod_tree, &mod_tree_ops); 211 __mod_tree_remove(&mod->mtn_init);
193} 212}
194 213
195static void mod_tree_remove(struct module *mod) 214static void mod_tree_remove(struct module *mod)
196{ 215{
197 latch_tree_erase(&mod->mtn_core.node, &mod_tree, &mod_tree_ops); 216 __mod_tree_remove(&mod->mtn_core);
198 mod_tree_remove_init(mod); 217 mod_tree_remove_init(mod);
199} 218}
200 219
@@ -202,7 +221,7 @@ static struct module *mod_find(unsigned long addr)
202{ 221{
203 struct latch_tree_node *ltn; 222 struct latch_tree_node *ltn;
204 223
205 ltn = latch_tree_find((void *)addr, &mod_tree, &mod_tree_ops); 224 ltn = latch_tree_find((void *)addr, &mod_tree.root, &mod_tree_ops);
206 if (!ltn) 225 if (!ltn)
207 return NULL; 226 return NULL;
208 227
@@ -211,6 +230,8 @@ static struct module *mod_find(unsigned long addr)
211 230
212#else /* MODULES_TREE_LOOKUP */ 231#else /* MODULES_TREE_LOOKUP */
213 232
233static unsigned long module_addr_min = -1UL, module_addr_max = 0;
234
214static void mod_tree_insert(struct module *mod) { } 235static void mod_tree_insert(struct module *mod) { }
215static void mod_tree_remove_init(struct module *mod) { } 236static void mod_tree_remove_init(struct module *mod) { }
216static void mod_tree_remove(struct module *mod) { } 237static void mod_tree_remove(struct module *mod) { }
@@ -229,6 +250,28 @@ static struct module *mod_find(unsigned long addr)
229 250
230#endif /* MODULES_TREE_LOOKUP */ 251#endif /* MODULES_TREE_LOOKUP */
231 252
253/*
254 * Bounds of module text, for speeding up __module_address.
255 * Protected by module_mutex.
256 */
257static void __mod_update_bounds(void *base, unsigned int size)
258{
259 unsigned long min = (unsigned long)base;
260 unsigned long max = min + size;
261
262 if (min < module_addr_min)
263 module_addr_min = min;
264 if (max > module_addr_max)
265 module_addr_max = max;
266}
267
268static void mod_update_bounds(struct module *mod)
269{
270 __mod_update_bounds(mod->module_core, mod->core_size);
271 if (mod->init_size)
272 __mod_update_bounds(mod->module_init, mod->init_size);
273}
274
232#ifdef CONFIG_KGDB_KDB 275#ifdef CONFIG_KGDB_KDB
233struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */ 276struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */
234#endif /* CONFIG_KGDB_KDB */ 277#endif /* CONFIG_KGDB_KDB */
@@ -297,10 +340,6 @@ static DECLARE_WAIT_QUEUE_HEAD(module_wq);
297 340
298static BLOCKING_NOTIFIER_HEAD(module_notify_list); 341static BLOCKING_NOTIFIER_HEAD(module_notify_list);
299 342
300/* Bounds of module allocation, for speeding __module_address.
301 * Protected by module_mutex. */
302static unsigned long module_addr_min = -1UL, module_addr_max = 0;
303
304int register_module_notifier(struct notifier_block *nb) 343int register_module_notifier(struct notifier_block *nb)
305{ 344{
306 return blocking_notifier_chain_register(&module_notify_list, nb); 345 return blocking_notifier_chain_register(&module_notify_list, nb);
@@ -2539,22 +2578,6 @@ void * __weak module_alloc(unsigned long size)
2539 return vmalloc_exec(size); 2578 return vmalloc_exec(size);
2540} 2579}
2541 2580
2542static void *module_alloc_update_bounds(unsigned long size)
2543{
2544 void *ret = module_alloc(size);
2545
2546 if (ret) {
2547 mutex_lock(&module_mutex);
2548 /* Update module bounds. */
2549 if ((unsigned long)ret < module_addr_min)
2550 module_addr_min = (unsigned long)ret;
2551 if ((unsigned long)ret + size > module_addr_max)
2552 module_addr_max = (unsigned long)ret + size;
2553 mutex_unlock(&module_mutex);
2554 }
2555 return ret;
2556}
2557
2558#ifdef CONFIG_DEBUG_KMEMLEAK 2581#ifdef CONFIG_DEBUG_KMEMLEAK
2559static void kmemleak_load_module(const struct module *mod, 2582static void kmemleak_load_module(const struct module *mod,
2560 const struct load_info *info) 2583 const struct load_info *info)
@@ -2960,7 +2983,7 @@ static int move_module(struct module *mod, struct load_info *info)
2960 void *ptr; 2983 void *ptr;
2961 2984
2962 /* Do the allocs. */ 2985 /* Do the allocs. */
2963 ptr = module_alloc_update_bounds(mod->core_size); 2986 ptr = module_alloc(mod->core_size);
2964 /* 2987 /*
2965 * The pointer to this block is stored in the module structure 2988 * The pointer to this block is stored in the module structure
2966 * which is inside the block. Just mark it as not being a 2989 * which is inside the block. Just mark it as not being a
@@ -2974,7 +2997,7 @@ static int move_module(struct module *mod, struct load_info *info)
2974 mod->module_core = ptr; 2997 mod->module_core = ptr;
2975 2998
2976 if (mod->init_size) { 2999 if (mod->init_size) {
2977 ptr = module_alloc_update_bounds(mod->init_size); 3000 ptr = module_alloc(mod->init_size);
2978 /* 3001 /*
2979 * The pointer to this block is stored in the module structure 3002 * The pointer to this block is stored in the module structure
2980 * which is inside the block. This block doesn't need to be 3003 * which is inside the block. This block doesn't need to be
@@ -3344,6 +3367,7 @@ again:
3344 err = -EEXIST; 3367 err = -EEXIST;
3345 goto out; 3368 goto out;
3346 } 3369 }
3370 mod_update_bounds(mod);
3347 list_add_rcu(&mod->list, &modules); 3371 list_add_rcu(&mod->list, &modules);
3348 mod_tree_insert(mod); 3372 mod_tree_insert(mod);
3349 err = 0; 3373 err = 0;