]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
ftrace: remove old pointers to mcount
authorSteven Rostedt <rostedt@goodmis.org>
Fri, 15 Aug 2008 02:47:19 +0000 (22:47 -0400)
committerIngo Molnar <mingo@elte.hu>
Tue, 14 Oct 2008 08:35:12 +0000 (10:35 +0200)
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>
include/linux/ftrace.h
include/linux/init.h
kernel/module.c
kernel/trace/ftrace.c

index 4936489f9ed899fad4bc969436f93c0463c1f325..6b232a2460c0012fae531b09d29985cdef7ab79d 100644 (file)
@@ -165,10 +165,12 @@ ftrace_special(unsigned long arg1, unsigned long arg2, unsigned long arg3) { }
 #ifdef CONFIG_FTRACE_MCOUNT_RECORD
 extern void ftrace_init(void);
 extern void ftrace_init_module(unsigned long *start, unsigned long *end);
+extern void ftrace_release(void *start, unsigned long size);
 #else
 static inline void ftrace_init(void) { }
 static inline void
 ftrace_init_module(unsigned long *start, unsigned long *end) { }
+static inline void ftrace_release(void *start, unsigned long size) { }
 #endif
 
 #endif /* _LINUX_FTRACE_H */
index 93538b696e3d99f2bb30d96b83d3516c66442233..27f61f6b3cb9c0625a0a272fbd3e4518026e765f 100644 (file)
@@ -40,7 +40,7 @@
 
 /* These are for everybody (although not all archs will actually
    discard it in modules) */
-#define __init         __section(.init.text) __cold
+#define __init         __section(.init.text) __cold notrace
 #define __initdata     __section(.init.data)
 #define __initconst    __section(.init.rodata)
 #define __exitdata     __section(.exit.data)
index d753fd9d83ece9803880e6ad4d60184a51d90645..7576c2d9462fc2dc2cadb40d4663512a99d00185 100644 (file)
@@ -1431,6 +1431,9 @@ static void free_module(struct module *mod)
        /* Module unload stuff */
        module_unload_free(mod);
 
+       /* release any pointers to mcount in this module */
+       ftrace_release(mod->module_core, mod->core_size);
+
        /* This may be NULL, but that's OK */
        module_free(mod, mod->module_init);
        kfree(mod->args);
@@ -1839,6 +1842,7 @@ static noinline struct module *load_module(void __user *umod,
        struct module *mod;
        long err = 0;
        void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
+       void *mseg;
        struct exception_table_entry *extable;
        mm_segment_t old_fs;
 
@@ -2190,10 +2194,9 @@ static noinline struct module *load_module(void __user *umod,
 #endif
        }
 
-       if (mcountindex) {
-               void *mseg = (void *)sechdrs[mcountindex].sh_addr;
-               ftrace_init_module(mseg, mseg + sechdrs[mcountindex].sh_size);
-       }
+       /* sechdrs[0].sh_size is always zero */
+       mseg = (void *)sechdrs[mcountindex].sh_addr;
+       ftrace_init_module(mseg, mseg + sechdrs[mcountindex].sh_size);
 
        err = module_finalize(hdr, sechdrs, mod);
        if (err < 0)
@@ -2264,6 +2267,7 @@ static noinline struct module *load_module(void __user *umod,
  cleanup:
        kobject_del(&mod->mkobj.kobj);
        kobject_put(&mod->mkobj.kobj);
+       ftrace_release(mod->module_core, mod->core_size);
  free_unload:
        module_unload_free(mod);
        module_free(mod, mod->module_init);
index 8affb6d00ec1e70c40755984447d4897c04f6c89..eadd0eaea9b6b70449bf7db247f215b096c4bc30 100644 (file)
@@ -294,13 +294,37 @@ static inline void ftrace_del_hash(struct dyn_ftrace *node)
 
 static void ftrace_free_rec(struct dyn_ftrace *rec)
 {
-       /* no locking, only called from kstop_machine */
-
        rec->ip = (unsigned long)ftrace_free_records;
        ftrace_free_records = rec;
        rec->flags |= FTRACE_FL_FREE;
 }
 
+void ftrace_release(void *start, unsigned long size)
+{
+       struct dyn_ftrace *rec;
+       struct ftrace_page *pg;
+       unsigned long s = (unsigned long)start;
+       unsigned long e = s + size;
+       int i;
+
+       if (!start)
+               return;
+
+       /* No interrupt should call this */
+       spin_lock(&ftrace_lock);
+
+       for (pg = ftrace_pages_start; pg; pg = pg->next) {
+               for (i = 0; i < pg->index; i++) {
+                       rec = &pg->records[i];
+
+                       if ((rec->ip >= s) && (rec->ip < e))
+                               ftrace_free_rec(rec);
+               }
+       }
+       spin_unlock(&ftrace_lock);
+
+}
+
 static struct dyn_ftrace *ftrace_alloc_dyn_node(unsigned long ip)
 {
        struct dyn_ftrace *rec;
@@ -1527,7 +1551,9 @@ static int ftrace_convert_nops(unsigned long *start,
        p = start;
        while (p < end) {
                addr = ftrace_call_adjust(*p++);
+               spin_lock(&ftrace_lock);
                ftrace_record_ip(addr);
+               spin_unlock(&ftrace_lock);
                ftrace_shutdown_replenish();
        }
 
@@ -1541,6 +1567,8 @@ static int ftrace_convert_nops(unsigned long *start,
 
 void ftrace_init_module(unsigned long *start, unsigned long *end)
 {
+       if (start == end)
+               return;
        ftrace_convert_nops(start, end);
 }