Commit 265c831c authored by Steven Rostedt's avatar Steven Rostedt

ftrace: add do_for_each_ftrace_rec and while_for_each_ftrace_rec

Impact: clean up

To iterate over all the functions that dynamic trace knows about
it requires two for loops. One to iterate over the pages and the
other to iterate over the records within the page.

There are several duplications of these loops in ftrace.c. This
patch creates the macros do_for_each_ftrace_rec and
while_for_each_ftrace_rec to handle this logic, and removes the
duplicate code.

While making this change, I also discovered and fixed a small
bug that one of the iterations should exit the loop after it found the
record it was searching for. This used a break when it should have
used a goto, since there were two loops it needed to break out
from.  No real harm was done by this bug since it would only continue
to search the other records, and the code was in a slow path anyway.
Signed-off-by: default avatarSteven Rostedt <srostedt@redhat.com>
parent 0c75a3ed
...@@ -297,6 +297,19 @@ static struct ftrace_page *ftrace_pages; ...@@ -297,6 +297,19 @@ static struct ftrace_page *ftrace_pages;
static struct dyn_ftrace *ftrace_free_records; static struct dyn_ftrace *ftrace_free_records;
/*
* This is a double for. Do not use 'break' to break out of the loop,
* you must use a goto.
*/
#define do_for_each_ftrace_rec(pg, rec) \
for (pg = ftrace_pages_start; pg; pg = pg->next) { \
int _____i; \
for (_____i = 0; _____i < pg->index; _____i++) { \
rec = &pg->records[_____i];
#define while_for_each_ftrace_rec() \
} \
}
#ifdef CONFIG_KPROBES #ifdef CONFIG_KPROBES
...@@ -341,7 +354,6 @@ void ftrace_release(void *start, unsigned long size) ...@@ -341,7 +354,6 @@ void ftrace_release(void *start, unsigned long size)
struct ftrace_page *pg; struct ftrace_page *pg;
unsigned long s = (unsigned long)start; unsigned long s = (unsigned long)start;
unsigned long e = s + size; unsigned long e = s + size;
int i;
if (ftrace_disabled || !start) if (ftrace_disabled || !start)
return; return;
...@@ -349,14 +361,11 @@ void ftrace_release(void *start, unsigned long size) ...@@ -349,14 +361,11 @@ void ftrace_release(void *start, unsigned long size)
/* should not be called from interrupt context */ /* should not be called from interrupt context */
spin_lock(&ftrace_lock); spin_lock(&ftrace_lock);
for (pg = ftrace_pages_start; pg; pg = pg->next) { do_for_each_ftrace_rec(pg, rec) {
for (i = 0; i < pg->index; i++) {
rec = &pg->records[i];
if ((rec->ip >= s) && (rec->ip < e)) if ((rec->ip >= s) && (rec->ip < e))
ftrace_free_rec(rec); ftrace_free_rec(rec);
} } while_for_each_ftrace_rec();
}
spin_unlock(&ftrace_lock); spin_unlock(&ftrace_lock);
} }
...@@ -523,14 +532,11 @@ __ftrace_replace_code(struct dyn_ftrace *rec, int enable) ...@@ -523,14 +532,11 @@ __ftrace_replace_code(struct dyn_ftrace *rec, int enable)
static void ftrace_replace_code(int enable) static void ftrace_replace_code(int enable)
{ {
int i, failed; int failed;
struct dyn_ftrace *rec; struct dyn_ftrace *rec;
struct ftrace_page *pg; struct ftrace_page *pg;
for (pg = ftrace_pages_start; pg; pg = pg->next) { do_for_each_ftrace_rec(pg, rec) {
for (i = 0; i < pg->index; i++) {
rec = &pg->records[i];
/* /*
* Skip over free records and records that have * Skip over free records and records that have
* failed. * failed.
...@@ -556,8 +562,7 @@ static void ftrace_replace_code(int enable) ...@@ -556,8 +562,7 @@ static void ftrace_replace_code(int enable)
} else } else
ftrace_bug(failed, rec->ip); ftrace_bug(failed, rec->ip);
} }
} } while_for_each_ftrace_rec();
}
} }
static int static int
...@@ -956,22 +961,17 @@ static void ftrace_filter_reset(int enable) ...@@ -956,22 +961,17 @@ static void ftrace_filter_reset(int enable)
struct ftrace_page *pg; struct ftrace_page *pg;
struct dyn_ftrace *rec; struct dyn_ftrace *rec;
unsigned long type = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE; unsigned long type = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE;
unsigned i;
/* should not be called from interrupt context */ /* should not be called from interrupt context */
spin_lock(&ftrace_lock); spin_lock(&ftrace_lock);
if (enable) if (enable)
ftrace_filtered = 0; ftrace_filtered = 0;
pg = ftrace_pages_start; do_for_each_ftrace_rec(pg, rec) {
while (pg) {
for (i = 0; i < pg->index; i++) {
rec = &pg->records[i];
if (rec->flags & FTRACE_FL_FAILED) if (rec->flags & FTRACE_FL_FAILED)
continue; continue;
rec->flags &= ~type; rec->flags &= ~type;
} } while_for_each_ftrace_rec();
pg = pg->next;
}
spin_unlock(&ftrace_lock); spin_unlock(&ftrace_lock);
} }
...@@ -1094,13 +1094,10 @@ ftrace_match(unsigned char *buff, int len, int enable) ...@@ -1094,13 +1094,10 @@ ftrace_match(unsigned char *buff, int len, int enable)
spin_lock(&ftrace_lock); spin_lock(&ftrace_lock);
if (enable) if (enable)
ftrace_filtered = 1; ftrace_filtered = 1;
pg = ftrace_pages_start; do_for_each_ftrace_rec(pg, rec) {
while (pg) {
for (i = 0; i < pg->index; i++) {
int matched = 0; int matched = 0;
char *ptr; char *ptr;
rec = &pg->records[i];
if (rec->flags & FTRACE_FL_FAILED) if (rec->flags & FTRACE_FL_FAILED)
continue; continue;
kallsyms_lookup(rec->ip, NULL, NULL, NULL, str); kallsyms_lookup(rec->ip, NULL, NULL, NULL, str);
...@@ -1129,9 +1126,7 @@ ftrace_match(unsigned char *buff, int len, int enable) ...@@ -1129,9 +1126,7 @@ ftrace_match(unsigned char *buff, int len, int enable)
else else
rec->flags |= flag; rec->flags |= flag;
} }
} } while_for_each_ftrace_rec();
pg = pg->next;
}
spin_unlock(&ftrace_lock); spin_unlock(&ftrace_lock);
} }
...@@ -1452,7 +1447,7 @@ ftrace_set_func(unsigned long *array, int idx, char *buffer) ...@@ -1452,7 +1447,7 @@ ftrace_set_func(unsigned long *array, int idx, char *buffer)
struct dyn_ftrace *rec; struct dyn_ftrace *rec;
struct ftrace_page *pg; struct ftrace_page *pg;
int found = 0; int found = 0;
int i, j; int j;
if (ftrace_disabled) if (ftrace_disabled)
return -ENODEV; return -ENODEV;
...@@ -1460,15 +1455,14 @@ ftrace_set_func(unsigned long *array, int idx, char *buffer) ...@@ -1460,15 +1455,14 @@ ftrace_set_func(unsigned long *array, int idx, char *buffer)
/* should not be called from interrupt context */ /* should not be called from interrupt context */
spin_lock(&ftrace_lock); spin_lock(&ftrace_lock);
for (pg = ftrace_pages_start; pg; pg = pg->next) { do_for_each_ftrace_rec(pg, rec) {
for (i = 0; i < pg->index; i++) {
rec = &pg->records[i];
if (rec->flags & (FTRACE_FL_FAILED | FTRACE_FL_FREE)) if (rec->flags & (FTRACE_FL_FAILED | FTRACE_FL_FREE))
continue; continue;
kallsyms_lookup(rec->ip, NULL, NULL, NULL, str); kallsyms_lookup(rec->ip, NULL, NULL, NULL, str);
if (strcmp(str, buffer) == 0) { if (strcmp(str, buffer) == 0) {
/* Return 1 if we add it to the array */
found = 1; found = 1;
for (j = 0; j < idx; j++) for (j = 0; j < idx; j++)
if (array[j] == rec->ip) { if (array[j] == rec->ip) {
...@@ -1477,10 +1471,10 @@ ftrace_set_func(unsigned long *array, int idx, char *buffer) ...@@ -1477,10 +1471,10 @@ ftrace_set_func(unsigned long *array, int idx, char *buffer)
} }
if (found) if (found)
array[idx] = rec->ip; array[idx] = rec->ip;
break; goto out;
}
}
} }
} while_for_each_ftrace_rec();
out:
spin_unlock(&ftrace_lock); spin_unlock(&ftrace_lock);
return found ? 0 : -EINVAL; return found ? 0 : -EINVAL;
......
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