Commit 42c269c8 authored by Steven Rostedt (VMware)'s avatar Steven Rostedt (VMware)

ftrace: Allow for function tracing to record init functions on boot up

Adding a hook into free_reserve_area() that informs ftrace that boot up init
text is being free, lets ftrace safely remove those init functions from its
records, which keeps ftrace from trying to modify text that no longer
exists.

Note, this still does not allow for tracing .init text of modules, as
modules require different work for freeing its init code.

Link: http://lkml.kernel.org/r/1488502497.7212.24.camel@linux.intel.com

Cc: linux-mm@kvack.org
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: Mel Gorman <mgorman@techsingularity.net>
Cc: Peter Zijlstra <peterz@infradead.org>
Requested-by: default avatarTodd Brandt <todd.e.brandt@linux.intel.com>
Signed-off-by: default avatarSteven Rostedt (VMware) <rostedt@goodmis.org>
parent dbeafd0d
...@@ -146,6 +146,10 @@ struct ftrace_ops_hash { ...@@ -146,6 +146,10 @@ struct ftrace_ops_hash {
struct ftrace_hash *filter_hash; struct ftrace_hash *filter_hash;
struct mutex regex_lock; struct mutex regex_lock;
}; };
void ftrace_free_mem(void *start, void *end);
#else
static inline void ftrace_free_mem(void *start, void *end) { }
#endif #endif
/* /*
...@@ -262,6 +266,7 @@ static inline int ftrace_nr_registered_ops(void) ...@@ -262,6 +266,7 @@ static inline int ftrace_nr_registered_ops(void)
} }
static inline void clear_ftrace_function(void) { } static inline void clear_ftrace_function(void) { }
static inline void ftrace_kill(void) { } static inline void ftrace_kill(void) { }
static inline void ftrace_free_mem(void *start, void *end) { }
#endif /* CONFIG_FUNCTION_TRACER */ #endif /* CONFIG_FUNCTION_TRACER */
#ifdef CONFIG_STACK_TRACER #ifdef CONFIG_STACK_TRACER
......
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
/* These are for everybody (although not all archs will actually /* These are for everybody (although not all archs will actually
discard it in modules) */ discard it in modules) */
#define __init __section(.init.text) __cold notrace __latent_entropy #define __init __section(.init.text) __cold __inittrace __latent_entropy
#define __initdata __section(.init.data) #define __initdata __section(.init.data)
#define __initconst __section(.init.rodata) #define __initconst __section(.init.rodata)
#define __exitdata __section(.exit.data) #define __exitdata __section(.exit.data)
...@@ -68,8 +68,10 @@ ...@@ -68,8 +68,10 @@
#ifdef MODULE #ifdef MODULE
#define __exitused #define __exitused
#define __inittrace notrace
#else #else
#define __exitused __used #define __exitused __used
#define __inittrace
#endif #endif
#define __exit __section(.exit.text) __exitused __cold notrace #define __exit __section(.exit.text) __exitused __cold notrace
......
...@@ -5262,6 +5262,50 @@ void ftrace_module_init(struct module *mod) ...@@ -5262,6 +5262,50 @@ void ftrace_module_init(struct module *mod)
} }
#endif /* CONFIG_MODULES */ #endif /* CONFIG_MODULES */
void ftrace_free_mem(void *start_ptr, void *end_ptr)
{
unsigned long start = (unsigned long)start_ptr;
unsigned long end = (unsigned long)end_ptr;
struct ftrace_page **last_pg = &ftrace_pages_start;
struct ftrace_page *pg;
struct dyn_ftrace *rec;
struct dyn_ftrace key;
int order;
key.ip = start;
key.flags = end; /* overload flags, as it is unsigned long */
mutex_lock(&ftrace_lock);
for (pg = ftrace_pages_start; pg; last_pg = &pg->next, pg = *last_pg) {
if (end < pg->records[0].ip ||
start >= (pg->records[pg->index - 1].ip + MCOUNT_INSN_SIZE))
continue;
again:
rec = bsearch(&key, pg->records, pg->index,
sizeof(struct dyn_ftrace),
ftrace_cmp_recs);
if (!rec)
continue;
pg->index--;
if (!pg->index) {
*last_pg = pg->next;
order = get_count_order(pg->size / ENTRIES_PER_PAGE);
free_pages((unsigned long)pg->records, order);
kfree(pg);
pg = container_of(last_pg, struct ftrace_page, next);
if (!(*last_pg))
ftrace_pages = pg;
continue;
}
memmove(rec, rec + 1,
(pg->index - (rec - pg->records)) * sizeof(*rec));
/* More than one function may be in this block */
goto again;
}
mutex_unlock(&ftrace_lock);
}
void __init ftrace_init(void) void __init ftrace_init(void)
{ {
extern unsigned long __start_mcount_loc[]; extern unsigned long __start_mcount_loc[];
......
...@@ -65,6 +65,7 @@ ...@@ -65,6 +65,7 @@
#include <linux/page_owner.h> #include <linux/page_owner.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/memcontrol.h> #include <linux/memcontrol.h>
#include <linux/ftrace.h>
#include <asm/sections.h> #include <asm/sections.h>
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
...@@ -6605,6 +6606,9 @@ unsigned long free_reserved_area(void *start, void *end, int poison, char *s) ...@@ -6605,6 +6606,9 @@ unsigned long free_reserved_area(void *start, void *end, int poison, char *s)
void *pos; void *pos;
unsigned long pages = 0; unsigned long pages = 0;
/* This may be .init text, inform ftrace to remove it */
ftrace_free_mem(start, end);
start = (void *)PAGE_ALIGN((unsigned long)start); start = (void *)PAGE_ALIGN((unsigned long)start);
end = (void *)((unsigned long)end & PAGE_MASK); end = (void *)((unsigned long)end & PAGE_MASK);
for (pos = start; pos < end; pos += PAGE_SIZE, pages++) { for (pos = start; pos < end; pos += PAGE_SIZE, pages++) {
......
...@@ -412,6 +412,7 @@ static int ...@@ -412,6 +412,7 @@ static int
is_mcounted_section_name(char const *const txtname) is_mcounted_section_name(char const *const txtname)
{ {
return strcmp(".text", txtname) == 0 || return strcmp(".text", txtname) == 0 ||
strcmp(".init.text", txtname) == 0 ||
strcmp(".ref.text", txtname) == 0 || strcmp(".ref.text", txtname) == 0 ||
strcmp(".sched.text", txtname) == 0 || strcmp(".sched.text", txtname) == 0 ||
strcmp(".spinlock.text", txtname) == 0 || strcmp(".spinlock.text", txtname) == 0 ||
......
...@@ -130,6 +130,7 @@ if ($inputfile =~ m,kernel/trace/ftrace\.o$,) { ...@@ -130,6 +130,7 @@ if ($inputfile =~ m,kernel/trace/ftrace\.o$,) {
# Acceptable sections to record. # Acceptable sections to record.
my %text_sections = ( my %text_sections = (
".text" => 1, ".text" => 1,
".init.text" => 1,
".ref.text" => 1, ".ref.text" => 1,
".sched.text" => 1, ".sched.text" => 1,
".spinlock.text" => 1, ".spinlock.text" => 1,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment