From: Steven Rostedt <rostedt@goodmis.org>
To: linux-kernel@vger.kernel.org
Cc: Ingo Molnar <mingo@elte.hu>,
Andrew Morton <akpm@linux-foundation.org>,
Thomas Gleixner <tglx@linutronix.de>,
Frederic Weisbecker <fweisbec@gmail.com>,
Mathieu Desnoyers <mathieu.desnoyers@efficios.com>,
Lai Jiangshan <laijs@cn.fujitsu.com>,
Li Zefan <lizf@cn.fujitsu.com>, Jiri Olsa <jolsa@redhat.com>,
David Sharp <dhsharp@google.com>,
Vaibhav Nagarnaik <vnagarnaik@google.com>,
Michael Rubin <mrubin@google.com>
Subject: [RFC][PATCH 01/13] ftrace: Replace FTRACE_FL_NOTRACE flag with a hash of ignored functions
Date: Fri, 06 May 2011 11:26:25 -0400 [thread overview]
Message-ID: <20110506154739.344597908@goodmis.org> (raw)
In-Reply-To: 20110506152624.776982312@goodmis.org
[-- Attachment #1: 0001-ftrace-Replace-FTRACE_FL_NOTRACE-flag-with-a-hash-of.patch --]
[-- Type: text/plain, Size: 7801 bytes --]
From: Steven Rostedt <srostedt@redhat.com>
To prepare for the accounting system that will allow multiple users of
the function tracer, having the FTRACE_FL_NOTRACE as a flag in the
dyn_trace record does not make sense.
All ftrace_ops will soon have a hash of functions they should trace
and not trace. By making a global hash of functions not to trace makes
this easier for the transition.
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
include/linux/ftrace.h | 1 -
kernel/trace/ftrace.c | 176 +++++++++++++++++++++++++++++++++++++++++-------
2 files changed, 150 insertions(+), 27 deletions(-)
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 3204744..fe0a90a 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -149,7 +149,6 @@ enum {
FTRACE_FL_FREE = (1 << 0),
FTRACE_FL_FILTER = (1 << 1),
FTRACE_FL_ENABLED = (1 << 2),
- FTRACE_FL_NOTRACE = (1 << 3),
};
struct dyn_ftrace {
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index d340634..04c002a 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -57,6 +57,7 @@
/* hash bits for specific function selection */
#define FTRACE_HASH_BITS 7
#define FTRACE_FUNC_HASHSIZE (1 << FTRACE_HASH_BITS)
+#define FTRACE_HASH_MAX_BITS 10
/* ftrace_enabled is a method to turn ftrace on or off */
int ftrace_enabled __read_mostly;
@@ -865,6 +866,22 @@ enum {
FTRACE_START_FUNC_RET = (1 << 3),
FTRACE_STOP_FUNC_RET = (1 << 4),
};
+struct ftrace_func_entry {
+ struct hlist_node hlist;
+ unsigned long ip;
+};
+
+struct ftrace_hash {
+ unsigned long size_bits;
+ struct hlist_head *buckets;
+ unsigned long count;
+};
+
+static struct hlist_head notrace_buckets[1 << FTRACE_HASH_MAX_BITS];
+static struct ftrace_hash notrace_hash = {
+ .size_bits = FTRACE_HASH_MAX_BITS,
+ .buckets = notrace_buckets,
+};
static int ftrace_filtered;
@@ -889,6 +906,79 @@ static struct ftrace_page *ftrace_pages;
static struct dyn_ftrace *ftrace_free_records;
+static struct ftrace_func_entry *
+ftrace_lookup_ip(struct ftrace_hash *hash, unsigned long ip)
+{
+ unsigned long key;
+ struct ftrace_func_entry *entry;
+ struct hlist_head *hhd;
+ struct hlist_node *n;
+
+ if (!hash->count)
+ return NULL;
+
+ if (hash->size_bits > 0)
+ key = hash_long(ip, hash->size_bits);
+ else
+ key = 0;
+
+ hhd = &hash->buckets[key];
+
+ hlist_for_each_entry_rcu(entry, n, hhd, hlist) {
+ if (entry->ip == ip)
+ return entry;
+ }
+ return NULL;
+}
+
+static int add_hash_entry(struct ftrace_hash *hash, unsigned long ip)
+{
+ struct ftrace_func_entry *entry;
+ struct hlist_head *hhd;
+ unsigned long key;
+
+ entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+
+ if (hash->size_bits)
+ key = hash_long(ip, hash->size_bits);
+ else
+ key = 0;
+
+ entry->ip = ip;
+ hhd = &hash->buckets[key];
+ hlist_add_head(&entry->hlist, hhd);
+ hash->count++;
+
+ return 0;
+}
+
+static void
+remove_hash_entry(struct ftrace_hash *hash,
+ struct ftrace_func_entry *entry)
+{
+ hlist_del(&entry->hlist);
+ kfree(entry);
+ hash->count--;
+}
+
+static void ftrace_hash_clear(struct ftrace_hash *hash)
+{
+ struct hlist_head *hhd;
+ struct hlist_node *tp, *tn;
+ struct ftrace_func_entry *entry;
+ int size = 1 << hash->size_bits;
+ int i;
+
+ for (i = 0; i < size; i++) {
+ hhd = &hash->buckets[i];
+ hlist_for_each_entry_safe(entry, tp, tn, hhd, hlist)
+ remove_hash_entry(hash, entry);
+ }
+ FTRACE_WARN_ON(hash->count);
+}
+
/*
* This is a double for. Do not use 'break' to break out of the loop,
* you must use a goto.
@@ -1032,7 +1122,7 @@ __ftrace_replace_code(struct dyn_ftrace *rec, int enable)
* If we want to enable it and filtering is on, enable it only if
* it's filtered
*/
- if (enable && !(rec->flags & FTRACE_FL_NOTRACE)) {
+ if (enable && !ftrace_lookup_ip(¬race_hash, rec->ip)) {
if (!ftrace_filtered || (rec->flags & FTRACE_FL_FILTER))
flag = FTRACE_FL_ENABLED;
}
@@ -1465,7 +1555,7 @@ t_next(struct seq_file *m, void *v, loff_t *pos)
!(rec->flags & FTRACE_FL_FILTER)) ||
((iter->flags & FTRACE_ITER_NOTRACE) &&
- !(rec->flags & FTRACE_FL_NOTRACE))) {
+ !ftrace_lookup_ip(¬race_hash, rec->ip))) {
rec = NULL;
goto retry;
}
@@ -1609,14 +1699,15 @@ static void ftrace_filter_reset(int enable)
{
struct ftrace_page *pg;
struct dyn_ftrace *rec;
- unsigned long type = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE;
mutex_lock(&ftrace_lock);
- if (enable)
+ if (enable) {
ftrace_filtered = 0;
- do_for_each_ftrace_rec(pg, rec) {
- rec->flags &= ~type;
- } while_for_each_ftrace_rec();
+ do_for_each_ftrace_rec(pg, rec) {
+ rec->flags &= ~FTRACE_FL_FILTER;
+ } while_for_each_ftrace_rec();
+ } else
+ ftrace_hash_clear(¬race_hash);
mutex_unlock(&ftrace_lock);
}
@@ -1716,13 +1807,36 @@ static int ftrace_match(char *str, char *regex, int len, int type)
return matched;
}
-static void
-update_record(struct dyn_ftrace *rec, unsigned long flag, int not)
+static int
+update_record(struct dyn_ftrace *rec, int enable, int not)
{
- if (not)
- rec->flags &= ~flag;
- else
- rec->flags |= flag;
+ struct ftrace_func_entry *entry;
+ struct ftrace_hash *hash = ¬race_hash;
+ int ret = 0;
+
+ if (enable) {
+ if (not)
+ rec->flags &= ~FTRACE_FL_FILTER;
+ else
+ rec->flags |= FTRACE_FL_FILTER;
+ } else {
+ if (not) {
+ /* Do nothing if it doesn't exist */
+ entry = ftrace_lookup_ip(hash, rec->ip);
+ if (!entry)
+ return 0;
+
+ remove_hash_entry(hash, entry);
+ } else {
+ /* Do nothing if it exists */
+ entry = ftrace_lookup_ip(hash, rec->ip);
+ if (entry)
+ return 0;
+
+ ret = add_hash_entry(hash, rec->ip);
+ }
+ }
+ return ret;
}
static int
@@ -1754,16 +1868,14 @@ static int match_records(char *buff, int len, char *mod, int enable, int not)
struct dyn_ftrace *rec;
int type = MATCH_FULL;
char *search = buff;
- unsigned long flag;
int found = 0;
+ int ret;
if (len) {
type = filter_parse_regex(buff, len, &search, ¬);
search_len = strlen(search);
}
- flag = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE;
-
mutex_lock(&ftrace_lock);
if (unlikely(ftrace_disabled))
@@ -1772,7 +1884,11 @@ static int match_records(char *buff, int len, char *mod, int enable, int not)
do_for_each_ftrace_rec(pg, rec) {
if (ftrace_match_record(rec, mod, search, search_len, type)) {
- update_record(rec, flag, not);
+ ret = update_record(rec, enable, not);
+ if (ret < 0) {
+ found = ret;
+ goto out_unlock;
+ }
found = 1;
}
/*
@@ -1821,6 +1937,7 @@ static int
ftrace_mod_callback(char *func, char *cmd, char *param, int enable)
{
char *mod;
+ int ret = -EINVAL;
/*
* cmd == 'mod' because we only registered this func
@@ -1832,15 +1949,19 @@ ftrace_mod_callback(char *func, char *cmd, char *param, int enable)
/* we must have a module name */
if (!param)
- return -EINVAL;
+ return ret;
mod = strsep(¶m, ":");
if (!strlen(mod))
- return -EINVAL;
+ return ret;
- if (ftrace_match_module_records(func, mod, enable))
- return 0;
- return -EINVAL;
+ ret = ftrace_match_module_records(func, mod, enable);
+ if (!ret)
+ ret = -EINVAL;
+ if (ret < 0)
+ return ret;
+
+ return 0;
}
static struct ftrace_func_command ftrace_mod_cmd = {
@@ -2132,14 +2253,17 @@ static int ftrace_process_regex(char *buff, int len, int enable)
{
char *func, *command, *next = buff;
struct ftrace_func_command *p;
- int ret = -EINVAL;
+ int ret;
func = strsep(&next, ":");
if (!next) {
- if (ftrace_match_records(func, len, enable))
- return 0;
- return ret;
+ ret = ftrace_match_records(func, len, enable);
+ if (!ret)
+ ret = -EINVAL;
+ if (ret < 0)
+ return ret;
+ return 0;
}
/* command found */
--
1.7.2.3
next prev parent reply other threads:[~2011-05-06 15:47 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-05-06 15:26 [RFC][PATCH 00/13] ftrace: Allow multiple users to pick and choose functions to trace Steven Rostedt
2011-05-06 15:26 ` Steven Rostedt [this message]
2011-05-06 15:26 ` [RFC][PATCH 02/13] ftrace: Use hash instead for FTRACE_FL_FILTER Steven Rostedt
2011-05-06 15:26 ` [RFC][PATCH 03/13] ftrace: Create a global_ops to hold the filter and notrace hashes Steven Rostedt
2011-05-06 15:26 ` [RFC][PATCH 04/13] ftrace: Separate hash allocation and assignment Steven Rostedt
2011-05-06 15:26 ` [RFC][PATCH 05/13] ftrace: Use counters to enable functions to trace Steven Rostedt
2011-05-06 15:26 ` [RFC][PATCH 06/13] ftrace: Add enabled_functions file Steven Rostedt
2011-05-06 15:26 ` [RFC][PATCH 07/13] ftrace: Add ops parameter to ftrace_startup/shutdown functions Steven Rostedt
2011-05-06 15:26 ` [RFC][PATCH 08/13] ftrace: Have global_ops store the functions that are to be traced Steven Rostedt
2011-05-06 15:26 ` [RFC][PATCH 09/13] ftrace: Free hash with call_rcu_sched() Steven Rostedt
2011-05-06 15:26 ` [RFC][PATCH 10/13] ftrace: Implement separate user function filtering Steven Rostedt
2011-05-06 15:26 ` [RFC][PATCH 11/13] ftrace: Allow dynamically allocated function tracers Steven Rostedt
2011-05-06 15:26 ` [RFC][PATCH 12/13] ftrace: Modify ftrace_set_filter/notrace to take ops Steven Rostedt
2011-05-06 15:26 ` [RFC][PATCH 13/13] ftrace: Add self-tests for multiple function trace users Steven Rostedt
2011-05-10 8:00 ` [RFC][PATCH 00/13] ftrace: Allow multiple users to pick and choose functions to trace Ingo Molnar
2011-05-10 8:32 ` Steven Rostedt
2011-05-10 14:29 ` Frederic Weisbecker
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20110506154739.344597908@goodmis.org \
--to=rostedt@goodmis.org \
--cc=akpm@linux-foundation.org \
--cc=dhsharp@google.com \
--cc=fweisbec@gmail.com \
--cc=jolsa@redhat.com \
--cc=laijs@cn.fujitsu.com \
--cc=linux-kernel@vger.kernel.org \
--cc=lizf@cn.fujitsu.com \
--cc=mathieu.desnoyers@efficios.com \
--cc=mingo@elte.hu \
--cc=mrubin@google.com \
--cc=tglx@linutronix.de \
--cc=vnagarnaik@google.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.