Skip to contentSkip to conversation

ftrace/rcu: Handle unsafe RCU functions and ftrace callbacks

RFC PATCH In review Steven Rostedt 6 participants 74 messages Aug 31, 2013 – Sep 6, 2013

Subsystems (7)
lore
Share & tools
lore

Steven Rostedt

author maintainer
#0 lore raw

v2 cover ftrace/rcu: Handle unsafe RCU functions and ftrace callbacks

This is my final draft of the patches. I'm starting to run them through my formal tests now. They may change depending on the outcome of the tests.

I'm also a bit tired, and I added the change logs last. Thus I may need to go back and fix the change logs up too. But the code was done when I was rather spunky. But that doesn't mean I didn't break anything.

Anyway, let me know what you think. I'm going to need acks for the places I added the FTRACE_UNSAFE_RCU() annotations.

I added a checker that traces all functions with the non RCU safe settings, and did a rcu_read_lock() with PROVE_RCU enabled. This caught several functions that needed to be annotated. There may be more, but the test gives us a way to find out.

There's some improvements that can be done to these patches, but for 3.12, I think this version is good enough. We can do the improvements for 3.13.

Well, enjoy.

-- Steve

Steven Rostedt (Red Hat) (18):
ftrace: Add hash list to save RCU unsafe functions
ftrace: Do not set ftrace records for unsafe RCU when not allowed
ftrace: Set ftrace internal function tracing RCU safe
ftrace: Add test for ops against unsafe RCU functions in callback
ftrace: Do not display non safe RCU functions in available_filter_functions
ftrace: Add rcu_unsafe_filter_functions file
ftrace: Add selftest to check if RCU unsafe functions are filtered properly ftrace/rcu: Do not trace debug_lockdep_rcu_enabled()
ftrace: Fix a slight race in modifying what function callback gets traced
ftrace: Create a RCU unsafe checker
ftrace: Adde infrastructure to stop RCU unsafe checker from checking
ftrace: Disable RCU unsafe checker when function graph is enabled
ftrace: Disable the RCU unsafe checker when irqsoff is enabled ftrace/lockdep: Have the RCU lockdep splat show what function triggered ftrace/rcu: Mark functions that are RCU unsafe
rcu/irq/x86: Mark functions that are RCU unsafe ftrace/cpuidle/x86: Mark functions that are RCU unsafe ftrace/sched: Mark functions that are RCU unsafe

----

 arch/x86/kernel/apic/apic.c           |    2 +
 arch/x86/kernel/irq.c                 |    1 +
 arch/x86/kernel/irq_work.c            |    3 +
 arch/x86/kernel/process.c             |    2 +
 arch/x86/kernel/smp.c                 |    8 ++
 drivers/cpuidle/cpuidle.c             |    2 +
 include/asm-generic/vmlinux.lds.h     |   10 ++
 include/linux/ftrace.h                |   46 +++++++
 kernel/cpu/idle.c                     |    2 +
 kernel/lockdep.c                      |    2 +
 kernel/rcupdate.c                     |    2 +-
 kernel/rcutiny.c                      |    1 +
 kernel/rcutree.c                      |    7 +
 kernel/sched/core.c                   |    2 +
 kernel/softirq.c                      |    2 +
 kernel/trace/Kconfig                  |   22 ++++
 kernel/trace/ftrace.c                 |  231 +++++++++++++++++++++++++++++++--
 kernel/trace/trace.h                  |   11 ++
 kernel/trace/trace_functions.c        |   76 ++++++++++-
 kernel/trace/trace_irqsoff.c          |   16 ++-
 kernel/trace/trace_selftest.c         |   94 ++++++++++++++
 kernel/trace/trace_selftest_dynamic.c |    7 +
 22 files changed, 532 insertions(+), 17 deletions(-)
author maintainer
#1 lore raw

RFC PATCH v2 1/18 ftrace: Add hash list to save RCU unsafe functions

From: "Steven Rostedt (Red Hat)" <[email protected]>

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 <[email protected]>
Cc Paul E. McKenney <[email protected]>
---
 include/asm-generic/vmlinux.lds.h |   10 +++
 include/linux/ftrace.h            |   38 +++++++++++
 kernel/trace/ftrace.c             |  135 ++++++++++++++++++++++++++++++++++---
 3 files changed, 174 insertions(+), 9 deletions(-)
include/asm-generic/vmlinux.lds.h +10 -0
index 69732d2..fdfddd2 100644
@@ -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()						\
include/linux/ftrace.h +38 -0
index 9f15c00..1d17a82 100644
@@ -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
kernel/trace/ftrace.c +126 -9

165 lines not on this page · raw message

Signature · 1 line
1.7.10.4
Acked-by on v2 1/18
#2 lore raw

Re: [RFC][PATCH 01/18 v2] ftrace: Add hash list to save RCU unsafe functions

Quoted 20 lines · Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

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)

Quoted 8 lines
{
	[...]
}

FTRACE_UNSAFE_RCU(func);

Cc Jiri Olsa <[email protected]>
Cc Paul E. McKenney <[email protected]>
Quoted 275 lines
---
 include/asm-generic/vmlinux.lds.h |   10 +++
 include/linux/ftrace.h            |   38 +++++++++++
 kernel/trace/ftrace.c             |  135 ++++++++++++++++++++++++++++++++++---
 3 files changed, 174 insertions(+), 9 deletions(-)
include/asm-generic/vmlinux.lds.h +10 -0
index 69732d2..fdfddd2 100644
@@ -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()						\
include/linux/ftrace.h +38 -0
index 9f15c00..1d17a82 100644
@@ -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
kernel/trace/ftrace.c +126 -9
index a6d098c..3750360 100644
@@ -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;
Signature · 1 line
1.7.10.4
author maintainer
#3 lore raw

Re: [RFC][PATCH 01/18 v2] ftrace: Add hash list to save RCU unsafe functions

In reply to Steven Rostedt
Quoted 15 lines · On Sat, 31 Aug 2013 01:11:18 -0400 Steven Rostedt <[email protected]> wrote:
kernel/trace/ftrace.c +7 -0
index a6d098c..3750360 100644
@@ -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
+	 */

kernel/trace/ftrace.c ftrace_hash_rec_disable(struct ftrace_ops *ops, int filter_hash); · line 1375

Quoted 10 lines
kernel/trace/ftrace.c +10 -0
+	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;
+}
+

Just found this bug. Strange that gcc never gave me a warning :-/

-- Steve

#4 lore raw

Re: [RFC][PATCH 01/18 v2] ftrace: Add hash list to save RCU unsafe functions

Quoted 23 lines · Steven Rostedt
Quoted 19 lines · On Sat, 31 Aug 2013 01:11:18 -0400 Steven Rostedt <[email protected]> wrote:
kernel/trace/ftrace.c +11 -0
index a6d098c..3750360 100644
@@ -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 */
Quoted 8 lines

kernel/trace/ftrace.c ftrace_hash_rec_disable(struct ftrace_ops *ops, int filter_hash); · line 1375

Quoted 6 lines
kernel/trace/ftrace.c +6 -0
+	if (bits > FTRACE_HASH_MAX_BITS)
+		bits = FTRACE_HASH_MAX_BITS;
+
+	return bits;
+}
+

Just found this bug. Strange that gcc never gave me a warning :-/

I can't give gcc too much trouble, as I also didn't give you an uninitialized-variable warning.

Thanx, Paul

author maintainer
#5 lore raw

Re: [RFC][PATCH 01/18 v2] ftrace: Add hash list to save RCU unsafe functions

Quoted 4 lines · On Tue, 3 Sep 2013 15:18:08 -0700 "Paul E. McKenney"…
Quoted 1 line

Just found this bug. Strange that gcc never gave me a warning :-/

I can't give gcc too much trouble, as I also didn't give you an uninitialized-variable warning.

I was also chasing down a nasty bug that looked to be a pointer corruption somewhere. Still never found exactly where it happened, but it always happened with the following conditions:

synchronize_sched() was in progress

The ftrace_unsafe_callback() was preempted by an interrupt

lockdep was processing a lock

A crash would happen which had memory corruption involved. But the above seemed always to be in play.

Now, I changed the logic from disabling context level recursion to disabling recursion at all. That is, the original code had used a series of bits to test for recursion (via helper functions) that would allow for the callback to be preempted by an interrupt, and then be called again.

The new code sets a per_cpu flag, and will not allow the callback to recurse if it were preempted by an interrupt. No real need to allow for that anyway.

I can go and debug this further, because I'm nervous that lockdep may have some kind of bug that the function tracer can trigger. But I'm not too concerned about it.

Here's the diff of the new code against the previous code.

Paul, can I still keep all your acks and reviewed-bys on this?

-- Steve

kernel/trace/ftrace.c +1 -1
index 310b727..899c8c1 100644
@@ -1373,7 +1373,7 @@ ftrace_hash_rec_enable(struct ftrace_ops *ops, int filter_hash);
 
 static int ftrace_convert_size_to_bits(int size)
 {
-	int bits;
+	int bits = 0;
 
 	/*
 	 * Make the hash size about 1/2 the # found
kernel/trace/trace_functions.c +11 -5
index f5a9031..0883069 100644
@@ -561,16 +561,21 @@ static inline int init_func_cmd_traceon(void)
 
 #ifdef CONFIG_FTRACE_UNSAFE_RCU_CHECKER
 
+static DEFINE_PER_CPU(int, ftrace_rcu_running);
 static atomic_t ftrace_unsafe_rcu_disabled;
 
 void ftrace_unsafe_rcu_checker_disable(void)
 {
 	atomic_inc(&ftrace_unsafe_rcu_disabled);
+	/* Make sure the update is seen immediately */
+	smp_wmb();
 }
 
 void ftrace_unsafe_rcu_checker_enable(void)
 {
 	atomic_dec(&ftrace_unsafe_rcu_disabled);
+	/* Make sure the update is seen immediately */
+	smp_wmb();
 }
 
 static DEFINE_PER_CPU(unsigned long, ftrace_rcu_func);
@@ -588,15 +593,14 @@ static void
 ftrace_unsafe_callback(unsigned long ip, unsigned long parent_ip,
 		       struct ftrace_ops *op, struct pt_regs *pt_regs)
 {
-	int bit;
-
+	/* Make sure we see disabled or not first */
+	smp_rmb();
 	if (atomic_read(&ftrace_unsafe_rcu_disabled))
 		return;
 
 	preempt_disable_notrace();
 
-	bit = trace_test_and_set_recursion(TRACE_FTRACE_START, TRACE_FTRACE_MAX);
-	if (bit < 0)
+	if (this_cpu_read(ftrace_rcu_running))
 		goto out;
 
 	if (WARN_ONCE(ftrace_rcu_unsafe(ip),
@@ -604,13 +608,15 @@ ftrace_unsafe_callback(unsigned long ip, unsigned long parent_ip,
 		      (void *)ip))
 		goto out;
 
+	this_cpu_write(ftrace_rcu_running, 1);
 	this_cpu_write(ftrace_rcu_func, ip);
+
 	/* Should trigger a RCU splat if called from unsafe RCU function */
 	rcu_read_lock();
 	rcu_read_unlock();
 	this_cpu_write(ftrace_rcu_func, 0);
 
-	trace_clear_recursion(bit);
+	this_cpu_write(ftrace_rcu_running, 0);
  out:
 	preempt_enable_notrace();
 }
author maintainer
#6 lore raw

Re: [RFC][PATCH 01/18 v2] ftrace: Add hash list to save RCU unsafe functions

Quoted 6 lines · On Tue, 3 Sep 2013 19:57:05 -0400 Steven Rostedt <[email protected]> wrote:

I was also chasing down a nasty bug that looked to be a pointer corruption somewhere. Still never found exactly where it happened, but it always happened with the following conditions:

synchronize_sched() was in progress

Quoted 8 lines

The ftrace_unsafe_callback() was preempted by an interrupt

lockdep was processing a lock

A crash would happen which had memory corruption involved. But the above seemed always to be in play.

Now putting back the context level recursion checks, and also adding a check for "oops_in_progress" to have the unsafe callback not call rcu_read_lock() on oops, I can get decent backtraces.

This seems to be what I get consistently now:

[   28.583983] Testing kprobe tracing: [   28.609714] ------------[ cut here ]------------
[   28.610050] WARNING: CPU: 2 PID: 0 at /home/rostedt/work/git/linux-trace.git/kernel/lockdep.c:960 __bfs+0xe8/0x1d5()
[   28.610050] Modules linked in:
[   28.610050] CPU: 2 PID: 0 Comm: swapper/2 Not tainted 3.11.0-rc3-test+ #220
[   28.610050] Hardware name: To Be Filled By O.E.M. To Be Filled By O.E.M./To be filled by O.E.M., BIOS SDBLI944.86P 05/08/2007
[   28.610050]  00000000000003c0 ffff88007d503a18 ffffffff81548e29 0000000000000000
[   28.610050]  0000000000000000 ffff88007d503a58 ffffffff810427b1 ffffffff817fc1ba
[   28.610050]  ffffffff810944f6 0000000000000000 0000000000000002 ffffffff81093d06
[   28.610050] Call Trace:
[   28.610050]  <IRQ>  [<ffffffff81548e29>] dump_stack+0x52/0x89
[   28.610050]  [<ffffffff810427b1>] warn_slowpath_common+0x81/0x9b
[   28.610050]  [<ffffffff810944f6>] ? __bfs+0xe8/0x1d5
[   28.610050]  [<ffffffff81093d06>] ? noop_count+0xb/0xb
[   28.610050]  [<ffffffff810427e5>] warn_slowpath_null+0x1a/0x1c
[   28.610050]  [<ffffffff810944f6>] __bfs+0xe8/0x1d5
[   28.610050]  [<ffffffff81550c77>] ? sub_preempt_count+0xe/0xe0
[   28.610050]  [<ffffffff81095fa2>] ? print_irq_inversion_bug+0x1d2/0x1d2
[   28.610050]  [<ffffffff81095ff0>] check_usage_forwards+0x4e/0x87
[   28.610050]  [<ffffffff810965d0>] ? valid_state+0x2b/0x235
[   28.610050]  [<ffffffff810968d9>] mark_lock+0xff/0x1d8
[   28.610050]  [<ffffffff81096caa>] __lock_acquire+0x2f8/0xf57
[   28.610050]  [<ffffffff810df575>] ? ftrace_unsafe_callback+0x1f1/0x203
[   28.610050]  [<ffffffff810df465>] ? ftrace_unsafe_callback+0xe1/0x203
[   28.610050]  [<ffffffff81553dfc>] ? ftrace_call+0x5/0x2f
[   28.610050]  [<ffffffff810554dc>] ? __lock_task_sighand+0x9f/0xe9
[   28.610050]  [<ffffffff81097e70>] lock_acquire+0xf2/0x138
[   28.610050]  [<ffffffff810554dc>] ? __lock_task_sighand+0x9f/0xe9
[   28.610050]  [<ffffffff81053824>] ? task_pid_vnr+0xf/0xf
[   28.610050]  [<ffffffff8154cd40>] _raw_spin_lock+0x3b/0x4a
[   28.610050]  [<ffffffff810554dc>] ? __lock_task_sighand+0x9f/0xe9
[   28.610050]  [<ffffffff8105376a>] ? rcu_read_lock_held+0x37/0x3f
[   28.610050]  [<ffffffff81053824>] ? task_pid_vnr+0xf/0xf
[   28.610050]  [<ffffffff810554dc>] __lock_task_sighand+0x9f/0xe9
[   28.610050]  [<ffffffff81062e24>] ? __rcu_read_lock+0x4/0x1a
[   28.610050]  [<ffffffff81067f79>] run_posix_cpu_timers+0x141/0x4a8
[   28.610050]  [<ffffffff81062e24>] ? __rcu_read_lock+0x4/0x1a
[   28.610050]  [<ffffffff8107b97a>] ? trigger_load_balance+0x10/0x264
[   28.610050]  [<ffffffff81052aad>] update_process_times+0x6a/0x72
[   28.610050]  [<ffffffff810925b2>] ? tick_sched_handle.clone.9+0xc/0x55
[   28.610050]  [<ffffffff810925ec>] tick_sched_handle.clone.9+0x46/0x55
[   28.610050]  [<ffffffff810926d8>] tick_sched_timer+0x42/0x62
[   28.610050]  [<ffffffff81068b38>] __run_hrtimer+0xeb/0x1dc
[   28.610050]  [<ffffffff81092696>] ? tick_nohz_handler+0x9b/0x9b
[   28.610050]  [<ffffffff810693e4>] hrtimer_interrupt+0xed/0x1f3
[   28.610050]  [<ffffffff8102a160>] local_apic_timer_interrupt+0x57/0x5b
[   28.610050]  [<ffffffff8155629a>] smp_apic_timer_interrupt+0x2f/0x41
[   28.610050]  [<ffffffff81554e2f>] apic_timer_interrupt+0x6f/0x80
[   28.610050]  <EOI>  [<ffffffff810df575>] ? ftrace_unsafe_callback+0x1f1/0x203
[   28.610050]  [<ffffffff810df465>] ? ftrace_unsafe_callback+0xe1/0x203
[   28.610050]  [<ffffffff8100b2df>] ? default_idle+0x21/0x32
[   28.610050]  [<ffffffff8100b2dd>] ? default_idle+0x1f/0x32
[   28.610050]  [<ffffffff8100ba5c>] arch_cpu_idle+0x18/0x22
[   28.610050]  [<ffffffff81089b59>] cpu_startup_entry+0x109/0x16c
[   28.610050]  [<ffffffff81028ba0>] start_secondary+0x251/0x258
[   28.610050] ---[ end trace 19765ef14295ecea ]---

Oh yes, and it always happens on testing kprobes. But it happens when that test does a synchronize_sched().

-- Steve

author maintainer
#7 lore raw

[RFC][PATCH 19/18] ftrace: Print a message when the rcu checker is disabled

Quoted 1 line

From f8f5d278e272c42349b3cd32485faf426d0c459e Mon Sep 17 00:00:00 2001

From: "Steven Rostedt (Red Hat)" <[email protected]>
Date: Tue, 3 Sep 2013 20:47:59 -0400
Subject: [PATCH] ftrace: Print a message when the rcu checker is disabled

Let the user know that the RCU safety checker for function tracing has been disabled. The checker only runs when the user specifically configures it in the kernel, and this is done to search for locations in the kernel that may be unsafe for a function trace callback to use rcu_read_lock()s. But if things like function graph tracing is started, which can live lock the machine when the checker is running, it is disabled. It would be nice if the kernel let the user know that the checker is disabled, and when it is re-enabled again.

As the checker only gets disabled and re-enabled by user actions (starting and stoping the function graph tracer or the irqsoff tracer) it is fine to have a printk display that it is disabled or not.

---
 kernel/trace/trace_functions.c | 4 ++++
 1 file changed, 4 insertions(+)
kernel/trace/trace_functions.c +4 -0
index 0883069..dd59827 100644
@@ -569,6 +569,8 @@ void ftrace_unsafe_rcu_checker_disable(void)
 	atomic_inc(&ftrace_unsafe_rcu_disabled);
 	/* Make sure the update is seen immediately */
 	smp_wmb();
+	pr_info("Disabled FTRACE RCU checker (%pS)\n",
+		__builtin_return_address(0));
 }
 
 void ftrace_unsafe_rcu_checker_enable(void)
@@ -576,6 +578,8 @@ void ftrace_unsafe_rcu_checker_enable(void)
 	atomic_dec(&ftrace_unsafe_rcu_disabled);
 	/* Make sure the update is seen immediately */
 	smp_wmb();
+	pr_info("Enabled FTRACE RCU checker (%pS)\n",
+		__builtin_return_address(0));
 }
 
 static DEFINE_PER_CPU(unsigned long, ftrace_rcu_func);
Signature · 1 line
1.8.1.4
Reviewed-by
#8 lore raw

Re: [RFC][PATCH 19/18] ftrace: Print a message when the rcu checker is disabled

Quoted 14 lines · Steven Rostedt

From f8f5d278e272c42349b3cd32485faf426d0c459e Mon Sep 17 00:00:00 2001
From: "Steven Rostedt (Red Hat)" <[email protected]>
Date: Tue, 3 Sep 2013 20:47:59 -0400
Subject: [PATCH] ftrace: Print a message when the rcu checker is disabled

Let the user know that the RCU safety checker for function tracing has been disabled. The checker only runs when the user specifically configures it in the kernel, and this is done to search for locations in the kernel that may be unsafe for a function trace callback to use rcu_read_lock()s. But if things like function graph tracing is started, which can live lock the machine when the checker is running, it is disabled. It would be nice if the kernel let the user know that the checker is disabled, and when it is re-enabled again.

Quoted 6 lines

As the checker only gets disabled and re-enabled by user actions (starting and stoping the function graph tracer or the irqsoff tracer) it is fine to have a printk display that it is disabled or not.

Quoted 29 lines
---
 kernel/trace/trace_functions.c | 4 ++++
 1 file changed, 4 insertions(+)
kernel/trace/trace_functions.c +4 -0
index 0883069..dd59827 100644
@@ -569,6 +569,8 @@ void ftrace_unsafe_rcu_checker_disable(void)
 	atomic_inc(&ftrace_unsafe_rcu_disabled);
 	/* Make sure the update is seen immediately */
 	smp_wmb();
+	pr_info("Disabled FTRACE RCU checker (%pS)\n",
+		__builtin_return_address(0));
 }
 
 void ftrace_unsafe_rcu_checker_enable(void)
@@ -576,6 +578,8 @@ void ftrace_unsafe_rcu_checker_enable(void)
 	atomic_dec(&ftrace_unsafe_rcu_disabled);
 	/* Make sure the update is seen immediately */
 	smp_wmb();
+	pr_info("Enabled FTRACE RCU checker (%pS)\n",
+		__builtin_return_address(0));
 }
 
 static DEFINE_PER_CPU(unsigned long, ftrace_rcu_func);
Signature · 1 line
1.8.1.4
#9 lore raw

Re: [RFC][PATCH 01/18 v2] ftrace: Add hash list to save RCU unsafe functions

In reply to Steven Rostedt
Quoted 33 lines · Steven Rostedt
Quoted 4 lines · On Tue, 3 Sep 2013 15:18:08 -0700 "Paul E. McKenney"…
Quoted 1 line

Just found this bug. Strange that gcc never gave me a warning :-/

I can't give gcc too much trouble, as I also didn't give you an uninitialized-variable warning.

I was also chasing down a nasty bug that looked to be a pointer corruption somewhere. Still never found exactly where it happened, but it always happened with the following conditions:

synchronize_sched() was in progress

The ftrace_unsafe_callback() was preempted by an interrupt

lockdep was processing a lock

A crash would happen which had memory corruption involved. But the above seemed always to be in play.

Now, I changed the logic from disabling context level recursion to disabling recursion at all. That is, the original code had used a series of bits to test for recursion (via helper functions) that would allow for the callback to be preempted by an interrupt, and then be called again.

The new code sets a per_cpu flag, and will not allow the callback to recurse if it were preempted by an interrupt. No real need to allow for that anyway.

Quoted 7 lines

I can go and debug this further, because I'm nervous that lockdep may have some kind of bug that the function tracer can trigger. But I'm not too concerned about it.

Here's the diff of the new code against the previous code.

Paul, can I still keep all your acks and reviewed-bys on this?

Yep, but some questions below.

Thanx, Paul

Quoted 21 lines

-- Steve

kernel/trace/ftrace.c +1 -1
index 310b727..899c8c1 100644
@@ -1373,7 +1373,7 @@ ftrace_hash_rec_enable(struct ftrace_ops *ops, int filter_hash);
 
 static int ftrace_convert_size_to_bits(int size)
 {
-	int bits;
+	int bits = 0;
 
 	/*
 	 * Make the hash size about 1/2 the # found
kernel/trace/trace_functions.c +0 -0
index f5a9031..0883069 100644
@@ -561,16 +561,21 @@ static inline int init_func_cmd_traceon(void)
 

kernel/trace/trace_functions.c static inline int init_func_cmd_traceon(void) · line 571

Quoted 10 lines
kernel/trace/trace_functions.c +3 -0
 #ifdef CONFIG_FTRACE_UNSAFE_RCU_CHECKER
 
+static DEFINE_PER_CPU(int, ftrace_rcu_running);
 static atomic_t ftrace_unsafe_rcu_disabled;
 
 void ftrace_unsafe_rcu_checker_disable(void)
 {
 	atomic_inc(&ftrace_unsafe_rcu_disabled);
+	/* Make sure the update is seen immediately */
+	smp_wmb();
	smp_mb__after_atomic_inc()?

kernel/trace/trace_functions.c static inline int init_func_cmd_traceon(void) · line 578

Quoted 7 lines
kernel/trace/trace_functions.c +2 -0
 }
 
 void ftrace_unsafe_rcu_checker_enable(void)
 {
 	atomic_dec(&ftrace_unsafe_rcu_disabled);
+	/* Make sure the update is seen immediately */
+	smp_wmb();
	smp_mb__after_atomic_dec()?

kernel/trace/trace_functions.c static void · line 597

Quoted 11 lines
kernel/trace/trace_functions.c +2 -2
 }
 
 static DEFINE_PER_CPU(unsigned long, ftrace_rcu_func);
@@ -588,15 +593,14 @@ static void
 ftrace_unsafe_callback(unsigned long ip, unsigned long parent_ip,
 		       struct ftrace_ops *op, struct pt_regs *pt_regs)
 {
-	int bit;
-
+	/* Make sure we see disabled or not first */
+	smp_rmb();
	smp_mb__before_atomic_inc()?
Quoted 29 lines
kernel/trace/trace_functions.c +4 -3
 	if (atomic_read(&ftrace_unsafe_rcu_disabled))
 		return;
 
 	preempt_disable_notrace();
 
-	bit = trace_test_and_set_recursion(TRACE_FTRACE_START, TRACE_FTRACE_MAX);
-	if (bit < 0)
+	if (this_cpu_read(ftrace_rcu_running))
 		goto out;
 
 	if (WARN_ONCE(ftrace_rcu_unsafe(ip),
@@ -604,13 +608,15 @@ ftrace_unsafe_callback(unsigned long ip, unsigned long parent_ip,
 		      (void *)ip))
 		goto out;
 
+	this_cpu_write(ftrace_rcu_running, 1);
 	this_cpu_write(ftrace_rcu_func, ip);
+
 	/* Should trigger a RCU splat if called from unsafe RCU function */
 	rcu_read_lock();
 	rcu_read_unlock();
 	this_cpu_write(ftrace_rcu_func, 0);
 
-	trace_clear_recursion(bit);
+	this_cpu_write(ftrace_rcu_running, 0);
  out:
 	preempt_enable_notrace();
 }
author maintainer
#10 lore raw

Re: [RFC][PATCH 01/18 v2] ftrace: Add hash list to save RCU unsafe functions

Quoted 34 lines · On Tue, 3 Sep 2013 18:24:04 -0700 "Paul E. McKenney"…
Quoted 1 line · Steven Rostedt

Paul, can I still keep all your acks and reviewed-bys on this?

Yep, but some questions below.

Thanx, Paul

Quoted 26 lines

-- Steve

kernel/trace/ftrace.c +1 -1
index 310b727..899c8c1 100644
@@ -1373,7 +1373,7 @@ ftrace_hash_rec_enable(struct ftrace_ops *ops, int filter_hash);
 
 static int ftrace_convert_size_to_bits(int size)
 {
-	int bits;
+	int bits = 0;
 
 	/*
 	 * Make the hash size about 1/2 the # found
kernel/trace/trace_functions.c +1 -0
index f5a9031..0883069 100644
@@ -561,16 +561,21 @@ static inline int init_func_cmd_traceon(void)
 
 #ifdef CONFIG_FTRACE_UNSAFE_RCU_CHECKER
 
+static DEFINE_PER_CPU(int, ftrace_rcu_running);
 static atomic_t ftrace_unsafe_rcu_disabled;
 
Quoted 7 lines

kernel/trace/trace_functions.c static inline int init_func_cmd_traceon(void) · line 571

Quoted 5 lines
kernel/trace/trace_functions.c +2 -0
 void ftrace_unsafe_rcu_checker_disable(void)
 {
 	atomic_inc(&ftrace_unsafe_rcu_disabled);
+	/* Make sure the update is seen immediately */
+	smp_wmb();
	smp_mb__after_atomic_inc()?

Yep.

Quoted 10 lines

kernel/trace/trace_functions.c static inline int init_func_cmd_traceon(void) · line 578

Quoted 8 lines
kernel/trace/trace_functions.c +2 -0
 }
 
 void ftrace_unsafe_rcu_checker_enable(void)
 {
 	atomic_dec(&ftrace_unsafe_rcu_disabled);
+	/* Make sure the update is seen immediately */
+	smp_wmb();
	smp_mb__after_atomic_dec()?

Yep.

Quoted 14 lines

kernel/trace/trace_functions.c static void · line 597

Quoted 12 lines
kernel/trace/trace_functions.c +2 -2
 }
 
 static DEFINE_PER_CPU(unsigned long, ftrace_rcu_func);
@@ -588,15 +593,14 @@ static void
 ftrace_unsafe_callback(unsigned long ip, unsigned long parent_ip,
 		       struct ftrace_ops *op, struct pt_regs *pt_regs)
 {
-	int bit;
-
+	/* Make sure we see disabled or not first */
+	smp_rmb();
	smp_mb__before_atomic_inc()?

Yep.

I'll update it and restart my tests.

Thanks!

-- Steve

Quoted 30 lines
Quoted 30 lines
kernel/trace/trace_functions.c +4 -3
 	if (atomic_read(&ftrace_unsafe_rcu_disabled))
 		return;
 
 	preempt_disable_notrace();
 
-	bit = trace_test_and_set_recursion(TRACE_FTRACE_START, TRACE_FTRACE_MAX);
-	if (bit < 0)
+	if (this_cpu_read(ftrace_rcu_running))
 		goto out;
 
 	if (WARN_ONCE(ftrace_rcu_unsafe(ip),
@@ -604,13 +608,15 @@ ftrace_unsafe_callback(unsigned long ip, unsigned long parent_ip,
 		      (void *)ip))
 		goto out;
 
+	this_cpu_write(ftrace_rcu_running, 1);
 	this_cpu_write(ftrace_rcu_func, ip);
+
 	/* Should trigger a RCU splat if called from unsafe RCU function */
 	rcu_read_lock();
 	rcu_read_unlock();
 	this_cpu_write(ftrace_rcu_func, 0);
 
-	trace_clear_recursion(bit);
+	this_cpu_write(ftrace_rcu_running, 0);
  out:
 	preempt_enable_notrace();
 }
author maintainer
#11 lore raw

Re: [RFC][PATCH 01/18 v2] ftrace: Add hash list to save RCU unsafe functions

Quoted 38 lines · On Tue, 3 Sep 2013 21:51:52 -0400 Steven Rostedt <[email protected]> wrote:
Quoted 7 lines

kernel/trace/trace_functions.c static inline int init_func_cmd_traceon(void) · line 571

Quoted 5 lines

void ftrace_unsafe_rcu_checker_disable(void)
{

kernel/trace/trace_functions.c +2 -0
 	atomic_inc(&ftrace_unsafe_rcu_disabled);
+	/* Make sure the update is seen immediately */
+	smp_wmb();
	smp_mb__after_atomic_inc()?

Yep.

Quoted 10 lines

kernel/trace/trace_functions.c static inline int init_func_cmd_traceon(void) · line 578

Quoted 8 lines

}

void ftrace_unsafe_rcu_checker_enable(void)
{

kernel/trace/trace_functions.c +2 -0
 	atomic_dec(&ftrace_unsafe_rcu_disabled);
+	/* Make sure the update is seen immediately */
+	smp_wmb();
	smp_mb__after_atomic_dec()?

Yep.

Quoted 14 lines

kernel/trace/trace_functions.c static void · line 597

Quoted 12 lines

}

static DEFINE_PER_CPU(unsigned long, ftrace_rcu_func);

kernel/trace/trace_functions.c +2 -2
@@ -588,15 +593,14 @@ static void
 ftrace_unsafe_callback(unsigned long ip, unsigned long parent_ip,
 		       struct ftrace_ops *op, struct pt_regs *pt_regs)
 {
-	int bit;
-
+	/* Make sure we see disabled or not first */
+	smp_rmb();
	smp_mb__before_atomic_inc()?
Quoted 4 lines

Yep.

I'll update it and restart my tests.

Although, this will punish archs that need the mb(), as IIUC, smp_mb() is heavier weight than smp_wmb() or smp_rmb().

-- Steve

author maintainer
#12 lore raw

Re: [RFC][PATCH 01/18 v2] ftrace: Add hash list to save RCU unsafe functions

In reply to Paul E. McKenney
Quoted 12 lines · On Tue, 3 Sep 2013 18:24:04 -0700 "Paul E. McKenney"…

kernel/trace/trace_functions.c static void · line 597

Quoted 9 lines

static DEFINE_PER_CPU(unsigned long, ftrace_rcu_func);

kernel/trace/trace_functions.c +2 -2
@@ -588,15 +593,14 @@ static void
 ftrace_unsafe_callback(unsigned long ip, unsigned long parent_ip,
 		       struct ftrace_ops *op, struct pt_regs *pt_regs)
 {
-	int bit;
-
+	/* Make sure we see disabled or not first */
+	smp_rmb();
	smp_mb__before_atomic_inc()?

Ah, but this is before an atomic_read(), and not an atomic_inc(), thus the normal smp_rmb() is still required.

-- Steve

Quoted 5 lines
Quoted 5 lines
kernel/trace/trace_functions.c +0 -0
 	if (atomic_read(&ftrace_unsafe_rcu_disabled))
 		return;
 
 	preempt_disable_notrace();
 
author maintainer
#13 lore raw

Re: [RFC][PATCH 01/18 v2] ftrace: Add hash list to save RCU unsafe functions

Quoted 17 lines · On Tue, 3 Sep 2013 22:01:15 -0400 Steven Rostedt <[email protected]> wrote:
Quoted 12 lines · On Tue, 3 Sep 2013 18:24:04 -0700 "Paul E. McKenney"…

Review static void · line 597

Quoted 9 lines

static DEFINE_PER_CPU(unsigned long, ftrace_rcu_func);

(quoted diff) +2 -2
@@ -588,15 +593,14 @@ static void
 ftrace_unsafe_callback(unsigned long ip, unsigned long parent_ip,
 		       struct ftrace_ops *op, struct pt_regs *pt_regs)
 {
-	int bit;
-
+	/* Make sure we see disabled or not first */
+	smp_rmb();
	smp_mb__before_atomic_inc()?
Quoted 3 lines

Ah, but this is before an atomic_read(), and not an atomic_inc(), thus the normal smp_rmb() is still required.

Here's the changes against this one:

kernel/trace/trace_functions.c +2 -2
index cdcf187..9e6902a 100644
@@ -569,14 +569,14 @@ void ftrace_unsafe_rcu_checker_disable(void)
 {
 	atomic_inc(&ftrace_unsafe_rcu_disabled);
 	/* Make sure the update is seen immediately */
-	smp_wmb();
+	smp_mb__after_atomic_inc();
 }
 
 void ftrace_unsafe_rcu_checker_enable(void)
 {
 	atomic_dec(&ftrace_unsafe_rcu_disabled);
 	/* Make sure the update is seen immediately */
-	smp_wmb();
+	smp_mb__after_atomic_dec();
 }
 
 static void

Which is nice, because the smp_mb() are now in the really slow path.

-- Steve

#14 lore raw

Re: [RFC][PATCH 01/18 v2] ftrace: Add hash list to save RCU unsafe functions

Quoted 50 lines · Steven Rostedt
Quoted 17 lines · On Tue, 3 Sep 2013 22:01:15 -0400 Steven Rostedt <[email protected]> wrote:
Quoted 12 lines · On Tue, 3 Sep 2013 18:24:04 -0700 "Paul E. McKenney"…

Review static void · line 597

Quoted 9 lines

static DEFINE_PER_CPU(unsigned long, ftrace_rcu_func);

(quoted diff) +2 -2
@@ -588,15 +593,14 @@ static void
 ftrace_unsafe_callback(unsigned long ip, unsigned long parent_ip,
 		       struct ftrace_ops *op, struct pt_regs *pt_regs)
 {
-	int bit;
-
+	/* Make sure we see disabled or not first */
+	smp_rmb();
	smp_mb__before_atomic_inc()?
Quoted 3 lines

Ah, but this is before an atomic_read(), and not an atomic_inc(), thus the normal smp_rmb() is still required.

Here's the changes against this one:

kernel/trace/trace_functions.c +2 -2
index cdcf187..9e6902a 100644
@@ -569,14 +569,14 @@ void ftrace_unsafe_rcu_checker_disable(void)
 {
 	atomic_inc(&ftrace_unsafe_rcu_disabled);
 	/* Make sure the update is seen immediately */
-	smp_wmb();
+	smp_mb__after_atomic_inc();
 }
 
 void ftrace_unsafe_rcu_checker_enable(void)
 {
 	atomic_dec(&ftrace_unsafe_rcu_disabled);
 	/* Make sure the update is seen immediately */
-	smp_wmb();
+	smp_mb__after_atomic_dec();
 }
 
 static void
Quoted 1 line

Which is nice, because the smp_mb() are now in the really slow path.

Looks good!

But now that I look at it more carefully, including the comments... The smp_mb__after_atomic_dec() isn't going to make the update be seen faster -- instead, it will guarantee that if some other CPU sees this CPU's later write, then that CPU will also see the results of the atomic_dec().

Thanx, Paul

author maintainer
#15 lore raw

Re: [RFC][PATCH 01/18 v2] ftrace: Add hash list to save RCU unsafe functions

Quoted 55 lines · On Tue, 3 Sep 2013 21:18:28 -0700 "Paul E. McKenney"…
Quoted 50 lines · Steven Rostedt
Quoted 17 lines · On Tue, 3 Sep 2013 22:01:15 -0400 Steven Rostedt <[email protected]> wrote:
Quoted 12 lines · On Tue, 3 Sep 2013 18:24:04 -0700 "Paul E. McKenney"…

Review static void · line 597

Quoted 9 lines

static DEFINE_PER_CPU(unsigned long, ftrace_rcu_func);

(quoted diff) +2 -2
@@ -588,15 +593,14 @@ static void
 ftrace_unsafe_callback(unsigned long ip, unsigned long parent_ip,
 		       struct ftrace_ops *op, struct pt_regs *pt_regs)
 {
-	int bit;
-
+	/* Make sure we see disabled or not first */
+	smp_rmb();
	smp_mb__before_atomic_inc()?
Quoted 3 lines

Ah, but this is before an atomic_read(), and not an atomic_inc(), thus the normal smp_rmb() is still required.

Here's the changes against this one:

kernel/trace/trace_functions.c +2 -2
index cdcf187..9e6902a 100644
@@ -569,14 +569,14 @@ void ftrace_unsafe_rcu_checker_disable(void)
 {
 	atomic_inc(&ftrace_unsafe_rcu_disabled);
 	/* Make sure the update is seen immediately */
-	smp_wmb();
+	smp_mb__after_atomic_inc();
 }
 
 void ftrace_unsafe_rcu_checker_enable(void)
 {
 	atomic_dec(&ftrace_unsafe_rcu_disabled);
 	/* Make sure the update is seen immediately */
-	smp_wmb();
+	smp_mb__after_atomic_dec();
 }
 
 static void
Quoted 1 line

Which is nice, because the smp_mb() are now in the really slow path.

Looks good!

Quoted 5 lines

But now that I look at it more carefully, including the comments... The smp_mb__after_atomic_dec() isn't going to make the update be seen faster -- instead, it will guarantee that if some other CPU sees this CPU's later write, then that CPU will also see the results of the atomic_dec().

I don't need to have it seen "faster", just before anything that comes next after the call to ftrace_unsafe_rcu_checker_disable(). That's what I meant by the comment. In other words, don't delay this write, it needs to go first.

-- Steve

#16 lore raw

Re: [RFC][PATCH 01/18 v2] ftrace: Add hash list to save RCU unsafe functions

In reply to Steven Rostedt
Quoted 17 lines · Steven Rostedt
Quoted 12 lines · On Tue, 3 Sep 2013 18:24:04 -0700 "Paul E. McKenney"…

kernel/trace/trace_functions.c static void · line 597

Quoted 9 lines

static DEFINE_PER_CPU(unsigned long, ftrace_rcu_func);

kernel/trace/trace_functions.c +2 -2
@@ -588,15 +593,14 @@ static void
 ftrace_unsafe_callback(unsigned long ip, unsigned long parent_ip,
 		       struct ftrace_ops *op, struct pt_regs *pt_regs)
 {
-	int bit;
-
+	/* Make sure we see disabled or not first */
+	smp_rmb();
	smp_mb__before_atomic_inc()?
Quoted 2 lines

Ah, but this is before an atomic_read(), and not an atomic_inc(), thus the normal smp_rmb() is still required.

Good point, color me blind, dazed, and confused.

Thanx, Paul

Quoted 8 lines

-- Steve

Quoted 5 lines
Quoted 5 lines
kernel/trace/trace_functions.c +0 -0
 	if (atomic_read(&ftrace_unsafe_rcu_disabled))
 		return;
 
 	preempt_disable_notrace();
 
author maintainer
#17 lore raw

RFC PATCH v2 2/18 ftrace: Do not set ftrace records for unsafe RCU when not allowed

In reply to Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

For the ftrace_ops that use RCU read locks, and can not be called by unsafe RCU functions (those outside of RCU tracking), have them not update the RCU unsafe function records when they are being registered or unregistered.

The ftrace function records store a counter of all the ftrace_ops callbacks that are hooked to the function the record represents. As unsafe RCU functions do not call callbacks that do not specify that they do not use RCU, do not update those records.

Cc Jiri Olsa <[email protected]>
Cc Paul E. McKenney <[email protected]>
---
 kernel/trace/ftrace.c |   19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)
kernel/trace/ftrace.c +17 -2
index 3750360..d61f431 100644
@@ -1168,6 +1168,12 @@ static struct ftrace_page *ftrace_new_pgs;
 static struct ftrace_page	*ftrace_pages_start;
 static struct ftrace_page	*ftrace_pages;
 
+/*
+ * Hash of functions that are not safe to be called by
+ * callbacks that use RCU read locks.
+ */
+static struct ftrace_hash *ftrace_unsafe_rcu;
+
 static bool ftrace_hash_empty(struct ftrace_hash *hash)
 {
 	return !hash || !hash->count;
@@ -1638,6 +1644,7 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops,
 {
 	struct ftrace_hash *hash;
 	struct ftrace_hash *other_hash;
+	struct ftrace_hash *rcu_hash;
 	struct ftrace_page *pg;
 	struct dyn_ftrace *rec;
 	int count = 0;
@@ -1647,6 +1654,12 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops,
 	if (!(ops->flags & FTRACE_OPS_FL_ENABLED))
 		return;
 
+	/* Ignore rcu unsafe functions unless ops handles them */
+	if (ops->flags & FTRACE_OPS_FL_RCU_SAFE)
+		rcu_hash = NULL;
+	else
+		rcu_hash = ftrace_unsafe_rcu;
+
 	/*
 	 * In the filter_hash case:
 	 *   If the count is zero, we update all records.
@@ -1680,6 +1693,10 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops,
 		int in_hash = 0;
 		int match = 0;
 
+		/* Ignore all in the rcu unsafe hash */
+		if (ftrace_lookup_ip(rcu_hash, rec->ip))
+			continue;
+
 		if (all) {
 			/*
 			 * Only the filter_hash affects all records.
@@ -4291,8 +4308,6 @@ struct notifier_block ftrace_module_exit_nb = {
 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;
Signature · 1 line
1.7.10.4
Acked-by on v2 2/18
#18 lore raw

Re: [RFC][PATCH 02/18 v2] ftrace: Do not set ftrace records for unsafe RCU when not allowed

Quoted 7 lines · Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

For the ftrace_ops that use RCU read locks, and can not be called by unsafe RCU functions (those outside of RCU tracking), have them not update the RCU unsafe function records when they are being registered or unregistered.

Quoted 8 lines

The ftrace function records store a counter of all the ftrace_ops callbacks that are hooked to the function the record represents. As unsafe RCU functions do not call callbacks that do not specify that they do not use RCU, do not update those records.

Cc Jiri Olsa <[email protected]>
Cc Paul E. McKenney <[email protected]>
Quoted 66 lines
---
 kernel/trace/ftrace.c |   19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)
kernel/trace/ftrace.c +17 -2
index 3750360..d61f431 100644
@@ -1168,6 +1168,12 @@ static struct ftrace_page *ftrace_new_pgs;
 static struct ftrace_page	*ftrace_pages_start;
 static struct ftrace_page	*ftrace_pages;
 
+/*
+ * Hash of functions that are not safe to be called by
+ * callbacks that use RCU read locks.
+ */
+static struct ftrace_hash *ftrace_unsafe_rcu;
+
 static bool ftrace_hash_empty(struct ftrace_hash *hash)
 {
 	return !hash || !hash->count;
@@ -1638,6 +1644,7 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops,
 {
 	struct ftrace_hash *hash;
 	struct ftrace_hash *other_hash;
+	struct ftrace_hash *rcu_hash;
 	struct ftrace_page *pg;
 	struct dyn_ftrace *rec;
 	int count = 0;
@@ -1647,6 +1654,12 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops,
 	if (!(ops->flags & FTRACE_OPS_FL_ENABLED))
 		return;
 
+	/* Ignore rcu unsafe functions unless ops handles them */
+	if (ops->flags & FTRACE_OPS_FL_RCU_SAFE)
+		rcu_hash = NULL;
+	else
+		rcu_hash = ftrace_unsafe_rcu;
+
 	/*
 	 * In the filter_hash case:
 	 *   If the count is zero, we update all records.
@@ -1680,6 +1693,10 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops,
 		int in_hash = 0;
 		int match = 0;
 
+		/* Ignore all in the rcu unsafe hash */
+		if (ftrace_lookup_ip(rcu_hash, rec->ip))
+			continue;
+
 		if (all) {
 			/*
 			 * Only the filter_hash affects all records.
@@ -4291,8 +4308,6 @@ struct notifier_block ftrace_module_exit_nb = {
 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;
Signature · 1 line
1.7.10.4
author maintainer
#19 lore raw

RFC PATCH v2 3/18 ftrace: Set ftrace internal function tracing RCU safe

In reply to Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

Since none of the internal ftrace function tracing uses RCU in their callbacks, it is OK to set the global_ops (the one that they all use) to RCU safe.

Cc Jiri Olsa <[email protected]>
Cc Paul E. McKenney <[email protected]>
---
 kernel/trace/ftrace.c |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
kernel/trace/ftrace.c +3 -1
index d61f431..a45deaa 100644
@@ -1146,7 +1146,9 @@ static struct ftrace_ops global_ops = {
 	.func			= ftrace_stub,
 	.notrace_hash		= EMPTY_HASH,
 	.filter_hash		= EMPTY_HASH,
-	.flags			= FTRACE_OPS_FL_RECURSION_SAFE | FTRACE_OPS_FL_INITIALIZED,
+	.flags			= FTRACE_OPS_FL_RECURSION_SAFE |
+				  FTRACE_OPS_FL_INITIALIZED |
+				  FTRACE_OPS_FL_RCU_SAFE,
 	INIT_REGEX_LOCK(global_ops)
 };
 
Signature · 1 line
1.7.10.4
Acked-by on v2 3/18
#20 lore raw

Re: [RFC][PATCH 03/18 v2] ftrace: Set ftrace internal function tracing RCU safe

Quoted 9 lines · Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

Since none of the internal ftrace function tracing uses RCU in their callbacks, it is OK to set the global_ops (the one that they all use) to RCU safe.

Cc Jiri Olsa <[email protected]>
Cc Paul E. McKenney <[email protected]>
Quoted 23 lines
---
 kernel/trace/ftrace.c |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
kernel/trace/ftrace.c +3 -1
index d61f431..a45deaa 100644
@@ -1146,7 +1146,9 @@ static struct ftrace_ops global_ops = {
 	.func			= ftrace_stub,
 	.notrace_hash		= EMPTY_HASH,
 	.filter_hash		= EMPTY_HASH,
-	.flags			= FTRACE_OPS_FL_RECURSION_SAFE | FTRACE_OPS_FL_INITIALIZED,
+	.flags			= FTRACE_OPS_FL_RECURSION_SAFE |
+				  FTRACE_OPS_FL_INITIALIZED |
+				  FTRACE_OPS_FL_RCU_SAFE,
 	INIT_REGEX_LOCK(global_ops)
 };
 
Signature · 1 line
1.7.10.4
Acked-by on v2 3/18
#21 lore raw

Re: [RFC][PATCH 03/18 v2] ftrace: Set ftrace internal function tracing RCU safe

In reply to Steven Rostedt
Quoted 9 lines · Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

Since none of the internal ftrace function tracing uses RCU in their callbacks, it is OK to set the global_ops (the one that they all use) to RCU safe.

Cc Jiri Olsa <[email protected]>
Cc Paul E. McKenney <[email protected]>
Quoted 23 lines
---
 kernel/trace/ftrace.c |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
kernel/trace/ftrace.c +3 -1
index d61f431..a45deaa 100644
@@ -1146,7 +1146,9 @@ static struct ftrace_ops global_ops = {
 	.func			= ftrace_stub,
 	.notrace_hash		= EMPTY_HASH,
 	.filter_hash		= EMPTY_HASH,
-	.flags			= FTRACE_OPS_FL_RECURSION_SAFE | FTRACE_OPS_FL_INITIALIZED,
+	.flags			= FTRACE_OPS_FL_RECURSION_SAFE |
+				  FTRACE_OPS_FL_INITIALIZED |
+				  FTRACE_OPS_FL_RCU_SAFE,
 	INIT_REGEX_LOCK(global_ops)
 };
 
Signature · 1 line
1.7.10.4
author maintainer
#22 lore raw

Re: [RFC][PATCH 03/18 v2] ftrace: Set ftrace internal function tracing RCU safe

Quoted 7 lines · On Sat, 31 Aug 2013 12:44:31 -0700 "Paul E. McKenney"…
Quoted 6 lines · Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

Since none of the internal ftrace function tracing uses RCU in their callbacks, it is OK to set the global_ops (the one that they all use) to RCU safe.

Quoted 5 lines
Quoted 3 lines
Cc Jiri Olsa <[email protected]>
Cc Paul E. McKenney <[email protected]>

You must have liked this patch so much... that you acked it twice ;-)

-- Steve

Quoted 24 lines
Quoted 24 lines
---
 kernel/trace/ftrace.c |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
kernel/trace/ftrace.c +3 -1
index d61f431..a45deaa 100644
@@ -1146,7 +1146,9 @@ static struct ftrace_ops global_ops = {
 	.func			= ftrace_stub,
 	.notrace_hash		= EMPTY_HASH,
 	.filter_hash		= EMPTY_HASH,
-	.flags			= FTRACE_OPS_FL_RECURSION_SAFE | FTRACE_OPS_FL_INITIALIZED,
+	.flags			= FTRACE_OPS_FL_RECURSION_SAFE |
+				  FTRACE_OPS_FL_INITIALIZED |
+				  FTRACE_OPS_FL_RCU_SAFE,
 	INIT_REGEX_LOCK(global_ops)
 };
 
Signature · 1 line
1.7.10.4
#23 lore raw

Re: [RFC][PATCH 03/18 v2] ftrace: Set ftrace internal function tracing RCU safe

Quoted 10 lines · Steven Rostedt
Quoted 7 lines · On Sat, 31 Aug 2013 12:44:31 -0700 "Paul E. McKenney"…
Quoted 6 lines · Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

Since none of the internal ftrace function tracing uses RCU in their callbacks, it is OK to set the global_ops (the one that they all use) to RCU safe.

Quoted 7 lines
Quoted 5 lines
Quoted 3 lines
Cc Jiri Olsa <[email protected]>
Cc Paul E. McKenney <[email protected]>

You must have liked this patch so much... that you acked it twice ;-)

Better safe than sorry? No, that doesn't sound quite right...

Thanx, Paul

Quoted 27 lines

-- Steve

Quoted 24 lines
Quoted 24 lines
---
 kernel/trace/ftrace.c |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
kernel/trace/ftrace.c +3 -1
index d61f431..a45deaa 100644
@@ -1146,7 +1146,9 @@ static struct ftrace_ops global_ops = {
 	.func			= ftrace_stub,
 	.notrace_hash		= EMPTY_HASH,
 	.filter_hash		= EMPTY_HASH,
-	.flags			= FTRACE_OPS_FL_RECURSION_SAFE | FTRACE_OPS_FL_INITIALIZED,
+	.flags			= FTRACE_OPS_FL_RECURSION_SAFE |
+				  FTRACE_OPS_FL_INITIALIZED |
+				  FTRACE_OPS_FL_RCU_SAFE,
 	INIT_REGEX_LOCK(global_ops)
 };
 
Signature · 1 line
1.7.10.4
author maintainer
#24 lore raw

RFC PATCH v2 4/18 ftrace: Add test for ops against unsafe RCU functions in callback

In reply to Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

When more than one ftrace_ops is registered, the list function is is used to call all registered functions. It uses the filter and notrace hashes from the ftrace_ops to determine if the corresponding callback should be called or not.

Currently, it does not take into account for RCU unsafe functions. If multiple functions are registered, and an RCU safe callback is used on a RCU unsafe function, and the RCU unsafe callback says to trace all functions, it will end up tracing this RCU unsafe function and still suffer the problems when using RCU when RCU tracing is off.

Add a test to the multiple ops list function to test if the ops in question can use an RCU unsafe function or not, and if the function being traced happens to be an RCU unsafe function.

Cc Jiri Olsa <[email protected]>
Cc Paul E. McKenney <[email protected]>
---
 kernel/trace/ftrace.c |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
kernel/trace/ftrace.c +3 -1
index a45deaa..06504b2 100644
@@ -1480,7 +1480,9 @@ ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip, void *regs)
 	if ((ftrace_hash_empty(filter_hash) ||
 	     ftrace_lookup_ip(filter_hash, ip)) &&
 	    (ftrace_hash_empty(notrace_hash) ||
-	     !ftrace_lookup_ip(notrace_hash, ip)))
+	     !ftrace_lookup_ip(notrace_hash, ip)) &&
+	    (ops->flags & FTRACE_OPS_FL_RCU_SAFE ||
+	     !ftrace_lookup_ip(ftrace_unsafe_rcu, ip)))
 		ret = 1;
 	else
 		ret = 0;
Signature · 1 line
1.7.10.4
Acked-by on v2 4/18
#25 lore raw

Re: [RFC][PATCH 04/18 v2] ftrace: Add test for ops against unsafe RCU functions in callback

Quoted 14 lines · Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

When more than one ftrace_ops is registered, the list function is is used to call all registered functions. It uses the filter and notrace hashes from the ftrace_ops to determine if the corresponding callback should be called or not.

Currently, it does not take into account for RCU unsafe functions. If multiple functions are registered, and an RCU safe callback is used on a RCU unsafe function, and the RCU unsafe callback says to trace all functions, it will end up tracing this RCU unsafe function and still suffer the problems when using RCU when RCU tracing is off.

Quoted 7 lines

Add a test to the multiple ops list function to test if the ops in question can use an RCU unsafe function or not, and if the function being traced happens to be an RCU unsafe function.

Cc Jiri Olsa <[email protected]>
Cc Paul E. McKenney <[email protected]>
Quoted 23 lines
---
 kernel/trace/ftrace.c |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
kernel/trace/ftrace.c +3 -1
index a45deaa..06504b2 100644
@@ -1480,7 +1480,9 @@ ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip, void *regs)
 	if ((ftrace_hash_empty(filter_hash) ||
 	     ftrace_lookup_ip(filter_hash, ip)) &&
 	    (ftrace_hash_empty(notrace_hash) ||
-	     !ftrace_lookup_ip(notrace_hash, ip)))
+	     !ftrace_lookup_ip(notrace_hash, ip)) &&
+	    (ops->flags & FTRACE_OPS_FL_RCU_SAFE ||
+	     !ftrace_lookup_ip(ftrace_unsafe_rcu, ip)))
 		ret = 1;
 	else
 		ret = 0;
Signature · 1 line
1.7.10.4
author maintainer
#26 lore raw

RFC PATCH v2 5/18 ftrace: Do not display non safe RCU functions in available_filter_functions

In reply to Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

As available_filter_functions file displays functions that are generally available for tracing, do not show the ones that are RCU unsafe. Otherwise it may be confusing for perf users to see these functions in this file but not be able to trace them.

Cc Jiri Olsa <[email protected]>
Cc Paul E. McKenney <[email protected]>
---
 include/linux/ftrace.h |    1 +
 kernel/trace/ftrace.c  |    6 +++++-
 2 files changed, 6 insertions(+), 1 deletion(-)
include/linux/ftrace.h +1 -0
index 1d17a82..4709264 100644
@@ -411,6 +411,7 @@ enum {
 	FTRACE_ITER_DO_HASH	= (1 << 3),
 	FTRACE_ITER_HASH	= (1 << 4),
 	FTRACE_ITER_ENABLED	= (1 << 5),
+	FTRACE_ITER_NO_UNSAFE	= (1 << 6),
 };
 
 void arch_ftrace_update_code(int command);
kernel/trace/ftrace.c +5 -1
index 06504b2..be87ac9 100644
@@ -2645,7 +2645,10 @@ t_next(struct seq_file *m, void *v, loff_t *pos)
 		     !ftrace_lookup_ip(ops->notrace_hash, rec->ip)) ||
 
 		    ((iter->flags & FTRACE_ITER_ENABLED) &&
-		     !(rec->flags & FTRACE_FL_ENABLED))) {
+		     !(rec->flags & FTRACE_FL_ENABLED)) ||
+
+		    ((iter->flags & FTRACE_ITER_NO_UNSAFE) &&
+		     ftrace_lookup_ip(ftrace_unsafe_rcu, rec->ip))) {
 
 			rec = NULL;
 			goto retry;
@@ -2773,6 +2776,7 @@ ftrace_avail_open(struct inode *inode, struct file *file)
 	iter = __seq_open_private(file, &show_ftrace_seq_ops, sizeof(*iter));
 	if (iter) {
 		iter->pg = ftrace_pages_start;
+		iter->flags = FTRACE_ITER_NO_UNSAFE;
 		iter->ops = &global_ops;
 	}
 
Signature · 1 line
1.7.10.4
#27 lore raw

Re: [RFC][PATCH 05/18 v2] ftrace: Do not display non safe RCU functions in available_filter_functions

Quoted 32 lines · Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

As available_filter_functions file displays functions that are generally available for tracing, do not show the ones that are RCU unsafe. Otherwise it may be confusing for perf users to see these functions in this file but not be able to trace them.

Cc Jiri Olsa <[email protected]>
Cc Paul E. McKenney <[email protected]>
---
 include/linux/ftrace.h |    1 +
 kernel/trace/ftrace.c  |    6 +++++-
 2 files changed, 6 insertions(+), 1 deletion(-)
include/linux/ftrace.h +1 -0
index 1d17a82..4709264 100644
@@ -411,6 +411,7 @@ enum {
 	FTRACE_ITER_DO_HASH	= (1 << 3),
 	FTRACE_ITER_HASH	= (1 << 4),
 	FTRACE_ITER_ENABLED	= (1 << 5),
+	FTRACE_ITER_NO_UNSAFE	= (1 << 6),
 };
 
 void arch_ftrace_update_code(int command);
kernel/trace/ftrace.c +0 -0
index 06504b2..be87ac9 100644

kernel/trace/ftrace.c t_next(struct seq_file *m, void *v, loff_t *pos) · line 2649

Quoted 6 lines
kernel/trace/ftrace.c +2 -1
@@ -2645,7 +2645,10 @@ t_next(struct seq_file *m, void *v, loff_t *pos)
 		     !ftrace_lookup_ip(ops->notrace_hash, rec->ip)) ||
 
 		    ((iter->flags & FTRACE_ITER_ENABLED) &&
-		     !(rec->flags & FTRACE_FL_ENABLED))) {
+		     !(rec->flags & FTRACE_FL_ENABLED)) ||
+

OK, I'll bite... Why the blank line?

Thanx, Paul

Quoted 17 lines
kernel/trace/ftrace.c +3 -0
+		    ((iter->flags & FTRACE_ITER_NO_UNSAFE) &&
+		     ftrace_lookup_ip(ftrace_unsafe_rcu, rec->ip))) {
 
 			rec = NULL;
 			goto retry;
@@ -2773,6 +2776,7 @@ ftrace_avail_open(struct inode *inode, struct file *file)
 	iter = __seq_open_private(file, &show_ftrace_seq_ops, sizeof(*iter));
 	if (iter) {
 		iter->pg = ftrace_pages_start;
+		iter->flags = FTRACE_ITER_NO_UNSAFE;
 		iter->ops = &global_ops;
 	}
 
Signature · 1 line
1.7.10.4
author maintainer
#28 lore raw

Re: [RFC][PATCH 05/18 v2] ftrace: Do not display non safe RCU functions in available_filter_functions

Quoted 8 lines · Paul E. McKenney
Quoted 8 lines

void arch_ftrace_update_code(int command);

kernel/trace/ftrace.c +0 -0
index 06504b2..be87ac9 100644
@@ -2645,7 +2645,10 @@ t_next(struct seq_file *m, void *v, loff_t *pos)
 		     !ftrace_lookup_ip(ops->notrace_hash, rec->ip)) ||
 
Quoted 6 lines

kernel/trace/ftrace.c t_next(struct seq_file *m, void *v, loff_t *pos) · line 2649

Quoted 4 lines
kernel/trace/ftrace.c +2 -1
 		    ((iter->flags & FTRACE_ITER_ENABLED) &&
-		     !(rec->flags & FTRACE_FL_ENABLED))) {
+		     !(rec->flags & FTRACE_FL_ENABLED)) ||
+

OK, I'll bite... Why the blank line?

For readability. Here's the full if statement:

                if (((iter->flags & FTRACE_ITER_FILTER) &&
                     !(ftrace_lookup_ip(ops->filter_hash, rec->ip))) ||

                    ((iter->flags & FTRACE_ITER_NOTRACE) &&
                     !ftrace_lookup_ip(ops->notrace_hash, rec->ip)) ||

                    ((iter->flags & FTRACE_ITER_ENABLED) &&
                     !(rec->flags & FTRACE_FL_ENABLED)) ||

                    ((iter->flags & FTRACE_ITER_UNSAFE_ONLY) &&
                     !ftrace_lookup_ip(ftrace_unsafe_rcu, rec->ip)) ||

                    ((iter->flags & FTRACE_ITER_NO_UNSAFE) &&
                     ftrace_lookup_ip(ftrace_unsafe_rcu, rec->ip))) {

They are grouped in pairs.

-- Steve

Quoted 20 lines

Thanx, Paul

Quoted 17 lines
kernel/trace/ftrace.c +3 -0
+		    ((iter->flags & FTRACE_ITER_NO_UNSAFE) &&
+		     ftrace_lookup_ip(ftrace_unsafe_rcu, rec->ip))) {
 
 			rec = NULL;
 			goto retry;
@@ -2773,6 +2776,7 @@ ftrace_avail_open(struct inode *inode, struct file *file)
 	iter = __seq_open_private(file, &show_ftrace_seq_ops, sizeof(*iter));
 	if (iter) {
 		iter->pg = ftrace_pages_start;
+		iter->flags = FTRACE_ITER_NO_UNSAFE;
 		iter->ops = &global_ops;
 	}
 
Signature · 1 line
1.7.10.4
#29 lore raw

Re: [RFC][PATCH 05/18 v2] ftrace: Do not display non safe RCU functions in available_filter_functions

Quoted 35 lines · Steven Rostedt
Quoted 8 lines · Paul E. McKenney
Quoted 8 lines

void arch_ftrace_update_code(int command);

kernel/trace/ftrace.c +0 -0
index 06504b2..be87ac9 100644
@@ -2645,7 +2645,10 @@ t_next(struct seq_file *m, void *v, loff_t *pos)
 		     !ftrace_lookup_ip(ops->notrace_hash, rec->ip)) ||
 
Quoted 6 lines

kernel/trace/ftrace.c t_next(struct seq_file *m, void *v, loff_t *pos) · line 2649

Quoted 4 lines
kernel/trace/ftrace.c +2 -1
 		    ((iter->flags & FTRACE_ITER_ENABLED) &&
-		     !(rec->flags & FTRACE_FL_ENABLED))) {
+		     !(rec->flags & FTRACE_FL_ENABLED)) ||
+

OK, I'll bite... Why the blank line?

For readability. Here's the full if statement:

                if (((iter->flags & FTRACE_ITER_FILTER) &&
                     !(ftrace_lookup_ip(ops->filter_hash, rec->ip))) ||

                    ((iter->flags & FTRACE_ITER_NOTRACE) &&
                     !ftrace_lookup_ip(ops->notrace_hash, rec->ip)) ||

                    ((iter->flags & FTRACE_ITER_ENABLED) &&
                     !(rec->flags & FTRACE_FL_ENABLED)) ||

                    ((iter->flags & FTRACE_ITER_UNSAFE_ONLY) &&
                     !ftrace_lookup_ip(ftrace_unsafe_rcu, rec->ip)) ||

                    ((iter->flags & FTRACE_ITER_NO_UNSAFE) &&
                     ftrace_lookup_ip(ftrace_unsafe_rcu, rec->ip))) {
Quoted 1 line

They are grouped in pairs.

Fair enough!

Thanx, Paul

Quoted 24 lines

-- Steve

Quoted 20 lines

Thanx, Paul

Quoted 17 lines
kernel/trace/ftrace.c +3 -0
+		    ((iter->flags & FTRACE_ITER_NO_UNSAFE) &&
+		     ftrace_lookup_ip(ftrace_unsafe_rcu, rec->ip))) {
 
 			rec = NULL;
 			goto retry;
@@ -2773,6 +2776,7 @@ ftrace_avail_open(struct inode *inode, struct file *file)
 	iter = __seq_open_private(file, &show_ftrace_seq_ops, sizeof(*iter));
 	if (iter) {
 		iter->pg = ftrace_pages_start;
+		iter->flags = FTRACE_ITER_NO_UNSAFE;
 		iter->ops = &global_ops;
 	}
 
Signature · 1 line
1.7.10.4
author maintainer
#30 lore raw

Re: [RFC][PATCH 05/18 v2] ftrace: Do not display non safe RCU functions in available_filter_functions

Quoted 32 lines · On Sat, 31 Aug 2013 13:54:30 -0700 "Paul E. McKenney"…
Quoted 31 lines · Steven Rostedt
Quoted 8 lines · Paul E. McKenney
Quoted 8 lines

void arch_ftrace_update_code(int command);

kernel/trace/ftrace.c +0 -0
index 06504b2..be87ac9 100644
@@ -2645,7 +2645,10 @@ t_next(struct seq_file *m, void *v, loff_t *pos)
 		     !ftrace_lookup_ip(ops->notrace_hash, rec->ip)) ||
 
Quoted 6 lines

kernel/trace/ftrace.c t_next(struct seq_file *m, void *v, loff_t *pos) · line 2649

Quoted 4 lines
kernel/trace/ftrace.c +2 -1
 		    ((iter->flags & FTRACE_ITER_ENABLED) &&
-		     !(rec->flags & FTRACE_FL_ENABLED))) {
+		     !(rec->flags & FTRACE_FL_ENABLED)) ||
+

OK, I'll bite... Why the blank line?

For readability. Here's the full if statement:

                if (((iter->flags & FTRACE_ITER_FILTER) &&
                     !(ftrace_lookup_ip(ops->filter_hash, rec->ip))) ||

                    ((iter->flags & FTRACE_ITER_NOTRACE) &&
                     !ftrace_lookup_ip(ops->notrace_hash, rec->ip)) ||

                    ((iter->flags & FTRACE_ITER_ENABLED) &&
                     !(rec->flags & FTRACE_FL_ENABLED)) ||

                    ((iter->flags & FTRACE_ITER_UNSAFE_ONLY) &&
                     !ftrace_lookup_ip(ftrace_unsafe_rcu, rec->ip)) ||
Quoted 7 lines
Quoted 5 lines
                    ((iter->flags & FTRACE_ITER_NO_UNSAFE) &&
                     ftrace_lookup_ip(ftrace_unsafe_rcu, rec->ip))) {

They are grouped in pairs.

Fair enough!

Can I take this as an Acked-by?

-- Steve

Quoted 27 lines

Thanx, Paul

Quoted 24 lines

-- Steve

Quoted 20 lines

Thanx, Paul

Quoted 17 lines
kernel/trace/ftrace.c +3 -0
+		    ((iter->flags & FTRACE_ITER_NO_UNSAFE) &&
+		     ftrace_lookup_ip(ftrace_unsafe_rcu, rec->ip))) {
 
 			rec = NULL;
 			goto retry;
@@ -2773,6 +2776,7 @@ ftrace_avail_open(struct inode *inode, struct file *file)
 	iter = __seq_open_private(file, &show_ftrace_seq_ops, sizeof(*iter));
 	if (iter) {
 		iter->pg = ftrace_pages_start;
+		iter->flags = FTRACE_ITER_NO_UNSAFE;
 		iter->ops = &global_ops;
 	}
 
Signature · 1 line
1.7.10.4
#31 lore raw

Re: [RFC][PATCH 05/18 v2] ftrace: Do not display non safe RCU functions in available_filter_functions

Quoted 39 lines · Steven Rostedt
Quoted 36 lines · On Sat, 31 Aug 2013 13:54:30 -0700 "Paul E. McKenney"…
Quoted 35 lines · Steven Rostedt
Quoted 8 lines · Paul E. McKenney
Quoted 8 lines

void arch_ftrace_update_code(int command);

kernel/trace/ftrace.c +0 -0
index 06504b2..be87ac9 100644
@@ -2645,7 +2645,10 @@ t_next(struct seq_file *m, void *v, loff_t *pos)
 		     !ftrace_lookup_ip(ops->notrace_hash, rec->ip)) ||
 
Quoted 6 lines

kernel/trace/ftrace.c t_next(struct seq_file *m, void *v, loff_t *pos) · line 2649

Quoted 4 lines
kernel/trace/ftrace.c +2 -1
 		    ((iter->flags & FTRACE_ITER_ENABLED) &&
-		     !(rec->flags & FTRACE_FL_ENABLED))) {
+		     !(rec->flags & FTRACE_FL_ENABLED)) ||
+

OK, I'll bite... Why the blank line?

For readability. Here's the full if statement:

                if (((iter->flags & FTRACE_ITER_FILTER) &&
                     !(ftrace_lookup_ip(ops->filter_hash, rec->ip))) ||

                    ((iter->flags & FTRACE_ITER_NOTRACE) &&
                     !ftrace_lookup_ip(ops->notrace_hash, rec->ip)) ||

                    ((iter->flags & FTRACE_ITER_ENABLED) &&
                     !(rec->flags & FTRACE_FL_ENABLED)) ||

                    ((iter->flags & FTRACE_ITER_UNSAFE_ONLY) &&
                     !ftrace_lookup_ip(ftrace_unsafe_rcu, rec->ip)) ||

                    ((iter->flags & FTRACE_ITER_NO_UNSAFE) &&
                     ftrace_lookup_ip(ftrace_unsafe_rcu, rec->ip))) {
Quoted 5 lines
Quoted 3 lines
Quoted 1 line

They are grouped in pairs.

Fair enough!

Can I take this as an Acked-by?

Quoted 30 lines

-- Steve

Quoted 27 lines

Thanx, Paul

Quoted 24 lines

-- Steve

Quoted 20 lines

Thanx, Paul

Quoted 17 lines
kernel/trace/ftrace.c +3 -0
+		    ((iter->flags & FTRACE_ITER_NO_UNSAFE) &&
+		     ftrace_lookup_ip(ftrace_unsafe_rcu, rec->ip))) {
 
 			rec = NULL;
 			goto retry;
@@ -2773,6 +2776,7 @@ ftrace_avail_open(struct inode *inode, struct file *file)
 	iter = __seq_open_private(file, &show_ftrace_seq_ops, sizeof(*iter));
 	if (iter) {
 		iter->pg = ftrace_pages_start;
+		iter->flags = FTRACE_ITER_NO_UNSAFE;
 		iter->ops = &global_ops;
 	}
 
Signature · 1 line
1.7.10.4
author maintainer
#32 lore raw

RFC PATCH v2 6/18 ftrace: Add rcu_unsafe_filter_functions file

In reply to Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

Since the RCU unsafe functions are no longer displayed by the available_filter_functions, we still need a way to see these functions in order to trace them. Create a new file that lists the functions that were declared RCU unsafe.

Cc Jiri Olsa <[email protected]>
Cc Paul E. McKenney <[email protected]>
---
 include/linux/ftrace.h |    1 +
 kernel/trace/ftrace.c  |   31 +++++++++++++++++++++++++++++++
 2 files changed, 32 insertions(+)
include/linux/ftrace.h +1 -0
index 4709264..4752764 100644
@@ -412,6 +412,7 @@ enum {
 	FTRACE_ITER_HASH	= (1 << 4),
 	FTRACE_ITER_ENABLED	= (1 << 5),
 	FTRACE_ITER_NO_UNSAFE	= (1 << 6),
+	FTRACE_ITER_UNSAFE_ONLY	= (1 << 7),
 };
 
 void arch_ftrace_update_code(int command);
kernel/trace/ftrace.c +31 -0
index be87ac9..a3e4b71 100644
@@ -2647,6 +2647,9 @@ t_next(struct seq_file *m, void *v, loff_t *pos)
 		    ((iter->flags & FTRACE_ITER_ENABLED) &&
 		     !(rec->flags & FTRACE_FL_ENABLED)) ||
 
+		    ((iter->flags & FTRACE_ITER_UNSAFE_ONLY) &&
+		     !ftrace_lookup_ip(ftrace_unsafe_rcu, rec->ip)) ||
+
 		    ((iter->flags & FTRACE_ITER_NO_UNSAFE) &&
 		     ftrace_lookup_ip(ftrace_unsafe_rcu, rec->ip))) {
 
@@ -2784,6 +2787,24 @@ ftrace_avail_open(struct inode *inode, struct file *file)
 }
 
 static int
+ftrace_rcu_unsafe_open(struct inode *inode, struct file *file)
+{
+	struct ftrace_iterator *iter;
+
+	if (unlikely(ftrace_disabled))
+		return -ENODEV;
+
+	iter = __seq_open_private(file, &show_ftrace_seq_ops, sizeof(*iter));
+	if (iter) {
+		iter->pg = ftrace_pages_start;
+		iter->flags = FTRACE_ITER_UNSAFE_ONLY;
+		iter->ops = &global_ops;
+	}
+
+	return iter ? 0 : -ENOMEM;
+}
+
+static int
 ftrace_enabled_open(struct inode *inode, struct file *file)
 {
 	struct ftrace_iterator *iter;
@@ -3835,6 +3856,13 @@ static const struct file_operations ftrace_avail_fops = {
 	.release = seq_release_private,
 };
 
+static const struct file_operations ftrace_rcu_unsafe_fops = {
+	.open = ftrace_rcu_unsafe_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release_private,
+};
+
 static const struct file_operations ftrace_enabled_fops = {
 	.open = ftrace_enabled_open,
 	.read = seq_read,
@@ -4071,6 +4099,9 @@ static __init int ftrace_init_dyn_debugfs(struct dentry *d_tracer)
 	trace_create_file("available_filter_functions", 0444,
 			d_tracer, NULL, &ftrace_avail_fops);
 
+	trace_create_file("rcu_unsafe_filter_functions", 0444,
+			d_tracer, NULL, &ftrace_rcu_unsafe_fops);
+
 	trace_create_file("enabled_functions", 0444,
 			d_tracer, NULL, &ftrace_enabled_fops);
 
Signature · 1 line
1.7.10.4
Acked-by on v2 6/18
#33 lore raw

Re: [RFC][PATCH 06/18 v2] ftrace: Add rcu_unsafe_filter_functions file

Quoted 10 lines · Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

Since the RCU unsafe functions are no longer displayed by the available_filter_functions, we still need a way to see these functions in order to trace them. Create a new file that lists the functions that were declared RCU unsafe.

Cc Jiri Olsa <[email protected]>
Cc Paul E. McKenney <[email protected]>
Quoted 84 lines
---
 include/linux/ftrace.h |    1 +
 kernel/trace/ftrace.c  |   31 +++++++++++++++++++++++++++++++
 2 files changed, 32 insertions(+)
include/linux/ftrace.h +1 -0
index 4709264..4752764 100644
@@ -412,6 +412,7 @@ enum {
 	FTRACE_ITER_HASH	= (1 << 4),
 	FTRACE_ITER_ENABLED	= (1 << 5),
 	FTRACE_ITER_NO_UNSAFE	= (1 << 6),
+	FTRACE_ITER_UNSAFE_ONLY	= (1 << 7),
 };
 
 void arch_ftrace_update_code(int command);
kernel/trace/ftrace.c +31 -0
index be87ac9..a3e4b71 100644
@@ -2647,6 +2647,9 @@ t_next(struct seq_file *m, void *v, loff_t *pos)
 		    ((iter->flags & FTRACE_ITER_ENABLED) &&
 		     !(rec->flags & FTRACE_FL_ENABLED)) ||
 
+		    ((iter->flags & FTRACE_ITER_UNSAFE_ONLY) &&
+		     !ftrace_lookup_ip(ftrace_unsafe_rcu, rec->ip)) ||
+
 		    ((iter->flags & FTRACE_ITER_NO_UNSAFE) &&
 		     ftrace_lookup_ip(ftrace_unsafe_rcu, rec->ip))) {
 
@@ -2784,6 +2787,24 @@ ftrace_avail_open(struct inode *inode, struct file *file)
 }
 
 static int
+ftrace_rcu_unsafe_open(struct inode *inode, struct file *file)
+{
+	struct ftrace_iterator *iter;
+
+	if (unlikely(ftrace_disabled))
+		return -ENODEV;
+
+	iter = __seq_open_private(file, &show_ftrace_seq_ops, sizeof(*iter));
+	if (iter) {
+		iter->pg = ftrace_pages_start;
+		iter->flags = FTRACE_ITER_UNSAFE_ONLY;
+		iter->ops = &global_ops;
+	}
+
+	return iter ? 0 : -ENOMEM;
+}
+
+static int
 ftrace_enabled_open(struct inode *inode, struct file *file)
 {
 	struct ftrace_iterator *iter;
@@ -3835,6 +3856,13 @@ static const struct file_operations ftrace_avail_fops = {
 	.release = seq_release_private,
 };
 
+static const struct file_operations ftrace_rcu_unsafe_fops = {
+	.open = ftrace_rcu_unsafe_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release_private,
+};
+
 static const struct file_operations ftrace_enabled_fops = {
 	.open = ftrace_enabled_open,
 	.read = seq_read,
@@ -4071,6 +4099,9 @@ static __init int ftrace_init_dyn_debugfs(struct dentry *d_tracer)
 	trace_create_file("available_filter_functions", 0444,
 			d_tracer, NULL, &ftrace_avail_fops);
 
+	trace_create_file("rcu_unsafe_filter_functions", 0444,
+			d_tracer, NULL, &ftrace_rcu_unsafe_fops);
+
 	trace_create_file("enabled_functions", 0444,
 			d_tracer, NULL, &ftrace_enabled_fops);
 
Signature · 1 line
1.7.10.4
author maintainer
#34 lore raw

RFC PATCH v2 7/18 ftrace: Add selftest to check if RCU unsafe functions are filtered properly

In reply to Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

Add a boot time start up test that has a RCU safe ftrace_ops as well as an unsafe one. Make sure the RCU safe ops can trace RCU unsafe functions while the unsafe ftrace_ops can not.

Cc Jiri Olsa <[email protected]>
Cc Paul E. McKenney <[email protected]>
---
 kernel/trace/trace.h                  |    2 +
 kernel/trace/trace_selftest.c         |   94 +++++++++++++++++++++++++++++++++
 kernel/trace/trace_selftest_dynamic.c |    7 +++
 3 files changed, 103 insertions(+)
kernel/trace/trace.h +2 -0
index 502fed7..3578be6 100644
@@ -648,6 +648,8 @@ extern unsigned long ftrace_update_tot_cnt;
 extern int DYN_FTRACE_TEST_NAME(void);
 #define DYN_FTRACE_TEST_NAME2 trace_selftest_dynamic_test_func2
 extern int DYN_FTRACE_TEST_NAME2(void);
+#define DYN_FTRACE_TEST_RCU_UNSAFE trace_selftest_dynamic_test_rcu_unsafe
+extern int DYN_FTRACE_TEST_RCU_UNSAFE(void);
 
 extern bool ring_buffer_expanded;
 extern bool tracing_selftest_disabled;
kernel/trace/trace_selftest.c +94 -0

106 lines not on this page · raw message

kernel/trace/trace_selftest_dynamic.c +7 -0
index b4c475a..5eefa56 100644
@@ -11,3 +11,10 @@ int DYN_FTRACE_TEST_NAME2(void)
 	/* used to call mcount */
 	return 0;
 }
+
+int trace_selftest_dynamic_test_rcu_unsafe(void)
+{
+	/* used to call mcount */
+	return 0;
+}
+FTRACE_UNSAFE_RCU(trace_selftest_dynamic_test_rcu_unsafe);
Signature · 1 line
1.7.10.4
Acked-by on v2 7/18
#35 lore raw

Re: [RFC][PATCH 07/18 v2] ftrace: Add selftest to check if RCU unsafe functions are filtered properly

Quoted 9 lines · Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

Add a boot time start up test that has a RCU safe ftrace_ops as well as an unsafe one. Make sure the RCU safe ops can trace RCU unsafe functions while the unsafe ftrace_ops can not.

Cc Jiri Olsa <[email protected]>
Cc Paul E. McKenney <[email protected]>
Quoted 150 lines
---
 kernel/trace/trace.h                  |    2 +
 kernel/trace/trace_selftest.c         |   94 +++++++++++++++++++++++++++++++++
 kernel/trace/trace_selftest_dynamic.c |    7 +++
 3 files changed, 103 insertions(+)
kernel/trace/trace.h +2 -0
index 502fed7..3578be6 100644
@@ -648,6 +648,8 @@ extern unsigned long ftrace_update_tot_cnt;
 extern int DYN_FTRACE_TEST_NAME(void);
 #define DYN_FTRACE_TEST_NAME2 trace_selftest_dynamic_test_func2
 extern int DYN_FTRACE_TEST_NAME2(void);
+#define DYN_FTRACE_TEST_RCU_UNSAFE trace_selftest_dynamic_test_rcu_unsafe
+extern int DYN_FTRACE_TEST_RCU_UNSAFE(void);
 
 extern bool ring_buffer_expanded;
 extern bool tracing_selftest_disabled;
kernel/trace/trace_selftest.c +94 -0
index a7329b7..eeacb47 100644
@@ -185,6 +185,97 @@ static void reset_counts(void)
 	trace_selftest_test_dyn_cnt = 0;
 }
 
+static struct ftrace_ops ftrace_rcu_safe_ops = {
+	.func		= trace_selftest_test_probe1_func,
+	.flags		= FTRACE_OPS_FL_RECURSION_SAFE | FTRACE_OPS_FL_RCU_SAFE,
+};
+
+static struct ftrace_ops ftrace_rcu_unsafe_ops = {
+	.func		= trace_selftest_test_probe2_func,
+	.flags		= FTRACE_OPS_FL_RECURSION_SAFE,
+};
+
+static int test_rcu_safe_unsafe(void)
+{
+	int save_ftrace_enabled = ftrace_enabled;
+	char *func_name;
+	int len;
+	int ret = 0;
+
+	printk(KERN_CONT "PASSED\n");
+	pr_info("Testing ftrace rcu safe unsafe: ");
+
+	ftrace_enabled = 1;
+
+	trace_selftest_test_probe1_cnt = 0;
+	trace_selftest_test_probe2_cnt = 0;
+
+	func_name = "*" __stringify(DYN_FTRACE_TEST_RCU_UNSAFE);
+	len = strlen(func_name);
+
+	ftrace_set_filter(&ftrace_rcu_safe_ops, func_name, len, 1);
+	ftrace_set_filter(&ftrace_rcu_unsafe_ops, func_name, len, 1);
+
+	/* Do single registrations first */
+	register_ftrace_function(&ftrace_rcu_safe_ops);
+
+	DYN_FTRACE_TEST_RCU_UNSAFE();
+
+	unregister_ftrace_function(&ftrace_rcu_safe_ops);
+
+	if (trace_selftest_test_probe1_cnt != 1) {
+		printk(KERN_CONT "rcu_safe expected 1 call but had %d ",
+		       trace_selftest_test_probe1_cnt);
+		goto out;
+	}
+
+	register_ftrace_function(&ftrace_rcu_unsafe_ops);
+
+	DYN_FTRACE_TEST_RCU_UNSAFE();
+
+	unregister_ftrace_function(&ftrace_rcu_unsafe_ops);
+
+	if (trace_selftest_test_probe2_cnt != 0) {
+		printk(KERN_CONT "rcu_safe expected 0 calls but had %d ",
+		       trace_selftest_test_probe2_cnt);
+		goto out;
+	}
+
+	/* Run both together, which uses the list op */
+
+	trace_selftest_test_probe1_cnt = 0;
+	trace_selftest_test_probe2_cnt = 0;
+
+	register_ftrace_function(&ftrace_rcu_safe_ops);
+	register_ftrace_function(&ftrace_rcu_unsafe_ops);
+
+	DYN_FTRACE_TEST_RCU_UNSAFE();
+	DYN_FTRACE_TEST_RCU_UNSAFE();
+	DYN_FTRACE_TEST_RCU_UNSAFE();
+
+	unregister_ftrace_function(&ftrace_rcu_unsafe_ops);
+	unregister_ftrace_function(&ftrace_rcu_safe_ops);
+
+
+	if (trace_selftest_test_probe1_cnt != 3) {
+		printk(KERN_CONT "rcu_safe expected 3 calls but had %d ",
+		       trace_selftest_test_probe1_cnt);
+		goto out;
+	}
+
+	if (trace_selftest_test_probe2_cnt != 0) {
+		printk(KERN_CONT "rcu_safe expected 0 calls but had %d ",
+		       trace_selftest_test_probe2_cnt);
+		goto out;
+	}
+
+	ret = 0;
+ out:
+	ftrace_enabled = save_ftrace_enabled;
+
+	return ret;
+}
+
 static int trace_selftest_ops(int cnt)
 {
 	int save_ftrace_enabled = ftrace_enabled;
@@ -401,6 +492,9 @@ int trace_selftest_startup_dynamic_tracing(struct tracer *trace,
 	if (!ret)
 		ret = trace_selftest_ops(2);
 
+	if (!ret)
+		ret = test_rcu_safe_unsafe();
+
 	return ret;
 }
 
kernel/trace/trace_selftest_dynamic.c +7 -0
index b4c475a..5eefa56 100644
@@ -11,3 +11,10 @@ int DYN_FTRACE_TEST_NAME2(void)
 	/* used to call mcount */
 	return 0;
 }
+
+int trace_selftest_dynamic_test_rcu_unsafe(void)
+{
+	/* used to call mcount */
+	return 0;
+}
+FTRACE_UNSAFE_RCU(trace_selftest_dynamic_test_rcu_unsafe);
Signature · 1 line
1.7.10.4
author maintainer
#36 lore raw

RFC PATCH v2 8/18 ftrace/rcu: Do not trace debug_lockdep_rcu_enabled()

In reply to Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

The function debug_lockdep_rcu_enabled() is part of the RCU lockdep debugging, and is called very frequently. I found that if I enable a lot of debugging and run the function graph tracer, this function can cause a live lock of the system.

We don't usually trace lockdep infrastructure, no need to trace this either.

Cc Paul E. McKenney <[email protected]>
---
 kernel/rcupdate.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/rcupdate.c +1 -1
index cce6ba8..4f20c6c 100644
@@ -122,7 +122,7 @@ struct lockdep_map rcu_sched_lock_map =
 	STATIC_LOCKDEP_MAP_INIT("rcu_read_lock_sched", &rcu_sched_lock_key);
 EXPORT_SYMBOL_GPL(rcu_sched_lock_map);
 
-int debug_lockdep_rcu_enabled(void)
+int notrace debug_lockdep_rcu_enabled(void)
 {
 	return rcu_scheduler_active && debug_locks &&
 	       current->lockdep_recursion == 0;
Signature · 1 line
1.7.10.4
Reviewed-by on v2 8/18
#37 lore raw

Re: [RFC][PATCH 08/18 v2] ftrace/rcu: Do not trace debug_lockdep_rcu_enabled()

Quoted 7 lines · Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

The function debug_lockdep_rcu_enabled() is part of the RCU lockdep debugging, and is called very frequently. I found that if I enable a lot of debugging and run the function graph tracer, this function can cause a live lock of the system.

Quoted 5 lines

We don't usually trace lockdep infrastructure, no need to trace this either.

Cc Paul E. McKenney <[email protected]>

Or I can just take it, if you would rather. (If so, 3.12 or 3.13?)

Quoted 21 lines
---
 kernel/rcupdate.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/rcupdate.c +1 -1
index cce6ba8..4f20c6c 100644
@@ -122,7 +122,7 @@ struct lockdep_map rcu_sched_lock_map =
 	STATIC_LOCKDEP_MAP_INIT("rcu_read_lock_sched", &rcu_sched_lock_key);
 EXPORT_SYMBOL_GPL(rcu_sched_lock_map);
 
-int debug_lockdep_rcu_enabled(void)
+int notrace debug_lockdep_rcu_enabled(void)
 {
 	return rcu_scheduler_active && debug_locks &&
 	       current->lockdep_recursion == 0;
Signature · 1 line
1.7.10.4
author maintainer
#38 lore raw

Re: [RFC][PATCH 08/18 v2] ftrace/rcu: Do not trace debug_lockdep_rcu_enabled()

Quoted 11 lines · Paul E. McKenney
Quoted 10 lines · Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

The function debug_lockdep_rcu_enabled() is part of the RCU lockdep debugging, and is called very frequently. I found that if I enable a lot of debugging and run the function graph tracer, this function can cause a live lock of the system.

We don't usually trace lockdep infrastructure, no need to trace this either.

Quoted 7 lines
Quoted 2 lines
Cc Paul E. McKenney <[email protected]>

Or I can just take it, if you would rather. (If so, 3.12 or 3.13?)

Feel free to take it and I'll remove it from my queue. 3.12 please.

I'll just need to remember to turn off function graph tracing when testing these patches again.

-- Steve

author maintainer
#39 lore raw

RFC PATCH v2 9/18 ftrace: Fix a slight race in modifying what function callback gets traced

In reply to Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

There's a slight race when going from a list function to a non list function. That is, when only one callback is registered to the function tracer, it gets called directly by the mcount trampoline. But if this function has filters, it may be called by the wrong functions.

As the list ops callback that handles multiple callbacks that are registered to ftrace, it also handles what functions they call. While the transaction is taking place, use the list function always, and after all the updates are finished (only the functions that should be traced are being traced), then we can update the trampoline to call the function directly.

---
 kernel/trace/ftrace.c |   17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)
kernel/trace/ftrace.c +16 -1
index a3e4b71..33e4890 100644
@@ -2076,12 +2076,27 @@ int __weak ftrace_arch_code_modify_post_process(void)
 
 void ftrace_modify_all_code(int command)
 {
+	int update = command & FTRACE_UPDATE_TRACE_FUNC;
+
+	/*
+	 * If the ftrace_caller calls a ftrace_ops func directly,
+	 * we need to make sure that it only traces functions it
+	 * expects to trace. When doing the switch of functions,
+	 * we need to update to the ftrace_ops_list_func first
+	 * before the transition between old and new calls are set,
+	 * as the ftrace_ops_list_func will check the ops hashes
+	 * to make sure the ops are having the right functions
+	 * traced.
+	 */
+	if (update)
+		ftrace_update_ftrace_func(ftrace_ops_list_func);
+
 	if (command & FTRACE_UPDATE_CALLS)
 		ftrace_replace_code(1);
 	else if (command & FTRACE_DISABLE_CALLS)
 		ftrace_replace_code(0);
 
-	if (command & FTRACE_UPDATE_TRACE_FUNC)
+	if (update && ftrace_trace_function != ftrace_ops_list_func)
 		ftrace_update_ftrace_func(ftrace_trace_function);
 
 	if (command & FTRACE_START_FUNC_RET)
Signature · 1 line
1.7.10.4
author maintainer
#40 lore raw

RFC PATCH v2 10/18 ftrace: Create a RCU unsafe checker

In reply to Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

Knowing what functions are not safe to be traced by callbacks that use RCU read locks, is not easy to figure out. By adding a function tracer callback that is set as a non RCU safe callback that also uses rcu_read_lock() and enables PROVE_RCU, it can be used to find locations in the kernel that need to be tagged with FTRACE_UNSAFE_RCU().

On boot up, this callback gets registered so that all functions are being traced, and there's no way to turn this off. In the future we can make this enabled or disabled at run time, but for now it's only used for debugging and should not be enabled by normal users.

---
 kernel/trace/Kconfig           |   22 +++++++++++++++++++
 kernel/trace/ftrace.c          |   12 ++++++++++
 kernel/trace/trace.h           |    3 +++
 kernel/trace/trace_functions.c |   47 +++++++++++++++++++++++++++++++++++++++-
 4 files changed, 83 insertions(+), 1 deletion(-)
kernel/trace/Kconfig +22 -0
index 015f85a..907b497 100644
@@ -489,6 +489,28 @@ config FTRACE_MCOUNT_RECORD
 config FTRACE_SELFTEST
 	bool
 
+config FTRACE_UNSAFE_RCU_CHECKER
+        bool "Trace for unsafe RCU callers"
+	depends on DYNAMIC_FTRACE
+	depends on PROVE_LOCKING
+	select PROVE_RCU
+	help
+	 Some function tracing callbacks use RCU read lock (namely perf).
+	 There are some RCU critical functions that are called out
+	 of scope for RCU. For example, when NO_HZ_FULL is enabled,
+	 and coming out of user space. The CPU is not being tracked by
+	 RCU and all rcu_read_lock()s will be ignored. These functions
+	 need to be tagged as unsafe for RCU so that only function callbacks
+	 that specify that they do not use RCU will be called by them.
+
+	 This option will enable PROVE_RCU and will enable on boot up
+	 a function callback that traces all functions and uses an
+	 rcu_read_lock(). If any function that is not tagged as unsafe
+	 for RCU is called, a debug splat will be shown. This is used
+	 for finding unsafe RCU callers that need to be tagged.
+
+	 If you don't understand any of this, then say N.
+
 config FTRACE_STARTUP_TEST
 	bool "Perform a startup test on ftrace"
 	depends on GENERIC_TRACER
kernel/trace/ftrace.c +12 -0
index 33e4890..69b7f62 100644
@@ -1359,6 +1359,13 @@ alloc_and_copy_ftrace_hash(int size_bits, struct ftrace_hash *hash)
 	return NULL;
 }
 
+#ifdef CONFIG_FTRACE_UNSAFE_RCU_CHECKER
+bool ftrace_rcu_unsafe(unsigned long addr)
+{
+	return ftrace_lookup_ip(ftrace_unsafe_rcu, addr) != NULL;
+}
+#endif
+
 static void
 ftrace_hash_rec_disable(struct ftrace_ops *ops, int filter_hash);
 static void
@@ -4391,6 +4398,11 @@ static void __init create_unsafe_rcu_hash(void)
 		if (WARN_ON_ONCE(strcmp(str, finder->name) != 0))
 			continue;
 
+#ifdef CONFIG_FTRACE_UNSAFE_RCU_CHECKER
+		/* When checker is enabled, show what was marked unsafe */
+		pr_info("add ftrace rcu unsafe %p (%s)\n",
+			(void *)ip, finder->name);
+#endif
 		add_hash_entry(ftrace_unsafe_rcu, ip);
 	}
 }
kernel/trace/trace.h +3 -0
index 3578be6..e551316 100644
@@ -760,6 +760,9 @@ static inline int ftrace_graph_addr(unsigned long addr)
 
 	return 0;
 }
+#ifdef CONFIG_FTRACE_UNSAFE_RCU_CHECKER
+extern bool ftrace_rcu_unsafe(unsigned long addr);
+#endif
 #else
 static inline int ftrace_graph_addr(unsigned long addr)
 {
kernel/trace/trace_functions.c +46 -1

55 lines not on this page · raw message

Signature · 1 line
1.7.10.4
Acked-by on v2 10/18
#41 lore raw

Re: [RFC][PATCH 10/18 v2] ftrace: Create a RCU unsafe checker

Quoted 8 lines · Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

Knowing what functions are not safe to be traced by callbacks that use RCU read locks, is not easy to figure out. By adding a function tracer callback that is set as a non RCU safe callback that also uses rcu_read_lock() and enables PROVE_RCU, it can be used to find locations in the kernel that need to be tagged with FTRACE_UNSAFE_RCU().

Quoted 6 lines

On boot up, this callback gets registered so that all functions are being traced, and there's no way to turn this off. In the future we can make this enabled or disabled at run time, but for now it's only used for debugging and should not be enabled by normal users.

Quoted 148 lines
---
 kernel/trace/Kconfig           |   22 +++++++++++++++++++
 kernel/trace/ftrace.c          |   12 ++++++++++
 kernel/trace/trace.h           |    3 +++
 kernel/trace/trace_functions.c |   47 +++++++++++++++++++++++++++++++++++++++-
 4 files changed, 83 insertions(+), 1 deletion(-)
kernel/trace/Kconfig +22 -0
index 015f85a..907b497 100644
@@ -489,6 +489,28 @@ config FTRACE_MCOUNT_RECORD
 config FTRACE_SELFTEST
 	bool
 
+config FTRACE_UNSAFE_RCU_CHECKER
+        bool "Trace for unsafe RCU callers"
+	depends on DYNAMIC_FTRACE
+	depends on PROVE_LOCKING
+	select PROVE_RCU
+	help
+	 Some function tracing callbacks use RCU read lock (namely perf).
+	 There are some RCU critical functions that are called out
+	 of scope for RCU. For example, when NO_HZ_FULL is enabled,
+	 and coming out of user space. The CPU is not being tracked by
+	 RCU and all rcu_read_lock()s will be ignored. These functions
+	 need to be tagged as unsafe for RCU so that only function callbacks
+	 that specify that they do not use RCU will be called by them.
+
+	 This option will enable PROVE_RCU and will enable on boot up
+	 a function callback that traces all functions and uses an
+	 rcu_read_lock(). If any function that is not tagged as unsafe
+	 for RCU is called, a debug splat will be shown. This is used
+	 for finding unsafe RCU callers that need to be tagged.
+
+	 If you don't understand any of this, then say N.
+
 config FTRACE_STARTUP_TEST
 	bool "Perform a startup test on ftrace"
 	depends on GENERIC_TRACER
kernel/trace/ftrace.c +12 -0
index 33e4890..69b7f62 100644
@@ -1359,6 +1359,13 @@ alloc_and_copy_ftrace_hash(int size_bits, struct ftrace_hash *hash)
 	return NULL;
 }
 
+#ifdef CONFIG_FTRACE_UNSAFE_RCU_CHECKER
+bool ftrace_rcu_unsafe(unsigned long addr)
+{
+	return ftrace_lookup_ip(ftrace_unsafe_rcu, addr) != NULL;
+}
+#endif
+
 static void
 ftrace_hash_rec_disable(struct ftrace_ops *ops, int filter_hash);
 static void
@@ -4391,6 +4398,11 @@ static void __init create_unsafe_rcu_hash(void)
 		if (WARN_ON_ONCE(strcmp(str, finder->name) != 0))
 			continue;
 
+#ifdef CONFIG_FTRACE_UNSAFE_RCU_CHECKER
+		/* When checker is enabled, show what was marked unsafe */
+		pr_info("add ftrace rcu unsafe %p (%s)\n",
+			(void *)ip, finder->name);
+#endif
 		add_hash_entry(ftrace_unsafe_rcu, ip);
 	}
 }
kernel/trace/trace.h +3 -0
index 3578be6..e551316 100644
@@ -760,6 +760,9 @@ static inline int ftrace_graph_addr(unsigned long addr)
 
 	return 0;
 }
+#ifdef CONFIG_FTRACE_UNSAFE_RCU_CHECKER
+extern bool ftrace_rcu_unsafe(unsigned long addr);
+#endif
 #else
 static inline int ftrace_graph_addr(unsigned long addr)
 {
kernel/trace/trace_functions.c +46 -1
index 38fe148..9dd4627 100644
@@ -559,9 +559,54 @@ static inline int init_func_cmd_traceon(void)
 }
 #endif /* CONFIG_DYNAMIC_FTRACE */
 
+#ifdef CONFIG_FTRACE_UNSAFE_RCU_CHECKER
+static void
+ftrace_unsafe_callback(unsigned long ip, unsigned long parent_ip,
+		       struct ftrace_ops *op, struct pt_regs *pt_regs)
+{
+	int bit;
+
+	preempt_disable_notrace();
+
+	bit = trace_test_and_set_recursion(TRACE_FTRACE_START, TRACE_FTRACE_MAX);
+	if (bit < 0)
+		goto out;
+
+	if (WARN_ONCE(ftrace_rcu_unsafe(ip),
+		      "UNSAFE RCU function called %pS",
+		      (void *)ip))
+		goto out;
+
+	/* Should trigger a RCU splat if called from unsafe RCU function */
+	rcu_read_lock();
+	rcu_read_unlock();
+
+	trace_clear_recursion(bit);
+ out:
+	preempt_enable_notrace();
+}
+
+static struct ftrace_ops ftrace_unsafe_ops = {
+	.func			= ftrace_unsafe_callback,
+	.flags			= FTRACE_OPS_FL_RECURSION_SAFE
+};
+
+static __init void ftrace_start_unsafe_rcu(void)
+{
+	register_ftrace_function(&ftrace_unsafe_ops);
+}
+#else
+static inline void ftrace_start_unsafe_rcu(void) { }
+#endif
+
 static __init int init_function_trace(void)
 {
+	int ret;
+
 	init_func_cmd_traceon();
-	return register_tracer(&function_trace);
+	ret = register_tracer(&function_trace);
+	if (!ret)
+		ftrace_start_unsafe_rcu();
+	return ret;
 }
 core_initcall(init_function_trace);
Signature · 1 line
1.7.10.4
author maintainer
#42 lore raw

RFC PATCH v2 11/18 ftrace: Adde infrastructure to stop RCU unsafe checker from checking

In reply to Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

This is a light weight way to keep the rcu checker from checking RCU safety. It adds a ftrace_unsafe_rcu_checker_disable/enable() that increments or decrements a counter respectively. When the counter is set, the RCU unsafe checker callback does not run the tests to see if RCU is safe or not.

This is required by the graph tracer because the checks can cause the graph tracer to live lock the system by its own calls.

It's also needed by the irqsoff tracer, because it may be called in RCU unsafe regions and if its internal functions get traced then the RCU unsafe checker may have some false positives.

---
 kernel/trace/trace.h           |   12 +++++++++---
 kernel/trace/trace_functions.c |   15 +++++++++++++++
 2 files changed, 24 insertions(+), 3 deletions(-)
kernel/trace/trace.h +9 -3
index e551316..58e4c37 100644
@@ -760,9 +760,6 @@ static inline int ftrace_graph_addr(unsigned long addr)
 
 	return 0;
 }
-#ifdef CONFIG_FTRACE_UNSAFE_RCU_CHECKER
-extern bool ftrace_rcu_unsafe(unsigned long addr);
-#endif
 #else
 static inline int ftrace_graph_addr(unsigned long addr)
 {
@@ -1061,4 +1058,13 @@ int perf_ftrace_event_register(struct ftrace_event_call *call,
 #define perf_ftrace_event_register NULL
 #endif
 
+#ifdef CONFIG_FTRACE_UNSAFE_RCU_CHECKER
+extern bool ftrace_rcu_unsafe(unsigned long addr);
+extern void ftrace_unsafe_rcu_checker_disable(void);
+extern void ftrace_unsafe_rcu_checker_enable(void);
+#else
+static inline void ftrace_unsafe_rcu_checker_disable(void) { }
+static inline void ftrace_unsafe_rcu_checker_enable(void) { }
+#endif
+
 #endif /* _LINUX_KERNEL_TRACE_H */
kernel/trace/trace_functions.c +15 -0
index 9dd4627..1d5f951 100644
@@ -560,12 +560,27 @@ static inline int init_func_cmd_traceon(void)
 #endif /* CONFIG_DYNAMIC_FTRACE */
 
 #ifdef CONFIG_FTRACE_UNSAFE_RCU_CHECKER
+static atomic_t ftrace_unsafe_rcu_disabled;
+
+void ftrace_unsafe_rcu_checker_disable(void)
+{
+	atomic_inc(&ftrace_unsafe_rcu_disabled);
+}
+
+void ftrace_unsafe_rcu_checker_enable(void)
+{
+	atomic_dec(&ftrace_unsafe_rcu_disabled);
+}
+
 static void
 ftrace_unsafe_callback(unsigned long ip, unsigned long parent_ip,
 		       struct ftrace_ops *op, struct pt_regs *pt_regs)
 {
 	int bit;
 
+	if (atomic_read(&ftrace_unsafe_rcu_disabled))
+		return;
+
 	preempt_disable_notrace();
 
 	bit = trace_test_and_set_recursion(TRACE_FTRACE_START, TRACE_FTRACE_MAX);
Signature · 1 line
1.7.10.4
Acked-by on v2 11/18
#43 lore raw

Re: [RFC][PATCH 11/18 v2] ftrace: Adde infrastructure to stop RCU unsafe checker from checking

Quoted 7 lines · Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

This is a light weight way to keep the rcu checker from checking RCU safety. It adds a ftrace_unsafe_rcu_checker_disable/enable() that increments or decrements a counter respectively. When the counter is set, the RCU unsafe checker callback does not run the tests to see if RCU is safe or not.

Please add something saying what we do instead of testing RCU safety. Looks to me like it skips not only the tests, but also invoking the callback, but I could easily be wrong.

Quoted 8 lines

This is required by the graph tracer because the checks can cause the graph tracer to live lock the system by its own calls.

It's also needed by the irqsoff tracer, because it may be called in RCU unsafe regions and if its internal functions get traced then the RCU unsafe checker may have some false positives.

With the augmented commit log as noted above:

Quoted 69 lines
---
 kernel/trace/trace.h           |   12 +++++++++---
 kernel/trace/trace_functions.c |   15 +++++++++++++++
 2 files changed, 24 insertions(+), 3 deletions(-)
kernel/trace/trace.h +9 -3
index e551316..58e4c37 100644
@@ -760,9 +760,6 @@ static inline int ftrace_graph_addr(unsigned long addr)
 
 	return 0;
 }
-#ifdef CONFIG_FTRACE_UNSAFE_RCU_CHECKER
-extern bool ftrace_rcu_unsafe(unsigned long addr);
-#endif
 #else
 static inline int ftrace_graph_addr(unsigned long addr)
 {
@@ -1061,4 +1058,13 @@ int perf_ftrace_event_register(struct ftrace_event_call *call,
 #define perf_ftrace_event_register NULL
 #endif
 
+#ifdef CONFIG_FTRACE_UNSAFE_RCU_CHECKER
+extern bool ftrace_rcu_unsafe(unsigned long addr);
+extern void ftrace_unsafe_rcu_checker_disable(void);
+extern void ftrace_unsafe_rcu_checker_enable(void);
+#else
+static inline void ftrace_unsafe_rcu_checker_disable(void) { }
+static inline void ftrace_unsafe_rcu_checker_enable(void) { }
+#endif
+
 #endif /* _LINUX_KERNEL_TRACE_H */
kernel/trace/trace_functions.c +15 -0
index 9dd4627..1d5f951 100644
@@ -560,12 +560,27 @@ static inline int init_func_cmd_traceon(void)
 #endif /* CONFIG_DYNAMIC_FTRACE */
 
 #ifdef CONFIG_FTRACE_UNSAFE_RCU_CHECKER
+static atomic_t ftrace_unsafe_rcu_disabled;
+
+void ftrace_unsafe_rcu_checker_disable(void)
+{
+	atomic_inc(&ftrace_unsafe_rcu_disabled);
+}
+
+void ftrace_unsafe_rcu_checker_enable(void)
+{
+	atomic_dec(&ftrace_unsafe_rcu_disabled);
+}
+
 static void
 ftrace_unsafe_callback(unsigned long ip, unsigned long parent_ip,
 		       struct ftrace_ops *op, struct pt_regs *pt_regs)
 {
 	int bit;
 
+	if (atomic_read(&ftrace_unsafe_rcu_disabled))
+		return;
+
 	preempt_disable_notrace();
 
 	bit = trace_test_and_set_recursion(TRACE_FTRACE_START, TRACE_FTRACE_MAX);
Signature · 1 line
1.7.10.4
author maintainer
#44 lore raw

Re: [RFC][PATCH 11/18 v2] ftrace: Adde infrastructure to stop RCU unsafe checker from checking

Quoted 9 lines · Paul E. McKenney
Quoted 7 lines · Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

This is a light weight way to keep the rcu checker from checking RCU safety. It adds a ftrace_unsafe_rcu_checker_disable/enable() that increments or decrements a counter respectively. When the counter is set, the RCU unsafe checker callback does not run the tests to see if RCU is safe or not.

Quoted 3 lines

Please add something saying what we do instead of testing RCU safety. Looks to me like it skips not only the tests, but also invoking the callback, but I could easily be wrong.

Yeah, the change log sucks. I wrote the change logs after 1am and was half asleep. I see I wrote "Add" as "Adde" ;-)

Quoted 8 lines
Quoted 8 lines

This is required by the graph tracer because the checks can cause the graph tracer to live lock the system by its own calls.

It's also needed by the irqsoff tracer, because it may be called in RCU unsafe regions and if its internal functions get traced then the RCU unsafe checker may have some false positives.

Quoted 6 lines
Quoted 1 line

With the augmented commit log as noted above:

Thanks, come Tuesday, I'll update the logs.

-- Steve

Quoted 10 lines
Quoted 10 lines
---
 kernel/trace/trace.h           |   12 +++++++++---
 kernel/trace/trace_functions.c |   15 +++++++++++++++
 2 files changed, 24 insertions(+), 3 deletions(-)
kernel/trace/trace.h +0 -0
index e551316..58e4c37 100644
@@ -760,9 +760,6 @@ static inline int ftrace_graph_addr(unsigned long addr)
author maintainer
#45 lore raw

Re: [RFC][PATCH 11/18 v2] ftrace: Adde infrastructure to stop RCU unsafe checker from checking

In reply to Paul E. McKenney
Quoted 9 lines · On Sat, 31 Aug 2013 12:52:58 -0700 "Paul E. McKenney"…
Quoted 7 lines · Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

This is a light weight way to keep the rcu checker from checking RCU safety. It adds a ftrace_unsafe_rcu_checker_disable/enable() that increments or decrements a counter respectively. When the counter is set, the RCU unsafe checker callback does not run the tests to see if RCU is safe or not.

Quoted 3 lines

Please add something saying what we do instead of testing RCU safety. Looks to me like it skips not only the tests, but also invoking the callback, but I could easily be wrong.

Now that I'm awake and also not on holiday, I can reply with a clear mind.

When disabled, it forces the callback to return immediately. I may in the future, have it disable the callback altogether.

Yes, we can miss checks, but it's better than the test live locking the system :-)

Quoted 3 lines
Quoted 3 lines

This is required by the graph tracer because the checks can cause the graph tracer to live lock the system by its own calls.

I added this (I quoted the added text):

This is a light weight way to keep the rcu checker from checking RCU safety. It adds a ftrace_unsafe_rcu_checker_disable/enable() that increments or decrements a counter respectively. When the counter is set, the RCU unsafe checker callback does not run the tests to see if RCU is safe or not. "But the callback still gets called. It just does not call rcu_read_(un)lock()."

This is required by the graph tracer because the checks can cause the graph tracer to live lock the system by its own calls. "That is, the graph tracer will still trace rcu and the rcu debugging, and this will slow down the checker, which is still calling all other functions (in interrupts and faults), which can cause the timer interrupt to take oven a millisecond to complete, and it will then trigger once it finishes, live locking the system."

Quoted 8 lines
Quoted 6 lines

It's also needed by the irqsoff tracer, because it may be called in RCU unsafe regions and if its internal functions get traced then the RCU unsafe checker may have some false positives.

With the augmented commit log as noted above:

Is the above OK?

-- Steve

Quoted 72 lines
Quoted 69 lines
---
 kernel/trace/trace.h           |   12 +++++++++---
 kernel/trace/trace_functions.c |   15 +++++++++++++++
 2 files changed, 24 insertions(+), 3 deletions(-)
kernel/trace/trace.h +9 -3
index e551316..58e4c37 100644
@@ -760,9 +760,6 @@ static inline int ftrace_graph_addr(unsigned long addr)
 
 	return 0;
 }
-#ifdef CONFIG_FTRACE_UNSAFE_RCU_CHECKER
-extern bool ftrace_rcu_unsafe(unsigned long addr);
-#endif
 #else
 static inline int ftrace_graph_addr(unsigned long addr)
 {
@@ -1061,4 +1058,13 @@ int perf_ftrace_event_register(struct ftrace_event_call *call,
 #define perf_ftrace_event_register NULL
 #endif
 
+#ifdef CONFIG_FTRACE_UNSAFE_RCU_CHECKER
+extern bool ftrace_rcu_unsafe(unsigned long addr);
+extern void ftrace_unsafe_rcu_checker_disable(void);
+extern void ftrace_unsafe_rcu_checker_enable(void);
+#else
+static inline void ftrace_unsafe_rcu_checker_disable(void) { }
+static inline void ftrace_unsafe_rcu_checker_enable(void) { }
+#endif
+
 #endif /* _LINUX_KERNEL_TRACE_H */
kernel/trace/trace_functions.c +15 -0
index 9dd4627..1d5f951 100644
@@ -560,12 +560,27 @@ static inline int init_func_cmd_traceon(void)
 #endif /* CONFIG_DYNAMIC_FTRACE */
 
 #ifdef CONFIG_FTRACE_UNSAFE_RCU_CHECKER
+static atomic_t ftrace_unsafe_rcu_disabled;
+
+void ftrace_unsafe_rcu_checker_disable(void)
+{
+	atomic_inc(&ftrace_unsafe_rcu_disabled);
+}
+
+void ftrace_unsafe_rcu_checker_enable(void)
+{
+	atomic_dec(&ftrace_unsafe_rcu_disabled);
+}
+
 static void
 ftrace_unsafe_callback(unsigned long ip, unsigned long parent_ip,
 		       struct ftrace_ops *op, struct pt_regs *pt_regs)
 {
 	int bit;
 
+	if (atomic_read(&ftrace_unsafe_rcu_disabled))
+		return;
+
 	preempt_disable_notrace();
 
 	bit = trace_test_and_set_recursion(TRACE_FTRACE_START, TRACE_FTRACE_MAX);
Signature · 1 line
1.7.10.4
#46 lore raw

Re: [RFC][PATCH 11/18 v2] ftrace: Adde infrastructure to stop RCU unsafe checker from checking

Quoted 52 lines · Steven Rostedt
Quoted 9 lines · On Sat, 31 Aug 2013 12:52:58 -0700 "Paul E. McKenney"…
Quoted 7 lines · Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

This is a light weight way to keep the rcu checker from checking RCU safety. It adds a ftrace_unsafe_rcu_checker_disable/enable() that increments or decrements a counter respectively. When the counter is set, the RCU unsafe checker callback does not run the tests to see if RCU is safe or not.

Quoted 3 lines

Please add something saying what we do instead of testing RCU safety. Looks to me like it skips not only the tests, but also invoking the callback, but I could easily be wrong.

Now that I'm awake and also not on holiday, I can reply with a clear mind.

When disabled, it forces the callback to return immediately. I may in the future, have it disable the callback altogether.

Yes, we can miss checks, but it's better than the test live locking the system :-)

Quoted 3 lines
Quoted 3 lines

This is required by the graph tracer because the checks can cause the graph tracer to live lock the system by its own calls.

I added this (I quoted the added text):

This is a light weight way to keep the rcu checker from checking RCU safety. It adds a ftrace_unsafe_rcu_checker_disable/enable() that increments or decrements a counter respectively. When the counter is set, the RCU unsafe checker callback does not run the tests to see if RCU is safe or not. "But the callback still gets called. It just does not call rcu_read_(un)lock()."

This is required by the graph tracer because the checks can cause the graph tracer to live lock the system by its own calls. "That is, the graph tracer will still trace rcu and the rcu debugging, and this will slow down the checker, which is still calling all other functions (in interrupts and faults), which can cause the timer interrupt to take oven a millisecond to complete, and it will then trigger once it finishes, live locking the system."

Quoted 5 lines
Quoted 5 lines

It's also needed by the irqsoff tracer, because it may be called in RCU unsafe regions and if its internal functions get traced then the RCU unsafe checker may have some false positives.

Quoted 5 lines
Quoted 3 lines
Quoted 1 line

With the augmented commit log as noted above:

Is the above OK?

Works for me!

Thanx, Paul

Quoted 81 lines

-- Steve

Quoted 67 lines
Quoted 64 lines
---
 kernel/trace/trace.h           |   12 +++++++++---
 kernel/trace/trace_functions.c |   15 +++++++++++++++
 2 files changed, 24 insertions(+), 3 deletions(-)
kernel/trace/trace.h +9 -3
index e551316..58e4c37 100644
@@ -760,9 +760,6 @@ static inline int ftrace_graph_addr(unsigned long addr)
 
 	return 0;
 }
-#ifdef CONFIG_FTRACE_UNSAFE_RCU_CHECKER
-extern bool ftrace_rcu_unsafe(unsigned long addr);
-#endif
 #else
 static inline int ftrace_graph_addr(unsigned long addr)
 {
@@ -1061,4 +1058,13 @@ int perf_ftrace_event_register(struct ftrace_event_call *call,
 #define perf_ftrace_event_register NULL
 #endif
 
+#ifdef CONFIG_FTRACE_UNSAFE_RCU_CHECKER
+extern bool ftrace_rcu_unsafe(unsigned long addr);
+extern void ftrace_unsafe_rcu_checker_disable(void);
+extern void ftrace_unsafe_rcu_checker_enable(void);
+#else
+static inline void ftrace_unsafe_rcu_checker_disable(void) { }
+static inline void ftrace_unsafe_rcu_checker_enable(void) { }
+#endif
+
 #endif /* _LINUX_KERNEL_TRACE_H */
kernel/trace/trace_functions.c +15 -0
index 9dd4627..1d5f951 100644
@@ -560,12 +560,27 @@ static inline int init_func_cmd_traceon(void)
 #endif /* CONFIG_DYNAMIC_FTRACE */
 
 #ifdef CONFIG_FTRACE_UNSAFE_RCU_CHECKER
+static atomic_t ftrace_unsafe_rcu_disabled;
+
+void ftrace_unsafe_rcu_checker_disable(void)
+{
+	atomic_inc(&ftrace_unsafe_rcu_disabled);
+}
+
+void ftrace_unsafe_rcu_checker_enable(void)
+{
+	atomic_dec(&ftrace_unsafe_rcu_disabled);
+}
+
 static void
 ftrace_unsafe_callback(unsigned long ip, unsigned long parent_ip,
 		       struct ftrace_ops *op, struct pt_regs *pt_regs)
 {
 	int bit;
 
+	if (atomic_read(&ftrace_unsafe_rcu_disabled))
+		return;
+
 	preempt_disable_notrace();
 
Quoted 5 lines
Quoted 5 lines
kernel/trace/trace_functions.c +0 -0
 	bit = trace_test_and_set_recursion(TRACE_FTRACE_START, TRACE_FTRACE_MAX);
Signature · 1 line
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

author maintainer
#47 lore raw

RFC PATCH v2 12/18 ftrace: Disable RCU unsafe checker when function graph is enabled

In reply to Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

Having the RCU unsafe checker running when function graph is enabled can cause a live lock. That's because the RCU unsafe checker enables full lockdep debugging on RCU which does a lot of interal calls that may be traced by the function graph tacer. This adds quite a bit of overhead and can possibly live lock the system.

Just do not do the RCU unsafe checks when function graph tracer is enabled.

---
 kernel/trace/ftrace.c |    7 +++++++
 1 file changed, 7 insertions(+)
kernel/trace/ftrace.c +7 -0
index 69b7f62..310b727 100644
@@ -5118,6 +5118,12 @@ int register_ftrace_graph(trace_func_graph_ret_t retfunc,
 		goto out;
 	}
 
+	/*
+	 * The Unsafe RCU checker can live lock function graph tracing.
+	 * It's best to just disable it while doing the fgraph tracing.
+	 */
+	ftrace_unsafe_rcu_checker_disable();
+
 	ftrace_graph_return = retfunc;
 	ftrace_graph_entry = entryfunc;
 
@@ -5141,6 +5147,7 @@ void unregister_ftrace_graph(void)
 	ftrace_shutdown(&global_ops, FTRACE_STOP_FUNC_RET);
 	unregister_pm_notifier(&ftrace_suspend_notifier);
 	unregister_trace_sched_switch(ftrace_graph_probe_sched_switch, NULL);
+	ftrace_unsafe_rcu_checker_enable();
 
  out:
 	mutex_unlock(&ftrace_lock);
Signature · 1 line
1.7.10.4
#48 lore raw

Re: [RFC][PATCH 12/18 v2] ftrace: Disable RCU unsafe checker when function graph is enabled

Quoted 6 lines · Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

Having the RCU unsafe checker running when function graph is enabled can cause a live lock. That's because the RCU unsafe checker enables full lockdep debugging on RCU which does a lot of interal calls that may be traced by the function graph tacer. This adds quite a bit of

s/tacer/tracer/ (Yeah, yeah, picky, picky!)

Quoted 6 lines

overhead and can possibly live lock the system.

Just do not do the RCU unsafe checks when function graph tracer is enabled.

One question: How does the user/tester/developer know that RCU-unsafe checks have been disabled by function-graph tracing? Would it make sense to print something to dmesg calling this out? Or do the transitions happen too often?

Thanx, Paul

Quoted 33 lines
---
 kernel/trace/ftrace.c |    7 +++++++
 1 file changed, 7 insertions(+)
kernel/trace/ftrace.c +7 -0
index 69b7f62..310b727 100644
@@ -5118,6 +5118,12 @@ int register_ftrace_graph(trace_func_graph_ret_t retfunc,
 		goto out;
 	}
 
+	/*
+	 * The Unsafe RCU checker can live lock function graph tracing.
+	 * It's best to just disable it while doing the fgraph tracing.
+	 */
+	ftrace_unsafe_rcu_checker_disable();
+
 	ftrace_graph_return = retfunc;
 	ftrace_graph_entry = entryfunc;
 
@@ -5141,6 +5147,7 @@ void unregister_ftrace_graph(void)
 	ftrace_shutdown(&global_ops, FTRACE_STOP_FUNC_RET);
 	unregister_pm_notifier(&ftrace_suspend_notifier);
 	unregister_trace_sched_switch(ftrace_graph_probe_sched_switch, NULL);
+	ftrace_unsafe_rcu_checker_enable();
 
  out:
 	mutex_unlock(&ftrace_lock);
Signature · 1 line
1.7.10.4
author maintainer
#49 lore raw

Re: [RFC][PATCH 12/18 v2] ftrace: Disable RCU unsafe checker when function graph is enabled

Quoted 15 lines · Paul E. McKenney
Quoted 6 lines · Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

Having the RCU unsafe checker running when function graph is enabled can cause a live lock. That's because the RCU unsafe checker enables full lockdep debugging on RCU which does a lot of interal calls that may be traced by the function graph tacer. This adds quite a bit of

s/tacer/tracer/ (Yeah, yeah, picky, picky!)

Quoted 5 lines

overhead and can possibly live lock the system.

Just do not do the RCU unsafe checks when function graph tracer is enabled.

Quoted 6 lines
Quoted 1 line

One question: How does the user/tester/developer know that RCU-unsafe checks have been disabled by function-graph tracing? Would it make sense to print something to dmesg calling this out? Or do the transitions happen too often?

Ideally, (for 3.13) I plan on having this be a sysctl switch. That will be 1 or 0, depending on if it is enabled or not. But yeah, I can add a printk to show that the kernel changed it. It doesn't happen often, and mainly by a user (or selftest).

-- Steve

Quoted 4 lines

Thanx, Paul

Quoted 1 line

---

#50 lore raw

Re: [RFC][PATCH 12/18 v2] ftrace: Disable RCU unsafe checker when function graph is enabled

Quoted 23 lines · Steven Rostedt
Quoted 15 lines · Paul E. McKenney
Quoted 6 lines · Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

Having the RCU unsafe checker running when function graph is enabled can cause a live lock. That's because the RCU unsafe checker enables full lockdep debugging on RCU which does a lot of interal calls that may be traced by the function graph tacer. This adds quite a bit of

s/tacer/tracer/ (Yeah, yeah, picky, picky!)

Quoted 5 lines

overhead and can possibly live lock the system.

Just do not do the RCU unsafe checks when function graph tracer is enabled.

Quoted 6 lines
Quoted 1 line

One question: How does the user/tester/developer know that RCU-unsafe checks have been disabled by function-graph tracing? Would it make sense to print something to dmesg calling this out? Or do the transitions happen too often?

Quoted 4 lines

Ideally, (for 3.13) I plan on having this be a sysctl switch. That will be 1 or 0, depending on if it is enabled or not. But yeah, I can add a printk to show that the kernel changed it. It doesn't happen often, and mainly by a user (or selftest).

It would be good. Sooner or later someone is going to miss the fact that they added an unsafe RCU read-side code sequence because they had the checks suppressed during testing. It would be good to have a way to see that this happened. ;-)

Thanx, Paul

author maintainer
#51 lore raw

RFC PATCH v2 13/18 ftrace: Disable the RCU unsafe checker when irqsoff is enabled

In reply to Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

The irqsoff tracer can be called during some of the RCU unsafe regions. The proble is that some of the internal calls that it makes may also be traced. For example, it uses spin locks. But if the spin lock gets traced and the RCU unsafe checker runs, it will trigger that RCU is not safe to use. But the only reason a spin lock is being used in an RCU unsafe region is because the irqsoff trace uses it, and causes a false positive.

Disable the unsafe RCU checker when irqsoff is enabled.

---
 kernel/trace/trace_irqsoff.c |   16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)
kernel/trace/trace_irqsoff.c +14 -2
index 2aefbee..62d603c 100644
@@ -584,9 +584,14 @@ static int start_irqsoff_tracer(struct trace_array *tr, int graph)
 
 	ret = register_irqsoff_function(graph, 0);
 
-	if (!ret && tracing_is_enabled())
+	if (!ret && tracing_is_enabled()) {
+		/*
+		 * irqsoff tracer can cause unsafe rcu checker
+		 * to have false positives.
+		 */
+		ftrace_unsafe_rcu_checker_disable();
 		tracer_enabled = 1;
-	else
+	} else
 		tracer_enabled = 0;
 
 	return ret;
@@ -594,6 +599,9 @@ static int start_irqsoff_tracer(struct trace_array *tr, int graph)
 
 static void stop_irqsoff_tracer(struct trace_array *tr, int graph)
 {
+	if (tracer_enabled)
+		ftrace_unsafe_rcu_checker_enable();
+
 	tracer_enabled = 0;
 
 	unregister_irqsoff_function(graph);
@@ -630,11 +638,15 @@ static void irqsoff_tracer_reset(struct trace_array *tr)
 
 static void irqsoff_tracer_start(struct trace_array *tr)
 {
+	if (!tracer_enabled)
+		ftrace_unsafe_rcu_checker_disable();
 	tracer_enabled = 1;
 }
 
 static void irqsoff_tracer_stop(struct trace_array *tr)
 {
+	if (tracer_enabled)
+		ftrace_unsafe_rcu_checker_enable();
 	tracer_enabled = 0;
 }
 
Signature · 1 line
1.7.10.4
#52 lore raw

Re: [RFC][PATCH 13/18 v2] ftrace: Disable the RCU unsafe checker when irqsoff is enabled

Quoted 4 lines · Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

The irqsoff tracer can be called during some of the RCU unsafe regions. The proble is that some of the internal calls that it

s/proble/problem/

Quoted 9 lines

makes may also be traced. For example, it uses spin locks. But if the spin lock gets traced and the RCU unsafe checker runs, it will trigger that RCU is not safe to use. But the only reason a spin lock is being used in an RCU unsafe region is because the irqsoff trace uses it, and causes a false positive.

Disable the unsafe RCU checker when irqsoff is enabled.

Looks like a good compromise, as did the previous one involving the function graph tracer. Again, though, should we do something to indicate that RCU safety checks have been disabled?

Thanx, Paul

Quoted 55 lines
---
 kernel/trace/trace_irqsoff.c |   16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)
kernel/trace/trace_irqsoff.c +14 -2
index 2aefbee..62d603c 100644
@@ -584,9 +584,14 @@ static int start_irqsoff_tracer(struct trace_array *tr, int graph)
 
 	ret = register_irqsoff_function(graph, 0);
 
-	if (!ret && tracing_is_enabled())
+	if (!ret && tracing_is_enabled()) {
+		/*
+		 * irqsoff tracer can cause unsafe rcu checker
+		 * to have false positives.
+		 */
+		ftrace_unsafe_rcu_checker_disable();
 		tracer_enabled = 1;
-	else
+	} else
 		tracer_enabled = 0;
 
 	return ret;
@@ -594,6 +599,9 @@ static int start_irqsoff_tracer(struct trace_array *tr, int graph)
 
 static void stop_irqsoff_tracer(struct trace_array *tr, int graph)
 {
+	if (tracer_enabled)
+		ftrace_unsafe_rcu_checker_enable();
+
 	tracer_enabled = 0;
 
 	unregister_irqsoff_function(graph);
@@ -630,11 +638,15 @@ static void irqsoff_tracer_reset(struct trace_array *tr)
 
 static void irqsoff_tracer_start(struct trace_array *tr)
 {
+	if (!tracer_enabled)
+		ftrace_unsafe_rcu_checker_disable();
 	tracer_enabled = 1;
 }
 
 static void irqsoff_tracer_stop(struct trace_array *tr)
 {
+	if (tracer_enabled)
+		ftrace_unsafe_rcu_checker_enable();
 	tracer_enabled = 0;
 }
 
Signature · 1 line
1.7.10.4
author maintainer
#53 lore raw

RFC PATCH v2 14/18 ftrace/lockdep: Have the RCU lockdep splat show what function triggered

In reply to Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

When the RCU lockdep splat hits because of the unsafe RCU checker, the backtrace does not always show the culprit. But the culprit was passed to the unsafe RCU checker.

Save the ip of the function being traced in a per_cpu variable, and when the RCU lockdep detects a problem, it can also print out what function was being traced if it was caused by the unsafe RCU checker.

---
 include/linux/ftrace.h         |    6 ++++++
 kernel/lockdep.c               |    2 ++
 kernel/trace/trace_functions.c |   14 ++++++++++++++
 3 files changed, 22 insertions(+)
include/linux/ftrace.h +6 -0
index 4752764..3dbb946 100644
@@ -885,4 +885,10 @@ unsigned long arch_syscall_addr(int nr);
 
 #endif /* CONFIG_FTRACE_SYSCALLS */
 
+#ifdef CONFIG_FTRACE_UNSAFE_RCU_CHECKER
+extern void print_ftrace_rcu_func(int cpu);
+#else
+static inline void print_ftrace_rcu_func(int cpu) { }
+#endif
+
 #endif /* _LINUX_FTRACE_H */
kernel/lockdep.c +2 -0
index e16c45b..74272ed 100644
@@ -4229,6 +4229,8 @@ void lockdep_rcu_suspicious(const char *file, const int line, const char *s)
 				: "",
 	       rcu_scheduler_active, debug_locks);
 
+	print_ftrace_rcu_func(raw_smp_processor_id());
+
 	/*
 	 * If a CPU is in the RCU-free window in idle (ie: in the section
 	 * between rcu_idle_enter() and rcu_idle_exit(), then RCU
kernel/trace/trace_functions.c +14 -0
index 1d5f951..f5a9031 100644
@@ -560,6 +560,7 @@ static inline int init_func_cmd_traceon(void)
 #endif /* CONFIG_DYNAMIC_FTRACE */
 
 #ifdef CONFIG_FTRACE_UNSAFE_RCU_CHECKER
+
 static atomic_t ftrace_unsafe_rcu_disabled;
 
 void ftrace_unsafe_rcu_checker_disable(void)
@@ -572,6 +573,17 @@ void ftrace_unsafe_rcu_checker_enable(void)
 	atomic_dec(&ftrace_unsafe_rcu_disabled);
 }
 
+static DEFINE_PER_CPU(unsigned long, ftrace_rcu_func);
+
+void print_ftrace_rcu_func(int cpu)
+{
+	unsigned long ip = per_cpu(ftrace_rcu_func, cpu);
+
+	if (ip)
+		printk("ftrace_rcu_func: %pS\n",
+		       (void *)per_cpu(ftrace_rcu_func, cpu));
+}
+
 static void
 ftrace_unsafe_callback(unsigned long ip, unsigned long parent_ip,
 		       struct ftrace_ops *op, struct pt_regs *pt_regs)
@@ -592,9 +604,11 @@ ftrace_unsafe_callback(unsigned long ip, unsigned long parent_ip,
 		      (void *)ip))
 		goto out;
 
+	this_cpu_write(ftrace_rcu_func, ip);
 	/* Should trigger a RCU splat if called from unsafe RCU function */
 	rcu_read_lock();
 	rcu_read_unlock();
+	this_cpu_write(ftrace_rcu_func, 0);
 
 	trace_clear_recursion(bit);
  out:
Signature · 1 line
1.7.10.4
Acked-by on v2 14/18
#54 lore raw

Re: [RFC][PATCH 14/18 v2] ftrace/lockdep: Have the RCU lockdep splat show what function triggered

Quoted 6 lines · Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

When the RCU lockdep splat hits because of the unsafe RCU checker, the backtrace does not always show the culprit. But the culprit was passed to the unsafe RCU checker.

Quoted 6 lines

Save the ip of the function being traced in a per_cpu variable, and when the RCU lockdep detects a problem, it can also print out what function was being traced if it was caused by the unsafe RCU checker.

Quoted 80 lines
---
 include/linux/ftrace.h         |    6 ++++++
 kernel/lockdep.c               |    2 ++
 kernel/trace/trace_functions.c |   14 ++++++++++++++
 3 files changed, 22 insertions(+)
include/linux/ftrace.h +6 -0
index 4752764..3dbb946 100644
@@ -885,4 +885,10 @@ unsigned long arch_syscall_addr(int nr);
 
 #endif /* CONFIG_FTRACE_SYSCALLS */
 
+#ifdef CONFIG_FTRACE_UNSAFE_RCU_CHECKER
+extern void print_ftrace_rcu_func(int cpu);
+#else
+static inline void print_ftrace_rcu_func(int cpu) { }
+#endif
+
 #endif /* _LINUX_FTRACE_H */
kernel/lockdep.c +2 -0
index e16c45b..74272ed 100644
@@ -4229,6 +4229,8 @@ void lockdep_rcu_suspicious(const char *file, const int line, const char *s)
 				: "",
 	       rcu_scheduler_active, debug_locks);
 
+	print_ftrace_rcu_func(raw_smp_processor_id());
+
 	/*
 	 * If a CPU is in the RCU-free window in idle (ie: in the section
 	 * between rcu_idle_enter() and rcu_idle_exit(), then RCU
kernel/trace/trace_functions.c +14 -0
index 1d5f951..f5a9031 100644
@@ -560,6 +560,7 @@ static inline int init_func_cmd_traceon(void)
 #endif /* CONFIG_DYNAMIC_FTRACE */
 
 #ifdef CONFIG_FTRACE_UNSAFE_RCU_CHECKER
+
 static atomic_t ftrace_unsafe_rcu_disabled;
 
 void ftrace_unsafe_rcu_checker_disable(void)
@@ -572,6 +573,17 @@ void ftrace_unsafe_rcu_checker_enable(void)
 	atomic_dec(&ftrace_unsafe_rcu_disabled);
 }
 
+static DEFINE_PER_CPU(unsigned long, ftrace_rcu_func);
+
+void print_ftrace_rcu_func(int cpu)
+{
+	unsigned long ip = per_cpu(ftrace_rcu_func, cpu);
+
+	if (ip)
+		printk("ftrace_rcu_func: %pS\n",
+		       (void *)per_cpu(ftrace_rcu_func, cpu));
+}
+
 static void
 ftrace_unsafe_callback(unsigned long ip, unsigned long parent_ip,
 		       struct ftrace_ops *op, struct pt_regs *pt_regs)
@@ -592,9 +604,11 @@ ftrace_unsafe_callback(unsigned long ip, unsigned long parent_ip,
 		      (void *)ip))
 		goto out;
 
+	this_cpu_write(ftrace_rcu_func, ip);
 	/* Should trigger a RCU splat if called from unsafe RCU function */
 	rcu_read_lock();
 	rcu_read_unlock();
+	this_cpu_write(ftrace_rcu_func, 0);
 
 	trace_clear_recursion(bit);
  out:
Signature · 1 line
1.7.10.4
maintainer
#55 lore raw

Re: [RFC][PATCH 14/18 v2] ftrace/lockdep: Have the RCU lockdep splat show what function triggered

In reply to Steven Rostedt

kernel/trace/trace_functions.c void ftrace_unsafe_rcu_checker_enable(void) · line 585

Quoted 8 lines · Steven Rostedt
kernel/trace/trace_functions.c +8 -0
+void print_ftrace_rcu_func(int cpu)
+{
+	unsigned long ip = per_cpu(ftrace_rcu_func, cpu);
+
+	if (ip)
+		printk("ftrace_rcu_func: %pS\n",
+		       (void *)per_cpu(ftrace_rcu_func, cpu));
+}

That's missing { }.

author maintainer
#56 lore raw

Re: [RFC][PATCH 14/18 v2] ftrace/lockdep: Have the RCU lockdep splat show what function triggered

Quoted 11 lines · On Thu, 5 Sep 2013 21:18:39 +0200 Peter Zijlstra <[email protected]> wrote:

kernel/trace/trace_functions.c void ftrace_unsafe_rcu_checker_enable(void) · line 585

Quoted 8 lines · Steven Rostedt
kernel/trace/trace_functions.c +8 -0
+void print_ftrace_rcu_func(int cpu)
+{
+	unsigned long ip = per_cpu(ftrace_rcu_func, cpu);
+
+	if (ip)
+		printk("ftrace_rcu_func: %pS\n",
+		       (void *)per_cpu(ftrace_rcu_func, cpu));
+}

That's missing { }.

Hmm, that's an interesting point. Why the { } because I break up the printk for the 80 character limit?

Although, I'm still not convinced that it needs { }, as it looks to me that it flows nicely without it. I can't find a place in CodingStyle that says { } are needed here.

-- Steve

#57 lore raw

Re: [RFC][PATCH 14/18 v2] ftrace/lockdep: Have the RCU lockdep splat show what function triggered

Quoted 15 lines · Steven Rostedt
Quoted 11 lines · On Thu, 5 Sep 2013 21:18:39 +0200 Peter Zijlstra <[email protected]> wrote:

kernel/trace/trace_functions.c void ftrace_unsafe_rcu_checker_enable(void) · line 585

Quoted 8 lines · Steven Rostedt
kernel/trace/trace_functions.c +8 -0
+void print_ftrace_rcu_func(int cpu)
+{
+	unsigned long ip = per_cpu(ftrace_rcu_func, cpu);
+
+	if (ip)
+		printk("ftrace_rcu_func: %pS\n",
+		       (void *)per_cpu(ftrace_rcu_func, cpu));
+}

That's missing { }.

Quoted 2 lines

Hmm, that's an interesting point. Why the { } because I break up the printk for the 80 character limit?

You probably shouldn't break it up - it looks uglier.

Quoted 3 lines

Although, I'm still not convinced that it needs { }, as it looks to me that it flows nicely without it. I can't find a place in CodingStyle that says { } are needed here.

it's somewhat of a grey area - the section quoted below talks about it broadly - and it's typically understood to apply to multi-line statements as well, as it's easy to overlook and confuse multi-statements with multi-line statements...

Thanks,

Ingo

----------------------->

Do not unnecessarily use braces where a single statement will do.

if (condition)

        action();

and

if (condition)

        do_this();
else
        do_that();

This does not apply if only one branch of a conditional statement is a single statement; in the latter case use braces in both branches:

if (condition) {
        do_this();
        do_that();
} else {
        otherwise();
}
author maintainer
#58 lore raw

Re: [RFC][PATCH 14/18 v2] ftrace/lockdep: Have the RCU lockdep splat show what function triggered

Quoted 18 lines · On Fri, 6 Sep 2013 14:57:19 +0200 Ingo Molnar <[email protected]> wrote:
Quoted 15 lines · Steven Rostedt
Quoted 11 lines · On Thu, 5 Sep 2013 21:18:39 +0200 Peter Zijlstra <[email protected]> wrote:

kernel/trace/trace_functions.c void ftrace_unsafe_rcu_checker_enable(void) · line 585

Quoted 8 lines · Steven Rostedt
kernel/trace/trace_functions.c +8 -0
+void print_ftrace_rcu_func(int cpu)
+{
+	unsigned long ip = per_cpu(ftrace_rcu_func, cpu);
+
+	if (ip)
+		printk("ftrace_rcu_func: %pS\n",
+		       (void *)per_cpu(ftrace_rcu_func, cpu));
+}

That's missing { }.

Quoted 4 lines
Quoted 2 lines

Hmm, that's an interesting point. Why the { } because I break up the printk for the 80 character limit?

You probably shouldn't break it up - it looks uglier.

I thought for printk's it was fine to break after the comma, just not the printk format line. That is,

	printk("ftrace_rcu_func: %pS\n", (void *)per_cpu(ftrace_rcu_func, cpu));

can go to:

	printk("ftrace_rcu_func: %pS\n",
	       (void *)per_cpu(ftrace_rcu_func, cpu));

But

	printk("this is a really long line and it goes on forever and might be too much to break up\n");

can't go to:

	printk("this is a really long line and it goes on forever and"
		" might be too much to break up\n");
Quoted 9 lines
Quoted 4 lines

Although, I'm still not convinced that it needs { }, as it looks to me that it flows nicely without it. I can't find a place in CodingStyle that says { } are needed here.

it's somewhat of a grey area - the section quoted below talks about it broadly - and it's typically understood to apply to multi-line statements as well, as it's easy to overlook and confuse multi-statements with multi-line statements...

Yeah, I read that part too.

Anyway, this conversation is all moot, as the patch is on hold, and we may have a better way to solve this anyway, making the patch obsolete.

Thanks,

-- Steve

maintainer
#59 lore raw

Re: [RFC][PATCH 14/18 v2] ftrace/lockdep: Have the RCU lockdep splat show what function triggered

In reply to Steven Rostedt
Quoted 1 line · Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

Why put RHT in there? Surely greg and jonathan know you work for them? :-)

Quoted 7 lines

When the RCU lockdep splat hits because of the unsafe RCU checker, the backtrace does not always show the culprit. But the culprit was passed to the unsafe RCU checker.

Save the ip of the function being traced in a per_cpu variable, and when the RCU lockdep detects a problem, it can also print out what function was being traced if it was caused by the unsafe RCU checker.

So the below is an example of why this_cpu_* is utter shite, what ensures the code there isn't preemptible.

That said, I suppose you've thought about that and there's something obvious from the callpath but I can't be bothered to go hunt through the series if the changelog can't be bothered to clarify such things.

kernel/trace/trace_functions.c ftrace_unsafe_callback(unsigned long ip, unsigned long parent_ip, · line 614

Quoted 12 lines
kernel/trace/trace_functions.c +2 -0
@@ -592,9 +604,11 @@ ftrace_unsafe_callback(unsigned long ip, unsigned long parent_ip,
 		      (void *)ip))
 		goto out;
 
+	this_cpu_write(ftrace_rcu_func, ip);
 	/* Should trigger a RCU splat if called from unsafe RCU function */
 	rcu_read_lock();
 	rcu_read_unlock();
+	this_cpu_write(ftrace_rcu_func, 0);
 
 	trace_clear_recursion(bit);
  out:

I suppose this is all ok. I haven't read the entire series and I'm not going to during my vacation.

One quick question though, why do we have to mark functions and can't rely on the state RCU already keeps? Surely RCU knows when its 'enabled' and thus safe to use RCU -- if only for debuggin.

For instance that scheduler_ipi() call can happen in either state, do we really have to disallow it always?

Anyway, I suppose ACK on both these patches you asked me to look at, not particularly harmful it seems, just not something I feel I've got me head round atm.

author maintainer
#60 lore raw

Re: [RFC][PATCH 14/18 v2] ftrace/lockdep: Have the RCU lockdep splat show what function triggered

Quoted 6 lines · On Thu, 5 Sep 2013 21:35:53 +0200 Peter Zijlstra <[email protected]> wrote:
Quoted 1 line · Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

Why put RHT in there? Surely greg and jonathan know you work for them? :-)

It has nothing to do with Greg or Jonathan. Even though I think they both told me the same thing. It has to do with anyone looking at a git commit, and they will know that my work on this commit was sponsored by Red Hat. Has nothing to do with those silly stat numbers that come out every release ;-)

Quoted 10 lines
Quoted 7 lines

When the RCU lockdep splat hits because of the unsafe RCU checker, the backtrace does not always show the culprit. But the culprit was passed to the unsafe RCU checker.

Save the ip of the function being traced in a per_cpu variable, and when the RCU lockdep detects a problem, it can also print out what function was being traced if it was caused by the unsafe RCU checker.

So the below is an example of why this_cpu_* is utter shite, what ensures the code there isn't preemptible.

No disagreements with me about the utter shite, but what ensures it is what is hidden from the patch. If I expand the code a little, I get this:

        preempt_disable_notrace();

        if (this_cpu_read(ftrace_rcu_running))
                goto out;

        if (WARN_ONCE(ftrace_rcu_unsafe(ip),
                      "UNSAFE RCU function called %pS",
                      (void *)ip))
                goto out;

        this_cpu_write(ftrace_rcu_running, 1);
        this_cpu_write(ftrace_rcu_func, ip);

        /* Should trigger a RCU splat if called from unsafe RCU
        function */ rcu_read_lock();
        rcu_read_unlock();
        this_cpu_write(ftrace_rcu_func, 0);

        this_cpu_write(ftrace_rcu_running, 0);
 out:
        preempt_enable_notrace();
Quoted 21 lines

That said, I suppose you've thought about that and there's something obvious from the callpath but I can't be bothered to go hunt through the series if the changelog can't be bothered to clarify such things.

kernel/trace/trace_functions.c ftrace_unsafe_callback(unsigned long ip, unsigned long parent_ip, · line 614

Quoted 12 lines
kernel/trace/trace_functions.c +2 -0
@@ -592,9 +604,11 @@ ftrace_unsafe_callback(unsigned long ip, unsigned long parent_ip,
 		      (void *)ip))
 		goto out;
 
+	this_cpu_write(ftrace_rcu_func, ip);
 	/* Should trigger a RCU splat if called from unsafe RCU function */
 	rcu_read_lock();
 	rcu_read_unlock();
+	this_cpu_write(ftrace_rcu_func, 0);
 
 	trace_clear_recursion(bit);
  out:

I suppose this is all ok. I haven't read the entire series and I'm not going to during my vacation.

Quoted 3 lines

One quick question though, why do we have to mark functions and can't rely on the state RCU already keeps? Surely RCU knows when its 'enabled' and thus safe to use RCU -- if only for debuggin.

Funny you should say that. I just recently asked Paul about this very topic. It may make most of this patch series moot.

Quoted 3 lines

For instance that scheduler_ipi() call can happen in either state, do we really have to disallow it always?

Nope! The one thing I fear with this method is, is the inconsistency of seeing the scheduler_ipi() traced, and not seeing it. I predict getting nasty bug reports from people telling me that the tracer is broken.

"why don't I see scheduler_ipi() traced here! I see it here!!!! The tracer is shite!"

Quoted 4 lines

Anyway, I suppose ACK on both these patches you asked me to look at, not particularly harmful it seems, just not something I feel I've got me head round atm.

Thanks for taking some of your PTO out to do this! Although, it may all be in vain if I go the RCU state route. I wont need either of these patches then.

-- Steve

author maintainer
#61 lore raw

RFC PATCH v2 15/18 ftrace/rcu: Mark functions that are RCU unsafe

In reply to Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

Some callbacks of the function tracer use rcu_read_lock(). This means that there's places that can not be traced because RCU is not tracking the CPU for various reasons (like NO_HZ_FULL and coming back from userspace).

Thes functions need to be marked so that callbacks that use RCU do not trace them.

Cc Paul E. McKenney <[email protected]>
---
 kernel/rcutiny.c |    1 +
 kernel/rcutree.c |    7 +++++++
 2 files changed, 8 insertions(+)
kernel/rcutiny.c +1 -0
index aa34411..911a61c 100644
@@ -173,6 +173,7 @@ void rcu_irq_enter(void)
 	local_irq_restore(flags);
 }
 EXPORT_SYMBOL_GPL(rcu_irq_enter);
+FTRACE_UNSAFE_RCU(rcu_irq_enter);
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 
kernel/rcutree.c +7 -0
index 068de3a..ca53562 100644
@@ -53,6 +53,7 @@
 #include <linux/delay.h>
 #include <linux/stop_machine.h>
 #include <linux/random.h>
+#include <linux/ftrace.h>
 
 #include "rcutree.h"
 #include <trace/events/rcu.h>
@@ -373,6 +374,7 @@ static void rcu_eqs_enter_common(struct rcu_dynticks *rdtp, long long oldval,
 	rcu_lockdep_assert(!lock_is_held(&rcu_sched_lock_map),
 			   "Illegal idle entry in RCU-sched read-side critical section.");
 }
+FTRACE_UNSAFE_RCU(rcu_eqs_enter_common);
 
 /*
  * Enter an RCU extended quiescent state, which can be either the
@@ -392,6 +394,7 @@ static void rcu_eqs_enter(bool user)
 		rdtp->dynticks_nesting -= DYNTICK_TASK_NEST_VALUE;
 	rcu_eqs_enter_common(rdtp, oldval, user);
 }
+FTRACE_UNSAFE_RCU(rcu_eqs_enter);
 
 /**
  * rcu_idle_enter - inform RCU that current CPU is entering idle
@@ -513,6 +516,7 @@ static void rcu_eqs_exit_common(struct rcu_dynticks *rdtp, long long oldval,
 			  idle->pid, idle->comm); /* must be idle task! */
 	}
 }
+FTRACE_UNSAFE_RCU(rcu_eqs_exit_common);
 
 /*
  * Exit an RCU extended quiescent state, which can be either the
@@ -553,6 +557,7 @@ void rcu_idle_exit(void)
 	local_irq_restore(flags);
 }
 EXPORT_SYMBOL_GPL(rcu_idle_exit);
+FTRACE_UNSAFE_RCU(rcu_idle_exit);
 
 #ifdef CONFIG_RCU_USER_QS
 /**
@@ -565,6 +570,7 @@ void rcu_user_exit(void)
 {
 	rcu_eqs_exit(1);
 }
+FTRACE_UNSAFE_RCU(rcu_user_exit);
 
 /**
  * rcu_user_exit_after_irq - inform RCU that we won't resume to userspace
@@ -625,6 +631,7 @@ void rcu_irq_enter(void)
 		rcu_eqs_exit_common(rdtp, oldval, true);
 	local_irq_restore(flags);
 }
+FTRACE_UNSAFE_RCU(rcu_irq_enter);
 
 /**
  * rcu_nmi_enter - inform RCU of entry to NMI context
Signature · 1 line
1.7.10.4
Reviewed-by on v2 15/18
#62 lore raw

Re: [RFC][PATCH 15/18 v2] ftrace/rcu: Mark functions that are RCU unsafe

Quoted 11 lines · Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

Some callbacks of the function tracer use rcu_read_lock(). This means that there's places that can not be traced because RCU is not tracking the CPU for various reasons (like NO_HZ_FULL and coming back from userspace).

Thes functions need to be marked so that callbacks that use RCU do not trace them.

Cc Paul E. McKenney <[email protected]>

Please let me know if you would like me to take this one. If I don't hear otherwise, I will assume that you are pushing it.

Thanx, Paul

Quoted 81 lines
---
 kernel/rcutiny.c |    1 +
 kernel/rcutree.c |    7 +++++++
 2 files changed, 8 insertions(+)
kernel/rcutiny.c +1 -0
index aa34411..911a61c 100644
@@ -173,6 +173,7 @@ void rcu_irq_enter(void)
 	local_irq_restore(flags);
 }
 EXPORT_SYMBOL_GPL(rcu_irq_enter);
+FTRACE_UNSAFE_RCU(rcu_irq_enter);
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 
kernel/rcutree.c +7 -0
index 068de3a..ca53562 100644
@@ -53,6 +53,7 @@
 #include <linux/delay.h>
 #include <linux/stop_machine.h>
 #include <linux/random.h>
+#include <linux/ftrace.h>
 
 #include "rcutree.h"
 #include <trace/events/rcu.h>
@@ -373,6 +374,7 @@ static void rcu_eqs_enter_common(struct rcu_dynticks *rdtp, long long oldval,
 	rcu_lockdep_assert(!lock_is_held(&rcu_sched_lock_map),
 			   "Illegal idle entry in RCU-sched read-side critical section.");
 }
+FTRACE_UNSAFE_RCU(rcu_eqs_enter_common);
 
 /*
  * Enter an RCU extended quiescent state, which can be either the
@@ -392,6 +394,7 @@ static void rcu_eqs_enter(bool user)
 		rdtp->dynticks_nesting -= DYNTICK_TASK_NEST_VALUE;
 	rcu_eqs_enter_common(rdtp, oldval, user);
 }
+FTRACE_UNSAFE_RCU(rcu_eqs_enter);
 
 /**
  * rcu_idle_enter - inform RCU that current CPU is entering idle
@@ -513,6 +516,7 @@ static void rcu_eqs_exit_common(struct rcu_dynticks *rdtp, long long oldval,
 			  idle->pid, idle->comm); /* must be idle task! */
 	}
 }
+FTRACE_UNSAFE_RCU(rcu_eqs_exit_common);
 
 /*
  * Exit an RCU extended quiescent state, which can be either the
@@ -553,6 +557,7 @@ void rcu_idle_exit(void)
 	local_irq_restore(flags);
 }
 EXPORT_SYMBOL_GPL(rcu_idle_exit);
+FTRACE_UNSAFE_RCU(rcu_idle_exit);
 
 #ifdef CONFIG_RCU_USER_QS
 /**
@@ -565,6 +570,7 @@ void rcu_user_exit(void)
 {
 	rcu_eqs_exit(1);
 }
+FTRACE_UNSAFE_RCU(rcu_user_exit);
 
 /**
  * rcu_user_exit_after_irq - inform RCU that we won't resume to userspace
@@ -625,6 +631,7 @@ void rcu_irq_enter(void)
 		rcu_eqs_exit_common(rdtp, oldval, true);
 	local_irq_restore(flags);
 }
+FTRACE_UNSAFE_RCU(rcu_irq_enter);
 
 /**
  * rcu_nmi_enter - inform RCU of entry to NMI context
Signature · 1 line
1.7.10.4
author maintainer
#63 lore raw

Re: [RFC][PATCH 15/18 v2] ftrace/rcu: Mark functions that are RCU unsafe

Quoted 10 lines · Paul E. McKenney
Quoted 9 lines · Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

Some callbacks of the function tracer use rcu_read_lock(). This means that there's places that can not be traced because RCU is not tracking the CPU for various reasons (like NO_HZ_FULL and coming back from userspace).

Thes functions need to be marked so that callbacks that use RCU do not trace them.

Quoted 8 lines
Quoted 2 lines
Cc Paul E. McKenney <[email protected]>

Please let me know if you would like me to take this one. If I don't hear otherwise, I will assume that you are pushing it.

These I rather take, as they are all dependent on the previous changes.

Thanks!

-- Steve

#64 lore raw

Re: [RFC][PATCH 15/18 v2] ftrace/rcu: Mark functions that are RCU unsafe

Quoted 14 lines · Steven Rostedt
Quoted 13 lines · Paul E. McKenney
Quoted 11 lines · Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

Some callbacks of the function tracer use rcu_read_lock(). This means that there's places that can not be traced because RCU is not tracking the CPU for various reasons (like NO_HZ_FULL and coming back from userspace).

Thes functions need to be marked so that callbacks that use RCU do not trace them.

Cc Paul E. McKenney <[email protected]>
Quoted 7 lines
Quoted 5 lines

Please let me know if you would like me to take this one. If I don't hear otherwise, I will assume that you are pushing it.

These I rather take, as they are all dependent on the previous changes.

Good point, applies to the other one we discussed as well.

Thanx, Paul

author maintainer
#65 lore raw

RFC PATCH v2 16/18 rcu/irq/x86: Mark functions that are RCU unsafe

In reply to Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

Some callbacks of the function tracer use rcu_read_lock(). This means that there's places that can not be traced because RCU is not tracking the CPU for various reasons (like NO_HZ_FULL and coming back from userspace).

Thes functions need to be marked so that callbacks that use RCU do not trace them.

Cc H. Peter Anvin <[email protected]>
Cc Thomas Gleixner <[email protected]>
---
 arch/x86/kernel/apic/apic.c |    2 ++
 arch/x86/kernel/irq.c       |    1 +
 arch/x86/kernel/irq_work.c  |    3 +++
 arch/x86/kernel/smp.c       |    8 ++++++++
 kernel/softirq.c            |    2 ++
 5 files changed, 16 insertions(+)
arch/x86/kernel/apic/apic.c +2 -0
index eca89c5..91af16b 100644
@@ -931,6 +931,7 @@ void __irq_entry smp_apic_timer_interrupt(struct pt_regs *regs)
 
 	set_irq_regs(old_regs);
 }
+FTRACE_UNSAFE_RCU(smp_apic_timer_interrupt);
 
 void __irq_entry smp_trace_apic_timer_interrupt(struct pt_regs *regs)
 {
@@ -952,6 +953,7 @@ void __irq_entry smp_trace_apic_timer_interrupt(struct pt_regs *regs)
 
 	set_irq_regs(old_regs);
 }
+FTRACE_UNSAFE_RCU(smp_trace_apic_timer_interrupt);
 
 int setup_profiling_timer(unsigned int multiplier)
 {
arch/x86/kernel/irq.c +1 -0
index 3a8185c..fccd0d1 100644
@@ -203,6 +203,7 @@ unsigned int __irq_entry do_IRQ(struct pt_regs *regs)
 	set_irq_regs(old_regs);
 	return 1;
 }
+FTRACE_UNSAFE_RCU(do_IRQ);
 
 /*
  * Handler for X86_PLATFORM_IPI_VECTOR.
arch/x86/kernel/irq_work.c +3 -0
index 636a55e..a2199c2 100644
@@ -7,6 +7,7 @@
 #include <linux/kernel.h>
 #include <linux/irq_work.h>
 #include <linux/hardirq.h>
+#include <linux/ftrace.h>
 #include <asm/apic.h>
 #include <asm/trace/irq_vectors.h>
 
@@ -28,6 +29,7 @@ void smp_irq_work_interrupt(struct pt_regs *regs)
 	__smp_irq_work_interrupt();
 	exiting_irq();
 }
+FTRACE_UNSAFE_RCU(smp_irq_work_interrupt);
 
 void smp_trace_irq_work_interrupt(struct pt_regs *regs)
 {
@@ -37,6 +39,7 @@ void smp_trace_irq_work_interrupt(struct pt_regs *regs)
 	trace_irq_work_exit(IRQ_WORK_VECTOR);
 	exiting_irq();
 }
+FTRACE_UNSAFE_RCU(smp_trace_irq_work_interrupt);
 
 void arch_irq_work_raise(void)
 {
arch/x86/kernel/smp.c +8 -0
index cdaa347..3d702ef 100644
@@ -23,6 +23,7 @@
 #include <linux/interrupt.h>
 #include <linux/cpu.h>
 #include <linux/gfp.h>
+#include <linux/ftrace.h>
 
 #include <asm/mtrr.h>
 #include <asm/tlbflush.h>
@@ -175,6 +176,7 @@ asmlinkage void smp_reboot_interrupt(void)
 	stop_this_cpu(NULL);
 	irq_exit();
 }
+FTRACE_UNSAFE_RCU(smp_reboot_interrupt);
 
 static void native_stop_other_cpus(int wait)
 {
@@ -264,6 +266,7 @@ void smp_reschedule_interrupt(struct pt_regs *regs)
 	 * KVM uses this interrupt to force a cpu out of guest mode
 	 */
 }
+FTRACE_UNSAFE_RCU(smp_reschedule_interrupt);
 
 static inline void smp_entering_irq(void)
 {
@@ -288,6 +291,7 @@ void smp_trace_reschedule_interrupt(struct pt_regs *regs)
 	 * KVM uses this interrupt to force a cpu out of guest mode
 	 */
 }
+FTRACE_UNSAFE_RCU(smp_trace_reschedule_interrupt);
 
 static inline void __smp_call_function_interrupt(void)
 {
@@ -301,6 +305,7 @@ void smp_call_function_interrupt(struct pt_regs *regs)
 	__smp_call_function_interrupt();
 	exiting_irq();
 }
+FTRACE_UNSAFE_RCU(smp_call_function_interrupt);
 
 void smp_trace_call_function_interrupt(struct pt_regs *regs)
 {
@@ -310,6 +315,7 @@ void smp_trace_call_function_interrupt(struct pt_regs *regs)
 	trace_call_function_exit(CALL_FUNCTION_VECTOR);
 	exiting_irq();
 }
+FTRACE_UNSAFE_RCU(smp_trace_call_function_interrupt);
 
 static inline void __smp_call_function_single_interrupt(void)
 {
@@ -323,6 +329,7 @@ void smp_call_function_single_interrupt(struct pt_regs *regs)
 	__smp_call_function_single_interrupt();
 	exiting_irq();
 }
+FTRACE_UNSAFE_RCU(smp_call_function_single_interrupt);
 
 void smp_trace_call_function_single_interrupt(struct pt_regs *regs)
 {
@@ -332,6 +339,7 @@ void smp_trace_call_function_single_interrupt(struct pt_regs *regs)
 	trace_call_function_single_exit(CALL_FUNCTION_SINGLE_VECTOR);
 	exiting_irq();
 }
+FTRACE_UNSAFE_RCU(smp_trace_call_function_single_interrupt);
 
 static int __init nonmi_ipi_setup(char *str)
 {
kernel/softirq.c +2 -0
index be3d351..7960e70 100644
@@ -325,6 +325,7 @@ void irq_enter(void)
 
 	__irq_enter();
 }
+FTRACE_UNSAFE_RCU(irq_enter);
 
 static inline void invoke_softirq(void)
 {
@@ -367,6 +368,7 @@ void irq_exit(void)
 	tick_irq_exit();
 	rcu_irq_exit();
 }
+FTRACE_UNSAFE_RCU(irq_exit);
 
 /*
  * This function must run with irqs disabled!
Signature · 1 line
1.7.10.4
Acked-by on v2 16/18
#66 lore raw

Re: [RFC][PATCH 16/18 v2] rcu/irq/x86: Mark functions that are RCU unsafe

Quoted 6 lines · Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

Some callbacks of the function tracer use rcu_read_lock(). This means that there's places that can not be traced because RCU is not tracking the CPU for various reasons (like NO_HZ_FULL and coming back from userspace).

Quoted 6 lines

Thes functions need to be marked so that callbacks that use RCU do not trace them.

Cc H. Peter Anvin <[email protected]>
Cc Thomas Gleixner <[email protected]>
Quoted 160 lines
---
 arch/x86/kernel/apic/apic.c |    2 ++
 arch/x86/kernel/irq.c       |    1 +
 arch/x86/kernel/irq_work.c  |    3 +++
 arch/x86/kernel/smp.c       |    8 ++++++++
 kernel/softirq.c            |    2 ++
 5 files changed, 16 insertions(+)
arch/x86/kernel/apic/apic.c +2 -0
index eca89c5..91af16b 100644
@@ -931,6 +931,7 @@ void __irq_entry smp_apic_timer_interrupt(struct pt_regs *regs)
 
 	set_irq_regs(old_regs);
 }
+FTRACE_UNSAFE_RCU(smp_apic_timer_interrupt);
 
 void __irq_entry smp_trace_apic_timer_interrupt(struct pt_regs *regs)
 {
@@ -952,6 +953,7 @@ void __irq_entry smp_trace_apic_timer_interrupt(struct pt_regs *regs)
 
 	set_irq_regs(old_regs);
 }
+FTRACE_UNSAFE_RCU(smp_trace_apic_timer_interrupt);
 
 int setup_profiling_timer(unsigned int multiplier)
 {
arch/x86/kernel/irq.c +1 -0
index 3a8185c..fccd0d1 100644
@@ -203,6 +203,7 @@ unsigned int __irq_entry do_IRQ(struct pt_regs *regs)
 	set_irq_regs(old_regs);
 	return 1;
 }
+FTRACE_UNSAFE_RCU(do_IRQ);
 
 /*
  * Handler for X86_PLATFORM_IPI_VECTOR.
arch/x86/kernel/irq_work.c +3 -0
index 636a55e..a2199c2 100644
@@ -7,6 +7,7 @@
 #include <linux/kernel.h>
 #include <linux/irq_work.h>
 #include <linux/hardirq.h>
+#include <linux/ftrace.h>
 #include <asm/apic.h>
 #include <asm/trace/irq_vectors.h>
 
@@ -28,6 +29,7 @@ void smp_irq_work_interrupt(struct pt_regs *regs)
 	__smp_irq_work_interrupt();
 	exiting_irq();
 }
+FTRACE_UNSAFE_RCU(smp_irq_work_interrupt);
 
 void smp_trace_irq_work_interrupt(struct pt_regs *regs)
 {
@@ -37,6 +39,7 @@ void smp_trace_irq_work_interrupt(struct pt_regs *regs)
 	trace_irq_work_exit(IRQ_WORK_VECTOR);
 	exiting_irq();
 }
+FTRACE_UNSAFE_RCU(smp_trace_irq_work_interrupt);
 
 void arch_irq_work_raise(void)
 {
arch/x86/kernel/smp.c +8 -0
index cdaa347..3d702ef 100644
@@ -23,6 +23,7 @@
 #include <linux/interrupt.h>
 #include <linux/cpu.h>
 #include <linux/gfp.h>
+#include <linux/ftrace.h>
 
 #include <asm/mtrr.h>
 #include <asm/tlbflush.h>
@@ -175,6 +176,7 @@ asmlinkage void smp_reboot_interrupt(void)
 	stop_this_cpu(NULL);
 	irq_exit();
 }
+FTRACE_UNSAFE_RCU(smp_reboot_interrupt);
 
 static void native_stop_other_cpus(int wait)
 {
@@ -264,6 +266,7 @@ void smp_reschedule_interrupt(struct pt_regs *regs)
 	 * KVM uses this interrupt to force a cpu out of guest mode
 	 */
 }
+FTRACE_UNSAFE_RCU(smp_reschedule_interrupt);
 
 static inline void smp_entering_irq(void)
 {
@@ -288,6 +291,7 @@ void smp_trace_reschedule_interrupt(struct pt_regs *regs)
 	 * KVM uses this interrupt to force a cpu out of guest mode
 	 */
 }
+FTRACE_UNSAFE_RCU(smp_trace_reschedule_interrupt);
 
 static inline void __smp_call_function_interrupt(void)
 {
@@ -301,6 +305,7 @@ void smp_call_function_interrupt(struct pt_regs *regs)
 	__smp_call_function_interrupt();
 	exiting_irq();
 }
+FTRACE_UNSAFE_RCU(smp_call_function_interrupt);
 
 void smp_trace_call_function_interrupt(struct pt_regs *regs)
 {
@@ -310,6 +315,7 @@ void smp_trace_call_function_interrupt(struct pt_regs *regs)
 	trace_call_function_exit(CALL_FUNCTION_VECTOR);
 	exiting_irq();
 }
+FTRACE_UNSAFE_RCU(smp_trace_call_function_interrupt);
 
 static inline void __smp_call_function_single_interrupt(void)
 {
@@ -323,6 +329,7 @@ void smp_call_function_single_interrupt(struct pt_regs *regs)
 	__smp_call_function_single_interrupt();
 	exiting_irq();
 }
+FTRACE_UNSAFE_RCU(smp_call_function_single_interrupt);
 
 void smp_trace_call_function_single_interrupt(struct pt_regs *regs)
 {
@@ -332,6 +339,7 @@ void smp_trace_call_function_single_interrupt(struct pt_regs *regs)
 	trace_call_function_single_exit(CALL_FUNCTION_SINGLE_VECTOR);
 	exiting_irq();
 }
+FTRACE_UNSAFE_RCU(smp_trace_call_function_single_interrupt);
 
 static int __init nonmi_ipi_setup(char *str)
 {
kernel/softirq.c +2 -0
index be3d351..7960e70 100644
@@ -325,6 +325,7 @@ void irq_enter(void)
 
 	__irq_enter();
 }
+FTRACE_UNSAFE_RCU(irq_enter);
 
 static inline void invoke_softirq(void)
 {
@@ -367,6 +368,7 @@ void irq_exit(void)
 	tick_irq_exit();
 	rcu_irq_exit();
 }
+FTRACE_UNSAFE_RCU(irq_exit);
 
 /*
  * This function must run with irqs disabled!
Signature · 1 line
1.7.10.4
author maintainer
#67 lore raw

RFC PATCH v2 17/18 ftrace/cpuidle/x86: Mark functions that are RCU unsafe

In reply to Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

Some callbacks of the function tracer use rcu_read_lock(). This means that there's places that can not be traced because RCU is not tracking the CPU for various reasons (like NO_HZ_FULL and coming back from userspace).

Thes functions need to be marked so that callbacks that use RCU do not trace them.

Cc H. Peter Anvin <[email protected]>
Cc Rafael J. Wysocki <[email protected]>
---
 arch/x86/kernel/process.c |    2 ++
 drivers/cpuidle/cpuidle.c |    2 ++
 kernel/cpu/idle.c         |    2 ++
 3 files changed, 6 insertions(+)
arch/x86/kernel/process.c +2 -0
index 83369e5..18739cd 100644
@@ -17,6 +17,7 @@
 #include <linux/stackprotector.h>
 #include <linux/tick.h>
 #include <linux/cpuidle.h>
+#include <linux/ftrace.h>
 #include <trace/events/power.h>
 #include <linux/hw_breakpoint.h>
 #include <asm/cpu.h>
@@ -316,6 +317,7 @@ void default_idle(void)
 #ifdef CONFIG_APM_MODULE
 EXPORT_SYMBOL(default_idle);
 #endif
+FTRACE_UNSAFE_RCU(default_idle);
 
 #ifdef CONFIG_XEN
 bool xen_set_default_idle(void)
drivers/cpuidle/cpuidle.c +2 -0
index fdc432f..9515457 100644
@@ -19,6 +19,7 @@
 #include <linux/ktime.h>
 #include <linux/hrtimer.h>
 #include <linux/module.h>
+#include <linux/ftrace.h>
 #include <trace/events/power.h>
 
 #include "cpuidle.h"
@@ -168,6 +169,7 @@ int cpuidle_idle_call(void)
 
 	return 0;
 }
+FTRACE_UNSAFE_RCU(cpuidle_idle_call);
 
 /**
  * cpuidle_install_idle_handler - installs the cpuidle idle loop handler
kernel/cpu/idle.c +2 -0
index e695c0a..d9d290f 100644
@@ -5,6 +5,7 @@
 #include <linux/cpu.h>
 #include <linux/tick.h>
 #include <linux/mm.h>
+#include <linux/ftrace.h>
 #include <linux/stackprotector.h>
 
 #include <asm/tlb.h>
@@ -61,6 +62,7 @@ void __weak arch_cpu_idle(void)
 	cpu_idle_force_poll = 1;
 	local_irq_enable();
 }
+FTRACE_UNSAFE_RCU(arch_cpu_idle);
 
 /*
  * Generic idle loop implementation
Signature · 1 line
1.7.10.4
Acked-by on v2 17/18
#68 lore raw

RE: [RFC][PATCH 17/18 v2] ftrace/cpuidle/x86: Mark functions that are RCU unsafe

Sent from a tablet, I apologize for formatting issues.

Steven Rostedt <[email protected]> wrote:
From: "Steven Rostedt (Red Hat)" <[email protected]>

Some callbacks of the function tracer use rcu_read_lock(). This means that there's places that can not be traced because RCU is not tracking the CPU for various reasons (like NO_HZ_FULL and coming back from userspace).

Thes functions need to be marked so that callbacks that use RCU do not trace them.

Cc H. Peter Anvin <[email protected]>
Cc Rafael J. Wysocki <[email protected]>
---
 arch/x86/kernel/process.c |    2 ++
 drivers/cpuidle/cpuidle.c |    2 ++
 kernel/cpu/idle.c         |    2 ++
 3 files changed, 6 insertions(+)
arch/x86/kernel/process.c +2 -0
index 83369e5..18739cd 100644
@@ -17,6 +17,7 @@
 #include <linux/stackprotector.h>
 #include <linux/tick.h>
 #include <linux/cpuidle.h>
+#include <linux/ftrace.h>
 #include <trace/events/power.h>
 #include <linux/hw_breakpoint.h>
 #include <asm/cpu.h>
@@ -316,6 +317,7 @@ void default_idle(void)
 #ifdef CONFIG_APM_MODULE
 EXPORT_SYMBOL(default_idle);
 #endif
+FTRACE_UNSAFE_RCU(default_idle);
 
 #ifdef CONFIG_XEN
 bool xen_set_default_idle(void)
drivers/cpuidle/cpuidle.c +2 -0
index fdc432f..9515457 100644
@@ -19,6 +19,7 @@
 #include <linux/ktime.h>
 #include <linux/hrtimer.h>
 #include <linux/module.h>
+#include <linux/ftrace.h>
 #include <trace/events/power.h>
 
 #include "cpuidle.h"
@@ -168,6 +169,7 @@ int cpuidle_idle_call(void)
 
         return 0;
 }
+FTRACE_UNSAFE_RCU(cpuidle_idle_call);
 
 /**
  * cpuidle_install_idle_handler - installs the cpuidle idle loop handler
kernel/cpu/idle.c +2 -0
index e695c0a..d9d290f 100644
@@ -5,6 +5,7 @@
 #include <linux/cpu.h>
 #include <linux/tick.h>
 #include <linux/mm.h>
+#include <linux/ftrace.h>
 #include <linux/stackprotector.h>
 
 #include <asm/tlb.h>
@@ -61,6 +62,7 @@ void __weak arch_cpu_idle(void)
         cpu_idle_force_poll = 1;
         local_irq_enable();
 }
+FTRACE_UNSAFE_RCU(arch_cpu_idle);
 
 /*
  * Generic idle loop implementation

--
1.7.10.4

---------------------------------------------------------------------
Intel Technology Poland sp. z o.o.
ul. Slowackiego 173 | 80-298 Gdansk | Sad Rejonowy Gdansk Polnoc | VII Wydzial Gospodarczy Krajowego Rejestru Sadowego - KRS 101882 | NIP 957-07-52-316 | Kapital zakladowy 200.000 PLN.

Ta wiadomosc wraz z zalacznikami jest przeznaczona dla okreslonego adresata i moze zawierac informacje poufne. W razie przypadkowego otrzymania tej wiadomosci, prosimy o powiadomienie nadawcy oraz trwale jej usuniecie; jakiekolwiek przegladanie lub rozpowszechnianie jest zabronione. This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). If you are not the intended recipient, please contact the sender and delete all copies; any review or distribution by others is strictly prohibited.

Acked-by on v2 17/18
#69 lore raw

Re: [RFC][PATCH 17/18 v2] ftrace/cpuidle/x86: Mark functions that are RCU unsafe

In reply to Steven Rostedt
Quoted 6 lines · Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

Some callbacks of the function tracer use rcu_read_lock(). This means that there's places that can not be traced because RCU is not tracking the CPU for various reasons (like NO_HZ_FULL and coming back from userspace).

Quoted 6 lines

Thes functions need to be marked so that callbacks that use RCU do not trace them.

Cc H. Peter Anvin <[email protected]>
Cc Rafael J. Wysocki <[email protected]>
Quoted 70 lines
---
 arch/x86/kernel/process.c |    2 ++
 drivers/cpuidle/cpuidle.c |    2 ++
 kernel/cpu/idle.c         |    2 ++
 3 files changed, 6 insertions(+)
arch/x86/kernel/process.c +2 -0
index 83369e5..18739cd 100644
@@ -17,6 +17,7 @@
 #include <linux/stackprotector.h>
 #include <linux/tick.h>
 #include <linux/cpuidle.h>
+#include <linux/ftrace.h>
 #include <trace/events/power.h>
 #include <linux/hw_breakpoint.h>
 #include <asm/cpu.h>
@@ -316,6 +317,7 @@ void default_idle(void)
 #ifdef CONFIG_APM_MODULE
 EXPORT_SYMBOL(default_idle);
 #endif
+FTRACE_UNSAFE_RCU(default_idle);
 
 #ifdef CONFIG_XEN
 bool xen_set_default_idle(void)
drivers/cpuidle/cpuidle.c +2 -0
index fdc432f..9515457 100644
@@ -19,6 +19,7 @@
 #include <linux/ktime.h>
 #include <linux/hrtimer.h>
 #include <linux/module.h>
+#include <linux/ftrace.h>
 #include <trace/events/power.h>
 
 #include "cpuidle.h"
@@ -168,6 +169,7 @@ int cpuidle_idle_call(void)
 
 	return 0;
 }
+FTRACE_UNSAFE_RCU(cpuidle_idle_call);
 
 /**
  * cpuidle_install_idle_handler - installs the cpuidle idle loop handler
kernel/cpu/idle.c +2 -0
index e695c0a..d9d290f 100644
@@ -5,6 +5,7 @@
 #include <linux/cpu.h>
 #include <linux/tick.h>
 #include <linux/mm.h>
+#include <linux/ftrace.h>
 #include <linux/stackprotector.h>
 
 #include <asm/tlb.h>
@@ -61,6 +62,7 @@ void __weak arch_cpu_idle(void)
 	cpu_idle_force_poll = 1;
 	local_irq_enable();
 }
+FTRACE_UNSAFE_RCU(arch_cpu_idle);
 
 /*
  * Generic idle loop implementation
Signature · 1 line
1.7.10.4
reviewer Acked-by on v2 17/18
#70 lore raw

Re: [RFC][PATCH 17/18 v2] ftrace/cpuidle/x86: Mark functions that are RCU unsafe

In reply to Steven Rostedt
Quoted 6 lines · Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

Some callbacks of the function tracer use rcu_read_lock(). This means that there's places that can not be traced because RCU is not tracking the CPU for various reasons (like NO_HZ_FULL and coming back from userspace).

Quoted 6 lines

Thes functions need to be marked so that callbacks that use RCU do not trace them.

Cc H. Peter Anvin <[email protected]>
Cc Rafael J. Wysocki <[email protected]>
author maintainer
#71 lore raw

RFC PATCH v2 18/18 ftrace/sched: Mark functions that are RCU unsafe

In reply to Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

Some callbacks of the function tracer use rcu_read_lock(). This means that there's places that can not be traced because RCU is not tracking the CPU for various reasons (like NO_HZ_FULL and coming back from userspace).

Thes functions need to be marked so that callbacks that use RCU do not trace them.

---
 kernel/sched/core.c |    2 ++
 1 file changed, 2 insertions(+)
kernel/sched/core.c +2 -0
index b7c32cb..9bd2aea 100644
@@ -1440,6 +1440,7 @@ void scheduler_ipi(void)
 	}
 	irq_exit();
 }
+FTRACE_UNSAFE_RCU(scheduler_ipi);
 
 static void ttwu_queue_remote(struct task_struct *p, int cpu)
 {
@@ -3222,6 +3223,7 @@ int idle_cpu(int cpu)
 
 	return 1;
 }
+FTRACE_UNSAFE_RCU(idle_cpu);
 
 /**
  * idle_task - return the idle task for a given cpu.
Signature · 1 line
1.7.10.4
Acked-by on v2 18/18
#72 lore raw

Re: [RFC][PATCH 18/18 v2] ftrace/sched: Mark functions that are RCU unsafe

Quoted 11 lines · Steven Rostedt

From: "Steven Rostedt (Red Hat)" <[email protected]>

Some callbacks of the function tracer use rcu_read_lock(). This means that there's places that can not be traced because RCU is not tracking the CPU for various reasons (like NO_HZ_FULL and coming back from userspace).

Thes functions need to be marked so that callbacks that use RCU do not trace them.

Quoted 28 lines
---
 kernel/sched/core.c |    2 ++
 1 file changed, 2 insertions(+)
kernel/sched/core.c +2 -0
index b7c32cb..9bd2aea 100644
@@ -1440,6 +1440,7 @@ void scheduler_ipi(void)
 	}
 	irq_exit();
 }
+FTRACE_UNSAFE_RCU(scheduler_ipi);
 
 static void ttwu_queue_remote(struct task_struct *p, int cpu)
 {
@@ -3222,6 +3223,7 @@ int idle_cpu(int cpu)
 
 	return 1;
 }
+FTRACE_UNSAFE_RCU(idle_cpu);
 
 /**
  * idle_task - return the idle task for a given cpu.
Signature · 1 line
1.7.10.4
author maintainer
#73 lore raw
In reply to Steven Rostedt
Quoted 3 lines · On Sat, 31 Aug 2013 01:11:17 -0400 Steven Rostedt <[email protected]> wrote:

This is my final draft of the patches. I'm starting to run them through my formal tests now. They may change depending on the outcome of the tests.

Update: All my formal tests passed.

Quoted 4 lines

I'm also a bit tired, and I added the change logs last. Thus I may need to go back and fix the change logs up too. But the code was done when I was rather spunky. But that doesn't mean I didn't break anything.

I still probably need to update the change logs.

But other than that, I'm waiting on Acks or comments.

Thanks!

-- Steve