aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt <rostedt@goodmis.org>2008-08-14 22:47:19 -0400
committerIngo Molnar <mingo@elte.hu>2008-10-14 04:35:12 -0400
commitfed1939c64d2288938fdc1c367d49082da65e195 (patch)
treea4592352d28efcfe82379c71d061b9127e49a115
parent28614889bcb2558a47d02d52394b7fd9795a9547 (diff)
ftrace: remove old pointers to mcount
When a mcount pointer is recorded into a table, it is used to add or remove calls to mcount (replacing them with nops). If the code is removed via removing a module, the pointers still exist. At modifying the code a check is always made to make sure the code being replaced is the code expected. In-other-words, the code being replaced is compared to what it is expected to be before being replaced. There is a very small chance that the code being replaced just happens to look like code that calls mcount (very small since the call to mcount is relative). To remove this chance, this patch adds ftrace_release to allow module unloading to remove the pointers to mcount within the module. Another change for init calls is made to not trace calls marked with __init. The tracing can not be started until after init is done anyway. Signed-off-by: Steven Rostedt <srostedt@redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--include/linux/ftrace.h2
-rw-r--r--include/linux/init.h2
-rw-r--r--kernel/module.c12
-rw-r--r--kernel/trace/ftrace.c32
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
166extern void ftrace_init(void); 166extern void ftrace_init(void);
167extern void ftrace_init_module(unsigned long *start, unsigned long *end); 167extern void ftrace_init_module(unsigned long *start, unsigned long *end);
168extern void ftrace_release(void *start, unsigned long size);
168#else 169#else
169static inline void ftrace_init(void) { } 170static inline void ftrace_init(void) { }
170static inline void 171static inline void
171ftrace_init_module(unsigned long *start, unsigned long *end) { } 172ftrace_init_module(unsigned long *start, unsigned long *end) { }
173static 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
295static void ftrace_free_rec(struct dyn_ftrace *rec) 295static 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
302void 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
304static struct dyn_ftrace *ftrace_alloc_dyn_node(unsigned long ip) 328static 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
1542void ftrace_init_module(unsigned long *start, unsigned long *end) 1568void 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