diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 3ea4c9fa8b572b3af332843b5d355e748793a739..12ab1ad5f94f09e406d9a45445978c77ec6c9f4c 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -1576,10 +1576,12 @@ unsigned long ftrace_location_range(unsigned long start, unsigned long end) struct ftrace_page *pg; struct dyn_ftrace *rec; struct dyn_ftrace key; + unsigned long ip = 0; key.ip = start; key.flags = end; /* overload flags, as it is unsigned long */ + rcu_read_lock(); for (pg = ftrace_pages_start; pg; pg = pg->next) { if (pg->index == 0 || end < pg->records[0].ip || @@ -1588,11 +1590,14 @@ unsigned long ftrace_location_range(unsigned long start, unsigned long end) rec = bsearch(&key, pg->records, pg->index, sizeof(struct dyn_ftrace), ftrace_cmp_recs); - if (rec) - return rec->ip; + if (rec) { + ip = rec->ip; + break; + } } + rcu_read_unlock(); - return 0; + return ip; } /** @@ -5682,6 +5687,8 @@ static int ftrace_process_locs(struct module *mod, /* We should have used all pages unless we skipped some */ if (pg_unuse) { WARN_ON(!skipped); + /* Need to synchronize with ftrace_location_range() */ + synchronize_rcu(); ftrace_free_pages(pg_unuse); } return ret; @@ -5836,6 +5843,9 @@ void ftrace_release_mod(struct module *mod) out_unlock: mutex_unlock(&ftrace_lock); + /* Need to synchronize with ftrace_location_range() */ + if (tmp_page) + synchronize_rcu(); for (pg = tmp_page; pg; pg = tmp_page) { /* Needs to be called outside of ftrace_lock */ @@ -6144,6 +6154,7 @@ void ftrace_free_mem(struct module *mod, 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 *tmp_page = NULL; struct ftrace_page *pg; struct dyn_ftrace *rec; struct dyn_ftrace key; @@ -6188,9 +6199,8 @@ void ftrace_free_mem(struct module *mod, void *start_ptr, void *end_ptr) ftrace_update_tot_cnt--; 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->next = tmp_page; + tmp_page = pg; pg = container_of(last_pg, struct ftrace_page, next); if (!(*last_pg)) ftrace_pages = pg; @@ -6207,6 +6217,11 @@ void ftrace_free_mem(struct module *mod, void *start_ptr, void *end_ptr) clear_func_from_hashes(func); kfree(func); } + /* Need to synchronize with ftrace_location_range() */ + if (tmp_page) { + synchronize_rcu(); + ftrace_free_pages(tmp_page); + } } void __init ftrace_free_init_mem(void)