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>,
"Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
Subject: [RFC][PATCH 11/13] ftrace: Allow dynamically allocated function tracers
Date: Fri, 06 May 2011 11:26:35 -0400 [thread overview]
Message-ID: <20110506154741.969723618@goodmis.org> (raw)
In-Reply-To: 20110506152624.776982312@goodmis.org
[-- Attachment #1: 0011-ftrace-Allow-dynamically-allocated-function-tracers.patch --]
[-- Type: text/plain, Size: 6126 bytes --]
From: Steven Rostedt <srostedt@redhat.com>
Now that functions may be selected individually, it only makes sense
that we should allow dynamically allocated trace structures to
be traced. This will allow perf to allocate a ftrace_ops structure
at runtime and use it to pick and choose which functions that
structure will trace.
Note, a dynamically allocated ftrace_ops will always be called
indirectly instead of being called directly from the mcount in
entry.S. This is because there's no safe way to prevent mcount
from being preempted before calling the function, unless we
modify every entry.S to do so (not likely). Thus, dynamically allocated
functions will now be called by the ftrace_ops_list_func() that
loops through the ops that are allocated if there are more than
one op allocated at a time. This loop is protected with a
preempt_disable.
To determine if an ftrace_ops structure is allocated or not, a new
util function was added to the kernel/extable.c called
core_kernel_data(), which returns 1 if the address is between
_sdata and _edata.
Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
include/linux/ftrace.h | 1 +
include/linux/kernel.h | 1 +
kernel/extable.c | 8 ++++++++
kernel/trace/ftrace.c | 37 ++++++++++++++++++++++++++++++-------
4 files changed, 40 insertions(+), 7 deletions(-)
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 4609c0e..caba694 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -34,6 +34,7 @@ struct ftrace_hash;
enum {
FTRACE_OPS_FL_ENABLED = 1 << 0,
FTRACE_OPS_FL_GLOBAL = 1 << 1,
+ FTRACE_OPS_FL_DYNAMIC = 1 << 2,
};
struct ftrace_ops {
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 00cec4d..f37ba71 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -283,6 +283,7 @@ extern char *get_options(const char *str, int nints, int *ints);
extern unsigned long long memparse(const char *ptr, char **retptr);
extern int core_kernel_text(unsigned long addr);
+extern int core_kernel_data(unsigned long addr);
extern int __kernel_text_address(unsigned long addr);
extern int kernel_text_address(unsigned long addr);
extern int func_ptr_is_kernel_text(void *ptr);
diff --git a/kernel/extable.c b/kernel/extable.c
index 7f8f263..c2d625f 100644
--- a/kernel/extable.c
+++ b/kernel/extable.c
@@ -72,6 +72,14 @@ int core_kernel_text(unsigned long addr)
return 0;
}
+int core_kernel_data(unsigned long addr)
+{
+ if (addr >= (unsigned long)_sdata &&
+ addr < (unsigned long)_edata)
+ return 1;
+ return 0;
+}
+
int __kernel_text_address(unsigned long addr)
{
if (core_kernel_text(addr))
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 6c7e1df..5b3ee04 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -189,8 +189,14 @@ static void update_ftrace_function(void)
update_global_ops();
+ /*
+ * If we are at the end of the list and this ops is
+ * not dynamic, then have the mcount trampoline call
+ * the function directly
+ */
if (ftrace_ops_list == &ftrace_list_end ||
- ftrace_ops_list->next == &ftrace_list_end)
+ (ftrace_ops_list->next == &ftrace_list_end &&
+ !(ftrace_ops_list->flags & FTRACE_OPS_FL_DYNAMIC)))
func = ftrace_ops_list->func;
else
func = ftrace_ops_list_func;
@@ -250,6 +256,9 @@ static int __register_ftrace_function(struct ftrace_ops *ops)
if (WARN_ON(ops->flags & FTRACE_OPS_FL_ENABLED))
return -EBUSY;
+ if (!core_kernel_data((unsigned long)ops))
+ ops->flags |= FTRACE_OPS_FL_DYNAMIC;
+
if (ops->flags & FTRACE_OPS_FL_GLOBAL) {
int first = ftrace_global_list == &ftrace_list_end;
add_ftrace_ops(&ftrace_global_list, ops);
@@ -293,6 +302,13 @@ static int __unregister_ftrace_function(struct ftrace_ops *ops)
if (ftrace_enabled)
update_ftrace_function();
+ /*
+ * Dynamic ops may be freed, we must make sure that all
+ * callers are done before leaving this function.
+ */
+ if (ops->flags & FTRACE_OPS_FL_DYNAMIC)
+ synchronize_sched();
+
return 0;
}
@@ -1225,6 +1241,9 @@ ftrace_hash_move(struct ftrace_hash **dst, struct ftrace_hash *src)
* the filter_hash does not exist or is empty,
* AND
* the ip is not in the ops->notrace_hash.
+ *
+ * This needs to be called with preemption disabled as
+ * the hashes are freed with call_rcu_sched().
*/
static int
ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip)
@@ -1233,9 +1252,6 @@ ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip)
struct ftrace_hash *notrace_hash;
int ret;
- /* The hashes are freed with call_rcu_sched() */
- preempt_disable_notrace();
-
filter_hash = rcu_dereference_raw(ops->filter_hash);
notrace_hash = rcu_dereference_raw(ops->notrace_hash);
@@ -1246,7 +1262,6 @@ ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip)
ret = 1;
else
ret = 0;
- preempt_enable_notrace();
return ret;
}
@@ -3425,14 +3440,20 @@ ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip)
static void
ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip)
{
- /* see comment above ftrace_global_list_func */
- struct ftrace_ops *op = rcu_dereference_raw(ftrace_ops_list);
+ struct ftrace_ops *op;
+ /*
+ * Some of the ops may be dynamically allocated,
+ * they must be freed after a synchronize_sched().
+ */
+ preempt_disable_notrace();
+ op = rcu_dereference_raw(ftrace_ops_list);
while (op != &ftrace_list_end) {
if (ftrace_ops_test(op, ip))
op->func(ip, parent_ip);
op = rcu_dereference_raw(op->next);
};
+ preempt_enable_notrace();
}
static void clear_ftrace_swapper(void)
@@ -3743,6 +3764,7 @@ int register_ftrace_function(struct ftrace_ops *ops)
mutex_unlock(&ftrace_lock);
return ret;
}
+EXPORT_SYMBOL_GPL(register_ftrace_function);
/**
* unregister_ftrace_function - unregister a function for profiling.
@@ -3762,6 +3784,7 @@ int unregister_ftrace_function(struct ftrace_ops *ops)
return ret;
}
+EXPORT_SYMBOL_GPL(unregister_ftrace_function);
int
ftrace_enable_sysctl(struct ctl_table *table, int write,
--
1.7.2.3
next prev parent reply other threads:[~2011-05-06 15:48 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 ` [RFC][PATCH 01/13] ftrace: Replace FTRACE_FL_NOTRACE flag with a hash of ignored functions Steven Rostedt
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 ` Steven Rostedt [this message]
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=20110506154741.969723618@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=paulmck@linux.vnet.ibm.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox