All of lore.kernel.org
 help / color / mirror / Atom feed
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
> 
> 


  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 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.