diff options
-rw-r--r-- | include/linux/ftrace.h | 2 | ||||
-rw-r--r-- | include/linux/init.h | 2 | ||||
-rw-r--r-- | kernel/module.c | 12 | ||||
-rw-r--r-- | kernel/trace/ftrace.c | 32 |
4 files changed, 41 insertions, 7 deletions
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index 4936489f9ed8..6b232a2460c0 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h | |||
@@ -165,10 +165,12 @@ ftrace_special(unsigned long arg1, unsigned long arg2, unsigned long arg3) { } | |||
165 | #ifdef CONFIG_FTRACE_MCOUNT_RECORD | 165 | #ifdef CONFIG_FTRACE_MCOUNT_RECORD |
166 | extern void ftrace_init(void); | 166 | extern void ftrace_init(void); |
167 | extern void ftrace_init_module(unsigned long *start, unsigned long *end); | 167 | extern void ftrace_init_module(unsigned long *start, unsigned long *end); |
168 | extern void ftrace_release(void *start, unsigned long size); | ||
168 | #else | 169 | #else |
169 | static inline void ftrace_init(void) { } | 170 | static inline void ftrace_init(void) { } |
170 | static inline void | 171 | static inline void |
171 | ftrace_init_module(unsigned long *start, unsigned long *end) { } | 172 | ftrace_init_module(unsigned long *start, unsigned long *end) { } |
173 | static inline void ftrace_release(void *start, unsigned long size) { } | ||
172 | #endif | 174 | #endif |
173 | 175 | ||
174 | #endif /* _LINUX_FTRACE_H */ | 176 | #endif /* _LINUX_FTRACE_H */ |
diff --git a/include/linux/init.h b/include/linux/init.h index 93538b696e3d..27f61f6b3cb9 100644 --- a/include/linux/init.h +++ b/include/linux/init.h | |||
@@ -40,7 +40,7 @@ | |||
40 | 40 | ||
41 | /* These are for everybody (although not all archs will actually | 41 | /* These are for everybody (although not all archs will actually |
42 | discard it in modules) */ | 42 | discard it in modules) */ |
43 | #define __init __section(.init.text) __cold | 43 | #define __init __section(.init.text) __cold notrace |
44 | #define __initdata __section(.init.data) | 44 | #define __initdata __section(.init.data) |
45 | #define __initconst __section(.init.rodata) | 45 | #define __initconst __section(.init.rodata) |
46 | #define __exitdata __section(.exit.data) | 46 | #define __exitdata __section(.exit.data) |
diff --git a/kernel/module.c b/kernel/module.c index d753fd9d83ec..7576c2d9462f 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -1431,6 +1431,9 @@ static void free_module(struct module *mod) | |||
1431 | /* Module unload stuff */ | 1431 | /* Module unload stuff */ |
1432 | module_unload_free(mod); | 1432 | module_unload_free(mod); |
1433 | 1433 | ||
1434 | /* release any pointers to mcount in this module */ | ||
1435 | ftrace_release(mod->module_core, mod->core_size); | ||
1436 | |||
1434 | /* This may be NULL, but that's OK */ | 1437 | /* This may be NULL, but that's OK */ |
1435 | module_free(mod, mod->module_init); | 1438 | module_free(mod, mod->module_init); |
1436 | kfree(mod->args); | 1439 | kfree(mod->args); |
@@ -1839,6 +1842,7 @@ static noinline struct module *load_module(void __user *umod, | |||
1839 | struct module *mod; | 1842 | struct module *mod; |
1840 | long err = 0; | 1843 | long err = 0; |
1841 | void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */ | 1844 | void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */ |
1845 | void *mseg; | ||
1842 | struct exception_table_entry *extable; | 1846 | struct exception_table_entry *extable; |
1843 | mm_segment_t old_fs; | 1847 | mm_segment_t old_fs; |
1844 | 1848 | ||
@@ -2190,10 +2194,9 @@ static noinline struct module *load_module(void __user *umod, | |||
2190 | #endif | 2194 | #endif |
2191 | } | 2195 | } |
2192 | 2196 | ||
2193 | if (mcountindex) { | 2197 | /* sechdrs[0].sh_size is always zero */ |
2194 | void *mseg = (void *)sechdrs[mcountindex].sh_addr; | 2198 | mseg = (void *)sechdrs[mcountindex].sh_addr; |
2195 | ftrace_init_module(mseg, mseg + sechdrs[mcountindex].sh_size); | 2199 | ftrace_init_module(mseg, mseg + sechdrs[mcountindex].sh_size); |
2196 | } | ||
2197 | 2200 | ||
2198 | err = module_finalize(hdr, sechdrs, mod); | 2201 | err = module_finalize(hdr, sechdrs, mod); |
2199 | if (err < 0) | 2202 | if (err < 0) |
@@ -2264,6 +2267,7 @@ static noinline struct module *load_module(void __user *umod, | |||
2264 | cleanup: | 2267 | cleanup: |
2265 | kobject_del(&mod->mkobj.kobj); | 2268 | kobject_del(&mod->mkobj.kobj); |
2266 | kobject_put(&mod->mkobj.kobj); | 2269 | kobject_put(&mod->mkobj.kobj); |
2270 | ftrace_release(mod->module_core, mod->core_size); | ||
2267 | free_unload: | 2271 | free_unload: |
2268 | module_unload_free(mod); | 2272 | module_unload_free(mod); |
2269 | module_free(mod, mod->module_init); | 2273 | module_free(mod, mod->module_init); |
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 8affb6d00ec1..eadd0eaea9b6 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -294,13 +294,37 @@ static inline void ftrace_del_hash(struct dyn_ftrace *node) | |||
294 | 294 | ||
295 | static void ftrace_free_rec(struct dyn_ftrace *rec) | 295 | static void ftrace_free_rec(struct dyn_ftrace *rec) |
296 | { | 296 | { |
297 | /* no locking, only called from kstop_machine */ | ||
298 | |||
299 | rec->ip = (unsigned long)ftrace_free_records; | 297 | rec->ip = (unsigned long)ftrace_free_records; |
300 | ftrace_free_records = rec; | 298 | ftrace_free_records = rec; |
301 | rec->flags |= FTRACE_FL_FREE; | 299 | rec->flags |= FTRACE_FL_FREE; |
302 | } | 300 | } |
303 | 301 | ||
302 | void ftrace_release(void *start, unsigned long size) | ||
303 | { | ||
304 | struct dyn_ftrace *rec; | ||
305 | struct ftrace_page *pg; | ||
306 | unsigned long s = (unsigned long)start; | ||
307 | unsigned long e = s + size; | ||
308 | int i; | ||
309 | |||
310 | if (!start) | ||
311 | return; | ||
312 | |||
313 | /* No interrupt should call this */ | ||
314 | spin_lock(&ftrace_lock); | ||
315 | |||
316 | for (pg = ftrace_pages_start; pg; pg = pg->next) { | ||
317 | for (i = 0; i < pg->index; i++) { | ||
318 | rec = &pg->records[i]; | ||
319 | |||
320 | if ((rec->ip >= s) && (rec->ip < e)) | ||
321 | ftrace_free_rec(rec); | ||
322 | } | ||
323 | } | ||
324 | spin_unlock(&ftrace_lock); | ||
325 | |||
326 | } | ||
327 | |||
304 | static struct dyn_ftrace *ftrace_alloc_dyn_node(unsigned long ip) | 328 | static struct dyn_ftrace *ftrace_alloc_dyn_node(unsigned long ip) |
305 | { | 329 | { |
306 | struct dyn_ftrace *rec; | 330 | struct dyn_ftrace *rec; |
@@ -1527,7 +1551,9 @@ static int ftrace_convert_nops(unsigned long *start, | |||
1527 | p = start; | 1551 | p = start; |
1528 | while (p < end) { | 1552 | while (p < end) { |
1529 | addr = ftrace_call_adjust(*p++); | 1553 | addr = ftrace_call_adjust(*p++); |
1554 | spin_lock(&ftrace_lock); | ||
1530 | ftrace_record_ip(addr); | 1555 | ftrace_record_ip(addr); |
1556 | spin_unlock(&ftrace_lock); | ||
1531 | ftrace_shutdown_replenish(); | 1557 | ftrace_shutdown_replenish(); |
1532 | } | 1558 | } |
1533 | 1559 | ||
@@ -1541,6 +1567,8 @@ static int ftrace_convert_nops(unsigned long *start, | |||
1541 | 1567 | ||
1542 | void ftrace_init_module(unsigned long *start, unsigned long *end) | 1568 | void ftrace_init_module(unsigned long *start, unsigned long *end) |
1543 | { | 1569 | { |
1570 | if (start == end) | ||
1571 | return; | ||
1544 | ftrace_convert_nops(start, end); | 1572 | ftrace_convert_nops(start, end); |
1545 | } | 1573 | } |
1546 | 1574 | ||