From: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
To: Steven Rostedt <rostedt@goodmis.org>
Cc: linux-kernel@vger.kernel.org, Ingo Molnar <mingo@kernel.org>,
Andrew Morton <akpm@linux-foundation.org>,
Peter Zijlstra <peterz@infradead.org>,
Frederic Weisbecker <fweisbec@gmail.com>,
Jiri Olsa <jolsa@redhat.com>
Subject: Re: [RFC][PATCH 01/18 v2] ftrace: Add hash list to save RCU unsafe functions
Date: Sat, 31 Aug 2013 12:28:55 -0700 [thread overview]
Message-ID: <20130831192855.GH3871@linux.vnet.ibm.com> (raw)
In-Reply-To: <20130831051700.601365837@goodmis.org>
On Sat, Aug 31, 2013 at 01:11:18AM -0400, Steven Rostedt wrote:
> From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
>
> Some ftrace function tracing callbacks use RCU (perf), thus if
> it gets called from tracing a function outside of the RCU tracking,
> like in entering or leaving NO_HZ idle/userspace, the RCU read locks
> in the callback are useless.
>
> As normal function tracing does not use RCU, and function tracing
> happens to help debug RCU, we do not want to limit all callbacks
> from tracing these "unsafe" RCU functions. Instead, we create an
> infrastructure that will let us mark these unsafe RCU functions
> and we will only allow callbacks that explicitly say they do not
> use RCU to be called by these functions.
>
> This patch adds the infrastructure to create the hash of functions
> that are RCU unsafe. This is done with the FTRACE_UNSAFE_RCU()
> macro. It works like EXPORT_SYMBOL() does. Simply place the macro
> under the RCU unsafe function:
>
> void func(void)
> {
> [...]
> }
> FTRACE_UNSAFE_RCU(func);
>
> Cc: Jiri Olsa <jolsa@redhat.com>
> Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Acked-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
> ---
> include/asm-generic/vmlinux.lds.h | 10 +++
> include/linux/ftrace.h | 38 +++++++++++
> kernel/trace/ftrace.c | 135 ++++++++++++++++++++++++++++++++++---
> 3 files changed, 174 insertions(+), 9 deletions(-)
>
> diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
> index 69732d2..fdfddd2 100644
> --- a/include/asm-generic/vmlinux.lds.h
> +++ b/include/asm-generic/vmlinux.lds.h
> @@ -93,6 +93,15 @@
> #define MCOUNT_REC()
> #endif
>
> +#ifdef CONFIG_FUNCTION_TRACER
> +#define FTRACE_UNSAFE_RCU() . = ALIGN(8); \
> + VMLINUX_SYMBOL(__start_ftrace_unsafe_rcu) = .; \
> + *(_ftrace_unsafe_rcu) \
> + VMLINUX_SYMBOL(__stop_ftrace_unsafe_rcu) = .;
> +#else
> +#define FTRACE_UNSAFE_RCU()
> +#endif
> +
> #ifdef CONFIG_TRACE_BRANCH_PROFILING
> #define LIKELY_PROFILE() VMLINUX_SYMBOL(__start_annotated_branch_profile) = .; \
> *(_ftrace_annotated_branch) \
> @@ -479,6 +488,7 @@
> MEM_DISCARD(init.data) \
> KERNEL_CTORS() \
> MCOUNT_REC() \
> + FTRACE_UNSAFE_RCU() \
> *(.init.rodata) \
> FTRACE_EVENTS() \
> TRACE_SYSCALLS() \
> diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
> index 9f15c00..1d17a82 100644
> --- a/include/linux/ftrace.h
> +++ b/include/linux/ftrace.h
> @@ -92,6 +92,9 @@ typedef void (*ftrace_func_t)(unsigned long ip, unsigned long parent_ip,
> * STUB - The ftrace_ops is just a place holder.
> * INITIALIZED - The ftrace_ops has already been initialized (first use time
> * register_ftrace_function() is called, it will initialized the ops)
> + * RCU_SAFE - The callback uses no rcu type locking. This allows the
> + * callback to be called in locations that RCU is not active.
> + * (like going into or coming out of idle NO_HZ)
> */
> enum {
> FTRACE_OPS_FL_ENABLED = 1 << 0,
> @@ -103,6 +106,7 @@ enum {
> FTRACE_OPS_FL_RECURSION_SAFE = 1 << 6,
> FTRACE_OPS_FL_STUB = 1 << 7,
> FTRACE_OPS_FL_INITIALIZED = 1 << 8,
> + FTRACE_OPS_FL_RCU_SAFE = 1 << 9,
> };
>
> struct ftrace_ops {
> @@ -219,6 +223,40 @@ static inline int ftrace_function_local_disabled(struct ftrace_ops *ops)
> extern void ftrace_stub(unsigned long a0, unsigned long a1,
> struct ftrace_ops *op, struct pt_regs *regs);
>
> +/*
> + * In order to speed up boot, save both the name and the
> + * address of the function to find to add to hashes. The
> + * list of function mcount addresses are sorted by the address,
> + * but we still need to use the name to find the actual location
> + * as the mcount call is usually not at the address of the
> + * start of the function.
> + */
> +struct ftrace_func_finder {
> + const char *name;
> + unsigned long ip;
> +};
> +
> +/*
> + * For functions that are called when RCU is not tracking the CPU
> + * (like for entering or leaving NO_HZ mode, and RCU then ignores
> + * the CPU), they need to be marked with FTRACE_UNSAFE_RCU().
> + * This will prevent all function tracing callbacks from calling
> + * this function unless the callback explicitly states that it
> + * doesn't use RCU with the FTRACE_OPS_FL_RCU_SAFE flag.
> + *
> + * The usage of FTRACE_UNSAFE_RCU() is the same as EXPORT_SYMBOL().
> + * Just place the macro underneath the function that is unsafe.
> + */
> +#define FTRACE_UNSAFE_RCU(func) \
> + static struct ftrace_func_finder __ftrace_unsafe_rcu_##func \
> + __initdata = { \
> + .name = #func, \
> + .ip = (unsigned long)func, \
> + }; \
> + struct ftrace_func_finder *__ftrace_unsafe_rcu_ptr_##func \
> + __attribute__((__section__("_ftrace_unsafe_rcu"))) = \
> + &__ftrace_unsafe_rcu_##func
> +
> #else /* !CONFIG_FUNCTION_TRACER */
> /*
> * (un)register_ftrace_function must be a macro since the ops parameter
> diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
> index a6d098c..3750360 100644
> --- a/kernel/trace/ftrace.c
> +++ b/kernel/trace/ftrace.c
> @@ -1356,6 +1356,23 @@ ftrace_hash_rec_disable(struct ftrace_ops *ops, int filter_hash);
> static void
> ftrace_hash_rec_enable(struct ftrace_ops *ops, int filter_hash);
>
> +static int ftrace_convert_size_to_bits(int size)
> +{
> + int bits;
> +
> + /*
> + * Make the hash size about 1/2 the # found
> + */
> + for (size /= 2; size; size >>= 1)
> + bits++;
> +
> + /* Don't allocate too much */
> + if (bits > FTRACE_HASH_MAX_BITS)
> + bits = FTRACE_HASH_MAX_BITS;
> +
> + return bits;
> +}
> +
> static int
> ftrace_hash_move(struct ftrace_ops *ops, int enable,
> struct ftrace_hash **dst, struct ftrace_hash *src)
> @@ -1388,15 +1405,7 @@ ftrace_hash_move(struct ftrace_ops *ops, int enable,
> goto out;
> }
>
> - /*
> - * Make the hash size about 1/2 the # found
> - */
> - for (size /= 2; size; size >>= 1)
> - bits++;
> -
> - /* Don't allocate too much */
> - if (bits > FTRACE_HASH_MAX_BITS)
> - bits = FTRACE_HASH_MAX_BITS;
> + bits = ftrace_convert_size_to_bits(size);
>
> ret = -ENOMEM;
> new_hash = alloc_ftrace_hash(bits);
> @@ -1486,6 +1495,74 @@ ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip, void *regs)
> }
>
>
> +static __init int ftrace_find_ip(const void *a, const void *b)
> +{
> + const struct dyn_ftrace *key = a;
> + const struct dyn_ftrace *rec = b;
> +
> + if (key->ip == rec->ip)
> + return 0;
> +
> + if (key->ip < rec->ip) {
> + /* If previous is less than, then this is our func */
> + rec--;
> + if (rec->ip < key->ip)
> + return 0;
> + return -1;
> + }
> +
> + /* All else, we are greater */
> + return 1;
> +}
> +
> +/*
> + * Find the mcount caller location given the ip address of the
> + * function that contains it. As the mcount caller is usually
> + * after the mcount itself.
> + *
> + * Done for just core functions at boot.
> + */
> +static __init unsigned long ftrace_mcount_from_func(unsigned long ip)
> +{
> + struct ftrace_page *pg, *last_pg = NULL;
> + struct dyn_ftrace *rec;
> + struct dyn_ftrace key;
> +
> + key.ip = ip;
> +
> + for (pg = ftrace_pages_start; pg; last_pg = pg, pg = pg->next) {
> + if (ip >= (pg->records[pg->index - 1].ip + MCOUNT_INSN_SIZE))
> + continue;
> +
> + /*
> + * Do the first record manually, as we need to check
> + * the previous record from the previous page
> + */
> + if (ip < pg->records[0].ip) {
> + /* First page? Then we found our record! */
> + if (!last_pg)
> + return pg->records[0].ip;
> +
> + rec = &last_pg->records[last_pg->index - 1];
> + if (rec->ip < ip)
> + return pg->records[0].ip;
> +
> + /* Not found */
> + return 0;
> + }
> +
> + rec = bsearch(&key, pg->records + 1, pg->index - 1,
> + sizeof(struct dyn_ftrace),
> + ftrace_find_ip);
> + if (rec)
> + return rec->ip;
> +
> + break;
> + }
> +
> + return 0;
> +}
> +
> static int ftrace_cmp_recs(const void *a, const void *b)
> {
> const struct dyn_ftrace *key = a;
> @@ -4211,6 +4288,44 @@ struct notifier_block ftrace_module_exit_nb = {
> .priority = INT_MIN, /* Run after anything that can remove kprobes */
> };
>
> +extern struct ftrace_func_finder *__start_ftrace_unsafe_rcu[];
> +extern struct ftrace_func_finder *__stop_ftrace_unsafe_rcu[];
> +
> +static struct ftrace_hash *ftrace_unsafe_rcu;
> +
> +static void __init create_unsafe_rcu_hash(void)
> +{
> + struct ftrace_func_finder *finder;
> + struct ftrace_func_finder **p;
> + unsigned long ip;
> + char str[KSYM_SYMBOL_LEN];
> + int count;
> +
> + count = __stop_ftrace_unsafe_rcu - __start_ftrace_unsafe_rcu;
> + if (!count)
> + return;
> +
> + count = ftrace_convert_size_to_bits(count);
> + ftrace_unsafe_rcu = alloc_ftrace_hash(count);
> +
> + for (p = __start_ftrace_unsafe_rcu;
> + p < __stop_ftrace_unsafe_rcu;
> + p++) {
> + finder = *p;
> +
> + ip = ftrace_mcount_from_func(finder->ip);
> + if (WARN_ON_ONCE(!ip))
> + continue;
> +
> + /* Make sure this is our ip */
> + kallsyms_lookup(ip, NULL, NULL, NULL, str);
> + if (WARN_ON_ONCE(strcmp(str, finder->name) != 0))
> + continue;
> +
> + add_hash_entry(ftrace_unsafe_rcu, ip);
> + }
> +}
> +
> extern unsigned long __start_mcount_loc[];
> extern unsigned long __stop_mcount_loc[];
>
> @@ -4250,6 +4365,8 @@ void __init ftrace_init(void)
> if (ret)
> pr_warning("Failed to register trace ftrace module exit notifier\n");
>
> + create_unsafe_rcu_hash();
> +
> set_ftrace_early_filters();
>
> return;
> --
> 1.7.10.4
>
>
next prev parent reply other threads:[~2013-08-31 19:29 UTC|newest]
Thread overview: 74+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-08-31 5:11 [RFC][PATCH 00/18 v2] ftrace/rcu: Handle unsafe RCU functions and ftrace callbacks Steven Rostedt
2013-08-31 5:11 ` [RFC][PATCH 01/18 v2] ftrace: Add hash list to save RCU unsafe functions Steven Rostedt
2013-08-31 19:28 ` Paul E. McKenney [this message]
2013-09-03 21:15 ` Steven Rostedt
2013-09-03 22:18 ` Paul E. McKenney
2013-09-03 23:57 ` Steven Rostedt
2013-09-04 0:18 ` Steven Rostedt
2013-09-04 1:11 ` [RFC][PATCH 19/18] ftrace: Print a message when the rcu checker is disabled Steven Rostedt
2013-09-04 1:25 ` Paul E. McKenney
2013-09-04 1:24 ` [RFC][PATCH 01/18 v2] ftrace: Add hash list to save RCU unsafe functions Paul E. McKenney
2013-09-04 1:51 ` Steven Rostedt
2013-09-04 1:56 ` Steven Rostedt
2013-09-04 2:01 ` Steven Rostedt
2013-09-04 2:03 ` Steven Rostedt
2013-09-04 4:18 ` Paul E. McKenney
2013-09-04 11:50 ` Steven Rostedt
2013-09-04 4:12 ` Paul E. McKenney
2013-08-31 5:11 ` [RFC][PATCH 02/18 v2] ftrace: Do not set ftrace records for unsafe RCU when not allowed Steven Rostedt
2013-08-31 19:29 ` Paul E. McKenney
2013-08-31 5:11 ` [RFC][PATCH 03/18 v2] ftrace: Set ftrace internal function tracing RCU safe Steven Rostedt
2013-08-31 19:30 ` Paul E. McKenney
2013-08-31 19:44 ` Paul E. McKenney
2013-09-03 13:22 ` Steven Rostedt
2013-09-03 13:54 ` Paul E. McKenney
2013-08-31 5:11 ` [RFC][PATCH 04/18 v2] ftrace: Add test for ops against unsafe RCU functions in callback Steven Rostedt
2013-08-31 19:45 ` Paul E. McKenney
2013-08-31 5:11 ` [RFC][PATCH 05/18 v2] ftrace: Do not display non safe RCU functions in available_filter_functions Steven Rostedt
2013-08-31 19:46 ` Paul E. McKenney
2013-08-31 20:35 ` Steven Rostedt
2013-08-31 20:54 ` Paul E. McKenney
2013-09-03 13:26 ` Steven Rostedt
2013-09-03 13:54 ` Paul E. McKenney
2013-08-31 5:11 ` [RFC][PATCH 06/18 v2] ftrace: Add rcu_unsafe_filter_functions file Steven Rostedt
2013-08-31 19:46 ` Paul E. McKenney
2013-08-31 5:11 ` [RFC][PATCH 07/18 v2] ftrace: Add selftest to check if RCU unsafe functions are filtered properly Steven Rostedt
2013-08-31 19:47 ` Paul E. McKenney
2013-08-31 5:11 ` [RFC][PATCH 08/18 v2] ftrace/rcu: Do not trace debug_lockdep_rcu_enabled() Steven Rostedt
2013-08-31 19:21 ` Paul E. McKenney
2013-08-31 20:31 ` Steven Rostedt
2013-08-31 5:11 ` [RFC][PATCH 09/18 v2] ftrace: Fix a slight race in modifying what function callback gets traced Steven Rostedt
2013-08-31 5:11 ` [RFC][PATCH 10/18 v2] ftrace: Create a RCU unsafe checker Steven Rostedt
2013-08-31 19:49 ` Paul E. McKenney
2013-08-31 5:11 ` [RFC][PATCH 11/18 v2] ftrace: Adde infrastructure to stop RCU unsafe checker from checking Steven Rostedt
2013-08-31 19:52 ` Paul E. McKenney
2013-08-31 20:40 ` Steven Rostedt
2013-09-03 13:43 ` Steven Rostedt
2013-09-03 15:22 ` Paul E. McKenney
2013-08-31 5:11 ` [RFC][PATCH 12/18 v2] ftrace: Disable RCU unsafe checker when function graph is enabled Steven Rostedt
2013-08-31 19:55 ` Paul E. McKenney
2013-08-31 20:42 ` Steven Rostedt
2013-08-31 20:58 ` Paul E. McKenney
2013-08-31 5:11 ` [RFC][PATCH 13/18 v2] ftrace: Disable the RCU unsafe checker when irqsoff " Steven Rostedt
2013-08-31 19:58 ` Paul E. McKenney
2013-08-31 5:11 ` [RFC][PATCH 14/18 v2] ftrace/lockdep: Have the RCU lockdep splat show what function triggered Steven Rostedt
2013-08-31 19:59 ` Paul E. McKenney
2013-09-05 19:18 ` Peter Zijlstra
2013-09-05 19:52 ` Steven Rostedt
2013-09-06 12:57 ` Ingo Molnar
2013-09-06 13:16 ` Steven Rostedt
2013-09-05 19:35 ` Peter Zijlstra
2013-09-05 20:27 ` Steven Rostedt
2013-08-31 5:11 ` [RFC][PATCH 15/18 v2] ftrace/rcu: Mark functions that are RCU unsafe Steven Rostedt
2013-08-31 20:00 ` Paul E. McKenney
2013-08-31 20:43 ` Steven Rostedt
2013-08-31 20:54 ` Paul E. McKenney
2013-08-31 5:11 ` [RFC][PATCH 16/18 v2] rcu/irq/x86: " Steven Rostedt
2013-08-31 20:01 ` Paul E. McKenney
2013-08-31 5:11 ` [RFC][PATCH 17/18 v2] ftrace/cpuidle/x86: " Steven Rostedt
2013-08-31 11:07 ` Wysocki, Rafael J
2013-08-31 20:02 ` Paul E. McKenney
2013-09-04 0:16 ` H. Peter Anvin
2013-08-31 5:11 ` [RFC][PATCH 18/18 v2] ftrace/sched: " Steven Rostedt
2013-08-31 20:01 ` Paul E. McKenney
2013-08-31 15:50 ` [RFC][PATCH 00/18 v2] ftrace/rcu: Handle unsafe RCU functions and ftrace callbacks Steven Rostedt
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=20130831192855.GH3871@linux.vnet.ibm.com \
--to=paulmck@linux.vnet.ibm.com \
--cc=akpm@linux-foundation.org \
--cc=fweisbec@gmail.com \
--cc=jolsa@redhat.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@kernel.org \
--cc=peterz@infradead.org \
--cc=rostedt@goodmis.org \
/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