ftrace/alternatives: Introducing *_text_reserved functions
authorMasami Hiramatsu <mhiramat@redhat.com>
Tue, 2 Feb 2010 21:49:11 +0000 (16:49 -0500)
committerIngo Molnar <mingo@elte.hu>
Thu, 4 Feb 2010 08:36:19 +0000 (09:36 +0100)
Introducing *_text_reserved functions for checking the text
address range is partially reserved or not. This patch provides
checking routines for x86 smp alternatives and dynamic ftrace.
Since both functions modify fixed pieces of kernel text, they
should reserve and protect those from other dynamic text
modifier, like kprobes.

This will also be extended when introducing other subsystems
which modify fixed pieces of kernel text. Dynamic text modifiers
should avoid those.

Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: systemtap <systemtap@sources.redhat.com>
Cc: DLE <dle-develop@lists.sourceforge.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: przemyslaw@pawelczyk.it
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Cc: Jim Keniston <jkenisto@us.ibm.com>
Cc: Mathieu Desnoyers <compudj@krystal.dyndns.org>
Cc: Jason Baron <jbaron@redhat.com>
LKML-Reference: <20100202214911.4694.16587.stgit@dhcp-100-2-132.bos.redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
arch/x86/include/asm/alternative.h
arch/x86/kernel/alternative.c
include/linux/ftrace.h
kernel/trace/ftrace.c

index 69b74a7b877f917cd3f0bc9014045a1ea70d9412..ac80b7d70014aded380536cf0e412fb741cd9634 100644 (file)
@@ -65,12 +65,17 @@ extern void alternatives_smp_module_add(struct module *mod, char *name,
                                        void *text, void *text_end);
 extern void alternatives_smp_module_del(struct module *mod);
 extern void alternatives_smp_switch(int smp);
+extern int alternatives_text_reserved(void *start, void *end);
 #else
 static inline void alternatives_smp_module_add(struct module *mod, char *name,
                                               void *locks, void *locks_end,
                                               void *text, void *text_end) {}
 static inline void alternatives_smp_module_del(struct module *mod) {}
 static inline void alternatives_smp_switch(int smp) {}
+static inline int alternatives_text_reserved(void *start, void *end)
+{
+       return 0;
+}
 #endif /* CONFIG_SMP */
 
 /* alternative assembly primitive: */
index de7353c0ce9ca5bbb029e513bd55773a6c2396d5..3c13284ff86d3b19cc21d438497f8403f17c371e 100644 (file)
@@ -390,6 +390,22 @@ void alternatives_smp_switch(int smp)
        mutex_unlock(&smp_alt);
 }
 
+/* Return 1 if the address range is reserved for smp-alternatives */
+int alternatives_text_reserved(void *start, void *end)
+{
+       struct smp_alt_module *mod;
+       u8 **ptr;
+
+       list_for_each_entry(mod, &smp_alt_modules, next) {
+               if (mod->text > end || mod->text_end < start)
+                       continue;
+               for (ptr = mod->locks; ptr < mod->locks_end; ptr++)
+                       if (start <= *ptr && end >= *ptr)
+                               return 1;
+       }
+
+       return 0;
+}
 #endif
 
 #ifdef CONFIG_PARAVIRT
index 0b4f97d24d7f510b243bdd8cd461daa2786eaa19..9d127efed43c9198b4520719d1f5bbb44e5006c4 100644 (file)
@@ -134,6 +134,8 @@ extern void
 unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops);
 extern void unregister_ftrace_function_probe_all(char *glob);
 
+extern int ftrace_text_reserved(void *start, void *end);
+
 enum {
        FTRACE_FL_FREE          = (1 << 0),
        FTRACE_FL_FAILED        = (1 << 1),
@@ -250,6 +252,10 @@ static inline int unregister_ftrace_command(char *cmd_name)
 {
        return -EINVAL;
 }
+static inline int ftrace_text_reserved(void *start, void *end)
+{
+       return 0;
+}
 #endif /* CONFIG_DYNAMIC_FTRACE */
 
 /* totally disable ftrace - can not re-enable after this */
index 1e6640f80454000de4155a81a6c32a2f46816830..3d90661a5f40fb73b37723a399d87e033de8fd01 100644 (file)
@@ -1025,6 +1025,21 @@ static void ftrace_bug(int failed, unsigned long ip)
 }
 
 
+/* Return 1 if the address range is reserved for ftrace */
+int ftrace_text_reserved(void *start, void *end)
+{
+       struct dyn_ftrace *rec;
+       struct ftrace_page *pg;
+
+       do_for_each_ftrace_rec(pg, rec) {
+               if (rec->ip <= (unsigned long)end &&
+                   rec->ip + MCOUNT_INSN_SIZE > (unsigned long)start)
+                       return 1;
+       } while_for_each_ftrace_rec();
+       return 0;
+}
+
+
 static int
 __ftrace_replace_code(struct dyn_ftrace *rec, int enable)
 {