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>
This commit is contained in:
Родитель
615d0ebbc7
Коммит
2cfa19780d
|
@ -65,12 +65,17 @@ extern void alternatives_smp_module_add(struct module *mod, char *name,
|
||||||
void *text, void *text_end);
|
void *text, void *text_end);
|
||||||
extern void alternatives_smp_module_del(struct module *mod);
|
extern void alternatives_smp_module_del(struct module *mod);
|
||||||
extern void alternatives_smp_switch(int smp);
|
extern void alternatives_smp_switch(int smp);
|
||||||
|
extern int alternatives_text_reserved(void *start, void *end);
|
||||||
#else
|
#else
|
||||||
static inline void alternatives_smp_module_add(struct module *mod, char *name,
|
static inline void alternatives_smp_module_add(struct module *mod, char *name,
|
||||||
void *locks, void *locks_end,
|
void *locks, void *locks_end,
|
||||||
void *text, void *text_end) {}
|
void *text, void *text_end) {}
|
||||||
static inline void alternatives_smp_module_del(struct module *mod) {}
|
static inline void alternatives_smp_module_del(struct module *mod) {}
|
||||||
static inline void alternatives_smp_switch(int smp) {}
|
static inline void alternatives_smp_switch(int smp) {}
|
||||||
|
static inline int alternatives_text_reserved(void *start, void *end)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#endif /* CONFIG_SMP */
|
#endif /* CONFIG_SMP */
|
||||||
|
|
||||||
/* alternative assembly primitive: */
|
/* alternative assembly primitive: */
|
||||||
|
|
|
@ -390,6 +390,22 @@ void alternatives_smp_switch(int smp)
|
||||||
mutex_unlock(&smp_alt);
|
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
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_PARAVIRT
|
#ifdef CONFIG_PARAVIRT
|
||||||
|
|
|
@ -134,6 +134,8 @@ extern void
|
||||||
unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops);
|
unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops);
|
||||||
extern void unregister_ftrace_function_probe_all(char *glob);
|
extern void unregister_ftrace_function_probe_all(char *glob);
|
||||||
|
|
||||||
|
extern int ftrace_text_reserved(void *start, void *end);
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
FTRACE_FL_FREE = (1 << 0),
|
FTRACE_FL_FREE = (1 << 0),
|
||||||
FTRACE_FL_FAILED = (1 << 1),
|
FTRACE_FL_FAILED = (1 << 1),
|
||||||
|
@ -250,6 +252,10 @@ static inline int unregister_ftrace_command(char *cmd_name)
|
||||||
{
|
{
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
static inline int ftrace_text_reserved(void *start, void *end)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#endif /* CONFIG_DYNAMIC_FTRACE */
|
#endif /* CONFIG_DYNAMIC_FTRACE */
|
||||||
|
|
||||||
/* totally disable ftrace - can not re-enable after this */
|
/* totally disable ftrace - can not re-enable after this */
|
||||||
|
|
|
@ -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
|
static int
|
||||||
__ftrace_replace_code(struct dyn_ftrace *rec, int enable)
|
__ftrace_replace_code(struct dyn_ftrace *rec, int enable)
|
||||||
{
|
{
|
||||||
|
|
Загрузка…
Ссылка в новой задаче