Skip to content

Commit

Permalink
ftrace: Add freeing algorithm to free ftrace_mod_maps
Browse files Browse the repository at this point in the history
The ftrace_mod_map is a descriptor to save module init function names in
case they were traced, and the trace output needs to reference the function
name from the function address. But after the function is unloaded, it
the maps should be freed, as the rest of the function names are as well.

Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
  • Loading branch information
Steven Rostedt (VMware) committed Oct 5, 2017
1 parent aba4b5c commit 6aa6978
Showing 1 changed file with 30 additions and 2 deletions.
32 changes: 30 additions & 2 deletions kernel/trace/ftrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -5683,6 +5683,7 @@ struct ftrace_mod_func {
};

struct ftrace_mod_map {
struct rcu_head rcu;
struct list_head list;
struct module *mod;
unsigned long start_addr;
Expand All @@ -5694,6 +5695,8 @@ struct ftrace_mod_map {

#define next_to_ftrace_page(p) container_of(p, struct ftrace_page, next)

static LIST_HEAD(ftrace_mod_maps);

static int referenced_filters(struct dyn_ftrace *rec)
{
struct ftrace_ops *ops;
Expand Down Expand Up @@ -5747,8 +5750,26 @@ static void clear_mod_from_hashes(struct ftrace_page *pg)
mutex_unlock(&trace_types_lock);
}

static void ftrace_free_mod_map(struct rcu_head *rcu)
{
struct ftrace_mod_map *mod_map = container_of(rcu, struct ftrace_mod_map, rcu);
struct ftrace_mod_func *mod_func;
struct ftrace_mod_func *n;

/* All the contents of mod_map are now not visible to readers */
list_for_each_entry_safe(mod_func, n, &mod_map->funcs, list) {
kfree(mod_func->name);
list_del(&mod_func->list);
kfree(mod_func);
}

kfree(mod_map);
}

void ftrace_release_mod(struct module *mod)
{
struct ftrace_mod_map *mod_map;
struct ftrace_mod_map *n;
struct dyn_ftrace *rec;
struct ftrace_page **last_pg;
struct ftrace_page *tmp_page = NULL;
Expand All @@ -5760,6 +5781,14 @@ void ftrace_release_mod(struct module *mod)
if (ftrace_disabled)
goto out_unlock;

list_for_each_entry_safe(mod_map, n, &ftrace_mod_maps, list) {
if (mod_map->mod == mod) {
list_del_rcu(&mod_map->list);
call_rcu_sched(&mod_map->rcu, ftrace_free_mod_map);
break;
}
}

/*
* Each module has its own ftrace_pages, remove
* them from the list.
Expand Down Expand Up @@ -5914,8 +5943,6 @@ static void save_ftrace_mod_rec(struct ftrace_mod_map *mod_map,
list_add_rcu(&mod_func->list, &mod_map->funcs);
}

static LIST_HEAD(ftrace_mod_maps);

static struct ftrace_mod_map *
allocate_ftrace_mod_map(struct module *mod,
unsigned long start, unsigned long end)
Expand Down Expand Up @@ -5974,6 +6001,7 @@ ftrace_mod_address_lookup(unsigned long addr, unsigned long *size,
struct ftrace_mod_map *mod_map;
const char *ret = NULL;

/* mod_map is freed via call_rcu_sched() */
preempt_disable();
list_for_each_entry_rcu(mod_map, &ftrace_mod_maps, list) {
ret = ftrace_func_address_lookup(mod_map, addr, size, off, sym);
Expand Down

0 comments on commit 6aa6978

Please sign in to comment.