aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMasami Hiramatsu <mhiramat@redhat.com>2010-02-02 16:49:11 -0500
committerIngo Molnar <mingo@elte.hu>2010-02-04 03:36:19 -0500
commit2cfa19780d61740f65790c5bae363b759d7c96fa (patch)
treecc7a8277a9f04c1bd613efe03c7d6d16cd18dc96
parent615d0ebbc782b67296e3226c293f520f93f93515 (diff)
ftrace/alternatives: Introducing *_text_reserved functions
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>
-rw-r--r--arch/x86/include/asm/alternative.h5
-rw-r--r--arch/x86/kernel/alternative.c16
-rw-r--r--include/linux/ftrace.h6
-rw-r--r--kernel/trace/ftrace.c15
4 files changed, 42 insertions, 0 deletions
diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h
index 69b74a7b877f..ac80b7d70014 100644
--- a/arch/x86/include/asm/alternative.h
+++ b/arch/x86/include/asm/alternative.h
@@ -65,12 +65,17 @@ extern void alternatives_smp_module_add(struct module *mod, char *name,
65 void *text, void *text_end); 65 void *text, void *text_end);
66extern void alternatives_smp_module_del(struct module *mod); 66extern void alternatives_smp_module_del(struct module *mod);
67extern void alternatives_smp_switch(int smp); 67extern void alternatives_smp_switch(int smp);
68extern int alternatives_text_reserved(void *start, void *end);
68#else 69#else
69static inline void alternatives_smp_module_add(struct module *mod, char *name, 70static inline void alternatives_smp_module_add(struct module *mod, char *name,
70 void *locks, void *locks_end, 71 void *locks, void *locks_end,
71 void *text, void *text_end) {} 72 void *text, void *text_end) {}
72static inline void alternatives_smp_module_del(struct module *mod) {} 73static inline void alternatives_smp_module_del(struct module *mod) {}
73static inline void alternatives_smp_switch(int smp) {} 74static inline void alternatives_smp_switch(int smp) {}
75static inline int alternatives_text_reserved(void *start, void *end)
76{
77 return 0;
78}
74#endif /* CONFIG_SMP */ 79#endif /* CONFIG_SMP */
75 80
76/* alternative assembly primitive: */ 81/* alternative assembly primitive: */
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index de7353c0ce9c..3c13284ff86d 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -390,6 +390,22 @@ void alternatives_smp_switch(int smp)
390 mutex_unlock(&smp_alt); 390 mutex_unlock(&smp_alt);
391} 391}
392 392
393/* Return 1 if the address range is reserved for smp-alternatives */
394int alternatives_text_reserved(void *start, void *end)
395{
396 struct smp_alt_module *mod;
397 u8 **ptr;
398
399 list_for_each_entry(mod, &smp_alt_modules, next) {
400 if (mod->text > end || mod->text_end < start)
401 continue;
402 for (ptr = mod->locks; ptr < mod->locks_end; ptr++)
403 if (start <= *ptr && end >= *ptr)
404 return 1;
405 }
406
407 return 0;
408}
393#endif 409#endif
394 410
395#ifdef CONFIG_PARAVIRT 411#ifdef CONFIG_PARAVIRT
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 0b4f97d24d7f..9d127efed43c 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -134,6 +134,8 @@ extern void
134unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops); 134unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops);
135extern void unregister_ftrace_function_probe_all(char *glob); 135extern void unregister_ftrace_function_probe_all(char *glob);
136 136
137extern int ftrace_text_reserved(void *start, void *end);
138
137enum { 139enum {
138 FTRACE_FL_FREE = (1 << 0), 140 FTRACE_FL_FREE = (1 << 0),
139 FTRACE_FL_FAILED = (1 << 1), 141 FTRACE_FL_FAILED = (1 << 1),
@@ -250,6 +252,10 @@ static inline int unregister_ftrace_command(char *cmd_name)
250{ 252{
251 return -EINVAL; 253 return -EINVAL;
252} 254}
255static inline int ftrace_text_reserved(void *start, void *end)
256{
257 return 0;
258}
253#endif /* CONFIG_DYNAMIC_FTRACE */ 259#endif /* CONFIG_DYNAMIC_FTRACE */
254 260
255/* totally disable ftrace - can not re-enable after this */ 261/* totally disable ftrace - can not re-enable after this */
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 1e6640f80454..3d90661a5f40 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -1025,6 +1025,21 @@ static void ftrace_bug(int failed, unsigned long ip)
1025} 1025}
1026 1026
1027 1027
1028/* Return 1 if the address range is reserved for ftrace */
1029int ftrace_text_reserved(void *start, void *end)
1030{
1031 struct dyn_ftrace *rec;
1032 struct ftrace_page *pg;
1033
1034 do_for_each_ftrace_rec(pg, rec) {
1035 if (rec->ip <= (unsigned long)end &&
1036 rec->ip + MCOUNT_INSN_SIZE > (unsigned long)start)
1037 return 1;
1038 } while_for_each_ftrace_rec();
1039 return 0;
1040}
1041
1042
1028static int 1043static int
1029__ftrace_replace_code(struct dyn_ftrace *rec, int enable) 1044__ftrace_replace_code(struct dyn_ftrace *rec, int enable)
1030{ 1045{