Skip to contentSkip to conversation

rcutorture updates for 3.12

PATCH In review Paul E. McKenney 4 participants 30 messages Aug 18, 2013 – Aug 25, 2013

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover rcutorture updates for 3.12

Hello!

This series provides some rcutorture updates:

1. Add a debug_object option to rcutorture to allow testing
of RCU's debug-objects facilities.

2. Increase rcutorture test coverage by concurrently testing
synchronous, asynchronous, and expedited grace periods.

3. Sort the extensive list of rcutorture module parameters.

4. Remove the unused "oldbatch" variable.

5. Emit CPU-online failure message to the console.

Thanx, Paul

 b/Documentation/RCU/torture.txt |   10 +
 b/kernel/rcutorture.c           |  341 ++++++++++++++++------------------------
 2 files changed, 151 insertions(+), 200 deletions(-)
#1 lore raw

PATCH 1/5 rcu: Add duplicate-callback tests to rcutorture

From: "Paul E. McKenney" <[email protected]>

This commit adds a object_debug option to rcutorture to allow the debug-object-based checks for duplicate call_rcu() invocations to be deterministically tested.

Cc Mathieu Desnoyers <[email protected]>
Cc Sedat Dilek <[email protected]>
Cc Davidlohr Bueso <[email protected]>
Cc Rik van Riel <[email protected]>
Cc Thomas Gleixner <[email protected]>
Cc Linus Torvalds <[email protected]>
---
 kernel/rcutorture.c | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)
kernel/rcutorture.c +37 -0
index 3d936f0f..efb1c74 100644
@@ -66,6 +66,7 @@ static int fqs_duration;	/* Duration of bursts (us), 0 to disable. */
 static int fqs_holdoff;		/* Hold time within burst (us). */
 static int fqs_stutter = 3;	/* Wait time between bursts (s). */
 static int n_barrier_cbs;	/* Number of callbacks to test RCU barriers. */
+static int object_debug;	/* Test object-debug double call_rcu()?. */
 static int onoff_interval;	/* Wait time between CPU hotplugs, 0=disable. */
 static int onoff_holdoff;	/* Seconds after boot before CPU hotplugs. */
 static int shutdown_secs;	/* Shutdown time (s).  <=0 for no shutdown. */
@@ -100,6 +101,8 @@ module_param(fqs_stutter, int, 0444);
 MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)");
 module_param(n_barrier_cbs, int, 0444);
 MODULE_PARM_DESC(n_barrier_cbs, "# of callbacks/kthreads for barrier testing");
+module_param(object_debug, int, 0444);
+MODULE_PARM_DESC(object_debug, "Enable debug-object double call_rcu() testing");
 module_param(onoff_interval, int, 0444);
 MODULE_PARM_DESC(onoff_interval, "Time between CPU hotplugs (s), 0=disable");
 module_param(onoff_holdoff, int, 0444);
@@ -1934,6 +1937,18 @@ rcu_torture_cleanup(void)
 		rcu_torture_print_module_parms(cur_ops, "End of test: SUCCESS");
 }
 
+#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
+static void rcu_torture_leak_cb(struct rcu_head *rhp)
+{
+}
+
+static void rcu_torture_err_cb(struct rcu_head *rhp)
+{
+	/* This -might- happen due to race conditions, but is unlikely. */
+	pr_alert("rcutorture: duplicated callback was invoked.\n");
+}
+#endif /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
+
 static int __init
 rcu_torture_init(void)
 {
@@ -2163,6 +2178,28 @@ rcu_torture_init(void)
 		firsterr = retval;
 		goto unwind;
 	}
+	if (object_debug) {
+#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
+		struct rcu_head rh1;
+		struct rcu_head rh2;
+
+		init_rcu_head_on_stack(&rh1);
+		init_rcu_head_on_stack(&rh2);
+		pr_alert("rcutorture: WARN: Duplicate call_rcu() test starting.\n");
+		local_irq_disable(); /* Make it hard to finish grace period. */
+		call_rcu(&rh1, rcu_torture_leak_cb); /* start grace period. */
+		call_rcu(&rh2, rcu_torture_err_cb);
+		call_rcu(&rh2, rcu_torture_err_cb); /* duplicate callback. */
+		local_irq_enable();
+		rcu_barrier();
+		pr_alert("rcutorture: WARN: Duplicate call_rcu() test complete.\n");
+		destroy_rcu_head_on_stack(&rh1);
+		destroy_rcu_head_on_stack(&rh2);
+#else /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
+		pr_alert("rcutorture: !%s, not testing duplicate call_rcu()\n",
+			 "CONFIG_DEBUG_OBJECTS_RCU_HEAD");
+#endif /* #else #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
+	}
 	rcutorture_record_test_transition();
 	mutex_unlock(&fullstop_mutex);
 	return 0;
Signature · 1 line
1.8.1.5
#2 lore raw

PATCH 2/5 rcu: Increase rcutorture test coverage

From: "Paul E. McKenney" <[email protected]>

Currently, rcutorture has separate torture_types to test synchronous, asynchronous, and expedited grace-period primitives. This has two disadvantages: (1) Three times the number of runs to cover the combinations and (2) Little testing of concurrent combinations of the three options. This commit therefore adds a pair of module parameters that control normal and expedited state, with the default being both types, randomly selected, by the fakewriter processes, thus reducing source-code size and increasing test coverage. In addtion, the writer task switches between asynchronous-normal and expedited grace-period primitives driven by the same pair of module parameters.

---
 Documentation/RCU/torture.txt |  10 ++
 kernel/rcutorture.c           | 226 ++++++++++++------------------------------
 2 files changed, 73 insertions(+), 163 deletions(-)
Documentation/RCU/torture.txt +10 -0
index d8a5023..dac02a6 100644
@@ -42,6 +42,16 @@ fqs_holdoff	Holdoff time (in microseconds) between consecutive calls
 fqs_stutter	Wait time (in seconds) between consecutive bursts
 		of calls to force_quiescent_state().
 
+gp_normal	Make the fake writers use normal synchronous grace-period
+		primitives.
+
+gp_exp		Make the fake writers use expedited synchronous grace-period
+		primitives.  If both gp_normal and gp_exp are set, or
+		if neither gp_normal nor gp_exp are set, then randomly
+		choose the primitive so that about 50% are normal and
+		50% expedited.  By default, neither are set, which
+		gives best overall test coverage.
+
 irqreader	Says to invoke RCU readers from irq level.  This is currently
 		done via timers.  Defaults to "1" for variants of RCU that
 		permit this.  (Or, more accurately, variants of RCU that do
kernel/rcutorture.c +63 -163

342 lines not on this page · raw message

Signature · 1 line
1.8.1.5
#3 lore raw

PATCH 3/5 rcu: Sort rcutorture module parameters

In reply to Paul E. McKenney

From: "Paul E. McKenney" <[email protected]>

There are getting to be too many module parameters to permit the current semi-random order, so this patch orders them.

---
 kernel/rcutorture.c | 68 ++++++++++++++++++++++++++---------------------------
 1 file changed, 34 insertions(+), 34 deletions(-)
kernel/rcutorture.c +34 -34
index be38d4e..be50ebe 100644
@@ -52,81 +52,81 @@
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Paul E. McKenney <[email protected]> and Josh Triplett <[email protected]>");
 
-static int nreaders = -1;	/* # reader threads, defaults to 2*ncpus */
-static int nfakewriters = 4;	/* # fake writer threads */
-static int stat_interval = 60;	/* Interval between stats, in seconds. */
-				/*  Zero means "only at end of test". */
-static bool verbose;		/* Print more debug info. */
-static bool test_no_idle_hz = true;
-				/* Test RCU support for tickless idle CPUs. */
-static int shuffle_interval = 3; /* Interval between shuffles (in sec)*/
-static int stutter = 5;		/* Start/stop testing interval (in sec) */
-static int irqreader = 1;	/* RCU readers from irq (timers). */
 static int fqs_duration;	/* Duration of bursts (us), 0 to disable. */
 static int fqs_holdoff;		/* Hold time within burst (us). */
 static int fqs_stutter = 3;	/* Wait time between bursts (s). */
 static bool gp_exp;		/* Use expedited GP wait primitives. */
 static bool gp_normal;		/* Use normal GP wait primitives. */
+static int irqreader = 1;	/* RCU readers from irq (timers). */
 static int n_barrier_cbs;	/* Number of callbacks to test RCU barriers. */
+static int nfakewriters = 4;	/* # fake writer threads */
+static int nreaders = -1;	/* # reader threads, defaults to 2*ncpus */
 static int object_debug;	/* Test object-debug double call_rcu()?. */
-static int onoff_interval;	/* Wait time between CPU hotplugs, 0=disable. */
 static int onoff_holdoff;	/* Seconds after boot before CPU hotplugs. */
+static int onoff_interval;	/* Wait time between CPU hotplugs, 0=disable. */
+static int shuffle_interval = 3; /* Interval between shuffles (in sec)*/
 static int shutdown_secs;	/* Shutdown time (s).  <=0 for no shutdown. */
 static int stall_cpu;		/* CPU-stall duration (s).  0 for no stall. */
 static int stall_cpu_holdoff = 10; /* Time to wait until stall (s).  */
+static int stat_interval = 60;	/* Interval between stats, in seconds. */
+				/*  Zero means "only at end of test". */
+static int stutter = 5;		/* Start/stop testing interval (in sec) */
 static int test_boost = 1;	/* Test RCU prio boost: 0=no, 1=maybe, 2=yes. */
-static int test_boost_interval = 7; /* Interval between boost tests, seconds. */
 static int test_boost_duration = 4; /* Duration of each boost test, seconds. */
+static int test_boost_interval = 7; /* Interval between boost tests, seconds. */
+static bool test_no_idle_hz = true;
+				/* Test RCU support for tickless idle CPUs. */
 static char *torture_type = "rcu"; /* What RCU implementation to torture. */
+static bool verbose;		/* Print more debug info. */
 
-module_param(nreaders, int, 0444);
-MODULE_PARM_DESC(nreaders, "Number of RCU reader threads");
-module_param(nfakewriters, int, 0444);
-MODULE_PARM_DESC(nfakewriters, "Number of RCU fake writer threads");
-module_param(stat_interval, int, 0644);
-MODULE_PARM_DESC(stat_interval, "Number of seconds between stats printk()s");
-module_param(verbose, bool, 0444);
-MODULE_PARM_DESC(verbose, "Enable verbose debugging printk()s");
-module_param(test_no_idle_hz, bool, 0444);
-MODULE_PARM_DESC(test_no_idle_hz, "Test support for tickless idle CPUs");
-module_param(shuffle_interval, int, 0444);
-MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles");
-module_param(stutter, int, 0444);
-MODULE_PARM_DESC(stutter, "Number of seconds to run/halt test");
-module_param(irqreader, int, 0444);
-MODULE_PARM_DESC(irqreader, "Allow RCU readers from irq handlers");
 module_param(fqs_duration, int, 0444);
 MODULE_PARM_DESC(fqs_duration, "Duration of fqs bursts (us)");
 module_param(fqs_holdoff, int, 0444);
 MODULE_PARM_DESC(fqs_holdoff, "Holdoff time within fqs bursts (us)");
 module_param(fqs_stutter, int, 0444);
 MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)");
-module_param(gp_normal, bool, 0444);
-MODULE_PARM_DESC(gp_normal, "Use normal (non-expedited) GP wait primitives");
 module_param(gp_exp, bool, 0444);
 MODULE_PARM_DESC(gp_exp, "Use expedited GP wait primitives");
+module_param(gp_normal, bool, 0444);
+MODULE_PARM_DESC(gp_normal, "Use normal (non-expedited) GP wait primitives");
+module_param(irqreader, int, 0444);
+MODULE_PARM_DESC(irqreader, "Allow RCU readers from irq handlers");
 module_param(n_barrier_cbs, int, 0444);
 MODULE_PARM_DESC(n_barrier_cbs, "# of callbacks/kthreads for barrier testing");
+module_param(nfakewriters, int, 0444);
+MODULE_PARM_DESC(nfakewriters, "Number of RCU fake writer threads");
+module_param(nreaders, int, 0444);
+MODULE_PARM_DESC(nreaders, "Number of RCU reader threads");
 module_param(object_debug, int, 0444);
 MODULE_PARM_DESC(object_debug, "Enable debug-object double call_rcu() testing");
-module_param(onoff_interval, int, 0444);
-MODULE_PARM_DESC(onoff_interval, "Time between CPU hotplugs (s), 0=disable");
 module_param(onoff_holdoff, int, 0444);
 MODULE_PARM_DESC(onoff_holdoff, "Time after boot before CPU hotplugs (s)");
+module_param(onoff_interval, int, 0444);
+MODULE_PARM_DESC(onoff_interval, "Time between CPU hotplugs (s), 0=disable");
+module_param(shuffle_interval, int, 0444);
+MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles");
 module_param(shutdown_secs, int, 0444);
 MODULE_PARM_DESC(shutdown_secs, "Shutdown time (s), zero to disable.");
 module_param(stall_cpu, int, 0444);
 MODULE_PARM_DESC(stall_cpu, "Stall duration (s), zero to disable.");
 module_param(stall_cpu_holdoff, int, 0444);
 MODULE_PARM_DESC(stall_cpu_holdoff, "Time to wait before starting stall (s).");
+module_param(stat_interval, int, 0644);
+MODULE_PARM_DESC(stat_interval, "Number of seconds between stats printk()s");
+module_param(stutter, int, 0444);
+MODULE_PARM_DESC(stutter, "Number of seconds to run/halt test");
 module_param(test_boost, int, 0444);
 MODULE_PARM_DESC(test_boost, "Test RCU prio boost: 0=no, 1=maybe, 2=yes.");
-module_param(test_boost_interval, int, 0444);
-MODULE_PARM_DESC(test_boost_interval, "Interval between boost tests, seconds.");
 module_param(test_boost_duration, int, 0444);
 MODULE_PARM_DESC(test_boost_duration, "Duration of each boost test, seconds.");
+module_param(test_boost_interval, int, 0444);
+MODULE_PARM_DESC(test_boost_interval, "Interval between boost tests, seconds.");
+module_param(test_no_idle_hz, bool, 0444);
+MODULE_PARM_DESC(test_no_idle_hz, "Test support for tickless idle CPUs");
 module_param(torture_type, charp, 0444);
 MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, srcu)");
+module_param(verbose, bool, 0444);
+MODULE_PARM_DESC(verbose, "Enable verbose debugging printk()s");
 
 #define TORTURE_FLAG "-torture:"
 #define PRINTK_STRING(s) \
Signature · 1 line
1.8.1.5
maintainer Reviewed-by on v1 3/5
#4 lore raw

Re: [PATCH tip/core/rcu 3/5] rcu: Sort rcutorture module parameters

Quoted 6 lines · Paul E. McKenney

From: "Paul E. McKenney" <[email protected]>

There are getting to be too many module parameters to permit the current semi-random order, so this patch orders them.

As long as you're reordering them anyway, how about grouping each of the variables together with the corresponding module parameter macros, and then dropping the comments that duplicate the module parameter documentation?

With that change:

#5 lore raw

Re: [PATCH tip/core/rcu 3/5] rcu: Sort rcutorture module parameters

Quoted 8 lines · Josh Triplett
Quoted 6 lines · Paul E. McKenney

From: "Paul E. McKenney" <[email protected]>

There are getting to be too many module parameters to permit the current semi-random order, so this patch orders them.

Quoted 7 lines

As long as you're reordering them anyway, how about grouping each of the variables together with the corresponding module parameter macros, and then dropping the comments that duplicate the module parameter documentation?

With that change:

Good point, done!

Thanx, Paul

#6 lore raw

PATCH 4/5 rcu: Remove unused variable from rcu_torture_writer()

In reply to Paul E. McKenney

From: "Paul E. McKenney" <[email protected]>

The oldbatch variable in rcu_torture_writer() is stored to, but never loaded from. This commit therefore removes it.

---
 kernel/rcutorture.c | 2 --
 1 file changed, 2 deletions(-)
kernel/rcutorture.c +0 -2
index be50ebe..7d42d13 100644
@@ -800,7 +800,6 @@ rcu_torture_writer(void *arg)
 {
 	bool exp;
 	int i;
-	long oldbatch = rcu_batches_completed();
 	struct rcu_torture *rp;
 	struct rcu_torture *rp1;
 	struct rcu_torture *old_rp;
@@ -854,7 +853,6 @@ rcu_torture_writer(void *arg)
 			}
 		}
 		rcutorture_record_progress(++rcu_torture_current_version);
-		oldbatch = cur_ops->completed();
 		rcu_stutter_wait("rcu_torture_writer");
 	} while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
 	VERBOSE_PRINTK_STRING("rcu_torture_writer task stopping");
Signature · 1 line
1.8.1.5
#7 lore raw

PATCH 5/5 rcu: Make rcutorture emit online failures if verbose

In reply to Paul E. McKenney

From: "Paul E. McKenney" <[email protected]>

Although rcutorture counts CPU-hotplug online failures, it does not explicitly record which CPUs were having trouble coming online. This commit therefore emits a console message when online failure occurs.

---
 kernel/rcutorture.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
kernel/rcutorture.c +7 -1
index 7d42d13..15bec39 100644
@@ -1437,7 +1437,13 @@ rcu_torture_onoff(void *arg)
 					 torture_type, cpu);
 			starttime = jiffies;
 			n_online_attempts++;
-			if (cpu_up(cpu) == 0) {
+			ret = cpu_up(cpu);
+			if (ret != 0) {
+				if (verbose)
+					pr_alert("%s" TORTURE_FLAG
+						 "rcu_torture_onoff task: online %d failed: errno %d\n",
+						 torture_type, cpu, ret);
+			} else {
 				if (verbose)
 					pr_alert("%s" TORTURE_FLAG
 						 "rcu_torture_onoff task: onlined %d\n",
Signature · 1 line
1.8.1.5
maintainer Reviewed-by on v1 5/5
#8 lore raw

Re: [PATCH tip/core/rcu 5/5] rcu: Make rcutorture emit online failures if verbose

Quoted 7 lines · Paul E. McKenney

From: "Paul E. McKenney" <[email protected]>

Although rcutorture counts CPU-hotplug online failures, it does not explicitly record which CPUs were having trouble coming online. This commit therefore emits a console message when online failure occurs.

One completely optional note below; with or without that change,

Quoted 8 lines
 kernel/rcutorture.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
kernel/rcutorture.c +0 -0
index 7d42d13..15bec39 100644

kernel/rcutorture.c rcu_torture_onoff(void *arg) · line 1441

Quoted 6 lines
kernel/rcutorture.c +2 -1
@@ -1437,7 +1437,13 @@ rcu_torture_onoff(void *arg)
 					 torture_type, cpu);
 			starttime = jiffies;
 			n_online_attempts++;
-			if (cpu_up(cpu) == 0) {
+			ret = cpu_up(cpu);
+			if (ret != 0) {

Or just "if (ret) {"

- Josh Triplett

#9 lore raw

Re: [PATCH tip/core/rcu 5/5] rcu: Make rcutorture emit online failures if verbose

Quoted 15 lines · Josh Triplett
Quoted 7 lines · Paul E. McKenney

From: "Paul E. McKenney" <[email protected]>

Although rcutorture counts CPU-hotplug online failures, it does not explicitly record which CPUs were having trouble coming online. This commit therefore emits a console message when online failure occurs.

One completely optional note below; with or without that change,

Quoted 3 lines
 kernel/rcutorture.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
Quoted 13 lines

kernel/rcutorture.c rcu_torture_onoff(void *arg) · line 1441

Quoted 11 lines
kernel/rcutorture.c +2 -1
index 7d42d13..15bec39 100644
@@ -1437,7 +1437,13 @@ rcu_torture_onoff(void *arg)
 					 torture_type, cpu);
 			starttime = jiffies;
 			n_online_attempts++;
-			if (cpu_up(cpu) == 0) {
+			ret = cpu_up(cpu);
+			if (ret != 0) {

Or just "if (ret) {"

Makes sense, fixed!

Thanx, Paul

maintainer Reviewed-by on v1 1/5
#10 lore raw

Re: [PATCH tip/core/rcu 1/5] rcu: Add duplicate-callback tests to rcutorture

In reply to Paul E. McKenney
Quoted 6 lines · Paul E. McKenney

From: "Paul E. McKenney" <[email protected]>

This commit adds a object_debug option to rcutorture to allow the debug-object-based checks for duplicate call_rcu() invocations to be deterministically tested.

Quoted 8 lines
Cc Mathieu Desnoyers <[email protected]>
Cc Sedat Dilek <[email protected]>
Cc Davidlohr Bueso <[email protected]>
Cc Rik van Riel <[email protected]>
Cc Thomas Gleixner <[email protected]>
Cc Linus Torvalds <[email protected]>

Two comments below; with those fixed,

kernel/rcutorture.c module_param(fqs_stutter, int, 0444); · line 105

Quoted 7 lines

---

kernel/rcutorture.c +2 -0
@@ -100,6 +101,8 @@ module_param(fqs_stutter, int, 0444);
 MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)");
 module_param(n_barrier_cbs, int, 0444);
 MODULE_PARM_DESC(n_barrier_cbs, "# of callbacks/kthreads for barrier testing");
+module_param(object_debug, int, 0444);
+MODULE_PARM_DESC(object_debug, "Enable debug-object double call_rcu() testing");

modules-next has a change to ignore and warn about
unknown module parameters. Thus, I'd suggest wrapping the ifdef around this module parameter, so it doesn't exist at all without CONFIG_DEBUG_OBJECTS_RCU_HEAD.

Alternatively, consider providing the test unconditionally, and just printing a big warning message saying that it's going to cause corruption in the !CONFIG_DEBUG_OBJECTS_RCU_HEAD case.

Quoted 14 lines
kernel/rcutorture.c +10 -0
@@ -2163,6 +2178,28 @@ rcu_torture_init(void)
 		firsterr = retval;
 		goto unwind;
 	}
+	if (object_debug) {
+#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
+		struct rcu_head rh1;
+		struct rcu_head rh2;
+
+		init_rcu_head_on_stack(&rh1);
+		init_rcu_head_on_stack(&rh2);
+		pr_alert("rcutorture: WARN: Duplicate call_rcu() test starting.\n");
+		local_irq_disable(); /* Make it hard to finish grace period. */
+		call_rcu(&rh1, rcu_torture_leak_cb); /* start grace period. */

kernel/rcutorture.c rcu_torture_init(void) · line 2200

Quoted 10 lines
kernel/rcutorture.c +10 -0
+		call_rcu(&rh2, rcu_torture_err_cb);
+		call_rcu(&rh2, rcu_torture_err_cb); /* duplicate callback. */
+		local_irq_enable();
+		rcu_barrier();
+		pr_alert("rcutorture: WARN: Duplicate call_rcu() test complete.\n");
+		destroy_rcu_head_on_stack(&rh1);
+		destroy_rcu_head_on_stack(&rh2);
+#else /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
+		pr_alert("rcutorture: !%s, not testing duplicate call_rcu()\n",
+			 "CONFIG_DEBUG_OBJECTS_RCU_HEAD");

Why put this parameter in a separate string? That makes it harder to grep for the full error message. (That's assuming you keep the error message, given the comment above.)

- Josh Triplett

#11 lore raw

Re: [PATCH tip/core/rcu 1/5] rcu: Add duplicate-callback tests to rcutorture

Quoted 32 lines · Josh Triplett
Quoted 6 lines · Paul E. McKenney

From: "Paul E. McKenney" <[email protected]>

This commit adds a object_debug option to rcutorture to allow the debug-object-based checks for duplicate call_rcu() invocations to be deterministically tested.

Quoted 8 lines
Cc Mathieu Desnoyers <[email protected]>
Cc Sedat Dilek <[email protected]>
Cc Davidlohr Bueso <[email protected]>
Cc Rik van Riel <[email protected]>
Cc Thomas Gleixner <[email protected]>
Cc Linus Torvalds <[email protected]>

Two comments below; with those fixed,

kernel/rcutorture.c module_param(fqs_stutter, int, 0444); · line 105

Quoted 7 lines

---

kernel/rcutorture.c +2 -0
@@ -100,6 +101,8 @@ module_param(fqs_stutter, int, 0444);
 MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)");
 module_param(n_barrier_cbs, int, 0444);
 MODULE_PARM_DESC(n_barrier_cbs, "# of callbacks/kthreads for barrier testing");
+module_param(object_debug, int, 0444);
+MODULE_PARM_DESC(object_debug, "Enable debug-object double call_rcu() testing");

modules-next has a change to ignore and warn about
unknown module parameters. Thus, I'd suggest wrapping the ifdef around this module parameter, so it doesn't exist at all without CONFIG_DEBUG_OBJECTS_RCU_HEAD.

Quoted 3 lines

Alternatively, consider providing the test unconditionally, and just printing a big warning message saying that it's going to cause corruption in the !CONFIG_DEBUG_OBJECTS_RCU_HEAD case.

I currently do something like the above. The module parameter is defined unconditionally, but the actual tests are under #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD. If you specify object_debug for a !CONFIG_DEBUG_OBJECTS_RCU_HEAD kernel, the pr_alert() below happens, and the test is omitted, thus avoiding the list corruption.

Seem reasonable?

Quoted 20 lines
Quoted 20 lines
kernel/rcutorture.c +16 -0
@@ -2163,6 +2178,28 @@ rcu_torture_init(void)
 		firsterr = retval;
 		goto unwind;
 	}
+	if (object_debug) {
+#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
+		struct rcu_head rh1;
+		struct rcu_head rh2;
+
+		init_rcu_head_on_stack(&rh1);
+		init_rcu_head_on_stack(&rh2);
+		pr_alert("rcutorture: WARN: Duplicate call_rcu() test starting.\n");
+		local_irq_disable(); /* Make it hard to finish grace period. */
+		call_rcu(&rh1, rcu_torture_leak_cb); /* start grace period. */
+		call_rcu(&rh2, rcu_torture_err_cb);
+		call_rcu(&rh2, rcu_torture_err_cb); /* duplicate callback. */
+		local_irq_enable();
+		rcu_barrier();
+		pr_alert("rcutorture: WARN: Duplicate call_rcu() test complete.\n");
+		destroy_rcu_head_on_stack(&rh1);
Quoted 8 lines

kernel/rcutorture.c rcu_torture_init(void) · line 2200

Quoted 4 lines
kernel/rcutorture.c +4 -0
+		destroy_rcu_head_on_stack(&rh2);
+#else /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
+		pr_alert("rcutorture: !%s, not testing duplicate call_rcu()\n",
+			 "CONFIG_DEBUG_OBJECTS_RCU_HEAD");

Why put this parameter in a separate string? That makes it harder to grep for the full error message. (That's assuming you keep the error message, given the comment above.)

Force of habit, fixed. ;-)

Thanx, Paul

maintainer
#12 lore raw

Re: [PATCH tip/core/rcu 1/5] rcu: Add duplicate-callback tests to rcutorture

Quoted 37 lines · Paul E. McKenney
Quoted 32 lines · Josh Triplett
Quoted 6 lines · Paul E. McKenney

From: "Paul E. McKenney" <[email protected]>

This commit adds a object_debug option to rcutorture to allow the debug-object-based checks for duplicate call_rcu() invocations to be deterministically tested.

Quoted 8 lines
Cc Mathieu Desnoyers <[email protected]>
Cc Sedat Dilek <[email protected]>
Cc Davidlohr Bueso <[email protected]>
Cc Rik van Riel <[email protected]>
Cc Thomas Gleixner <[email protected]>
Cc Linus Torvalds <[email protected]>

Two comments below; with those fixed,

kernel/rcutorture.c module_param(fqs_stutter, int, 0444); · line 105

Quoted 7 lines

---

kernel/rcutorture.c +2 -0
@@ -100,6 +101,8 @@ module_param(fqs_stutter, int, 0444);
 MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)");
 module_param(n_barrier_cbs, int, 0444);
 MODULE_PARM_DESC(n_barrier_cbs, "# of callbacks/kthreads for barrier testing");
+module_param(object_debug, int, 0444);
+MODULE_PARM_DESC(object_debug, "Enable debug-object double call_rcu() testing");

modules-next has a change to ignore and warn about
unknown module parameters. Thus, I'd suggest wrapping the ifdef around this module parameter, so it doesn't exist at all without CONFIG_DEBUG_OBJECTS_RCU_HEAD.

Quoted 3 lines

Alternatively, consider providing the test unconditionally, and just printing a big warning message saying that it's going to cause corruption in the !CONFIG_DEBUG_OBJECTS_RCU_HEAD case.

Quoted 7 lines

I currently do something like the above. The module parameter is defined unconditionally, but the actual tests are under #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD. If you specify object_debug for a !CONFIG_DEBUG_OBJECTS_RCU_HEAD kernel, the pr_alert() below happens, and the test is omitted, thus avoiding the list corruption.

Seem reasonable?

That's exactly the bit I was commenting on. I'm saying that you should either make the test unconditional (perhaps with a warning saying it's about to cause list corruption), or you should compile out the module parameter as well and then you don't need the pr_alert (since current kernels will emit a warning when you pass a non-existent module parameter).

Personally, I'd go with the latter.

- Josh Triplett

#13 lore raw

Re: [PATCH tip/core/rcu 1/5] rcu: Add duplicate-callback tests to rcutorture

Quoted 46 lines · Josh Triplett
Quoted 37 lines · Paul E. McKenney
Quoted 32 lines · Josh Triplett
Quoted 6 lines · Paul E. McKenney

From: "Paul E. McKenney" <[email protected]>

This commit adds a object_debug option to rcutorture to allow the debug-object-based checks for duplicate call_rcu() invocations to be deterministically tested.

Quoted 8 lines
Cc Mathieu Desnoyers <[email protected]>
Cc Sedat Dilek <[email protected]>
Cc Davidlohr Bueso <[email protected]>
Cc Rik van Riel <[email protected]>
Cc Thomas Gleixner <[email protected]>
Cc Linus Torvalds <[email protected]>

Two comments below; with those fixed,

kernel/rcutorture.c module_param(fqs_stutter, int, 0444); · line 105

Quoted 7 lines

---

kernel/rcutorture.c +2 -0
@@ -100,6 +101,8 @@ module_param(fqs_stutter, int, 0444);
 MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)");
 module_param(n_barrier_cbs, int, 0444);
 MODULE_PARM_DESC(n_barrier_cbs, "# of callbacks/kthreads for barrier testing");
+module_param(object_debug, int, 0444);
+MODULE_PARM_DESC(object_debug, "Enable debug-object double call_rcu() testing");

modules-next has a change to ignore and warn about
unknown module parameters. Thus, I'd suggest wrapping the ifdef around this module parameter, so it doesn't exist at all without CONFIG_DEBUG_OBJECTS_RCU_HEAD.

Quoted 3 lines

Alternatively, consider providing the test unconditionally, and just printing a big warning message saying that it's going to cause corruption in the !CONFIG_DEBUG_OBJECTS_RCU_HEAD case.

Quoted 7 lines

I currently do something like the above. The module parameter is defined unconditionally, but the actual tests are under #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD. If you specify object_debug for a !CONFIG_DEBUG_OBJECTS_RCU_HEAD kernel, the pr_alert() below happens, and the test is omitted, thus avoiding the list corruption.

Seem reasonable?

Quoted 8 lines

That's exactly the bit I was commenting on. I'm saying that you should either make the test unconditional (perhaps with a warning saying it's about to cause list corruption), or you should compile out the module parameter as well and then you don't need the pr_alert (since current kernels will emit a warning when you pass a non-existent module parameter).

Personally, I'd go with the latter.

Ah, the problem is the ugly ifdef in the middle of a function. Yeah, that is a problem in need of fixing. No idea what I was thinking...

How about if I pull that block of code out into its own function, and #ifdef the function body. For example, something like that shown below.

Thanx, Paul

static void rcu_test_debug_objects(void)
{

#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
	struct rcu_head rh1;
	struct rcu_head rh2;

	init_rcu_head_on_stack(&rh1);
	init_rcu_head_on_stack(&rh2);
	pr_alert("rcutorture: WARN: Duplicate call_rcu() test starting.\n");
	local_irq_disable(); /* Make it hard to finish grace period. */
	call_rcu(&rh1, rcu_torture_leak_cb); /* start grace period. */
	call_rcu(&rh2, rcu_torture_err_cb);
	call_rcu(&rh2, rcu_torture_err_cb); /* duplicate callback. */
	local_irq_enable();
	rcu_barrier();
	pr_alert("rcutorture: WARN: Duplicate call_rcu() test complete.\n");
	destroy_rcu_head_on_stack(&rh1);
	destroy_rcu_head_on_stack(&rh2);
#else /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
	pr_alert("rcutorture: !CONFIG_DEBUG_OBJECTS_RCU_HEAD, not testing duplicate call_rcu()\n");

#endif /* #else #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */ }

maintainer
#14 lore raw

Re: [PATCH tip/core/rcu 1/5] rcu: Add duplicate-callback tests to rcutorture

Quoted 61 lines · Paul E. McKenney
Quoted 46 lines · Josh Triplett
Quoted 37 lines · Paul E. McKenney
Quoted 32 lines · Josh Triplett
Quoted 6 lines · Paul E. McKenney

From: "Paul E. McKenney" <[email protected]>

This commit adds a object_debug option to rcutorture to allow the debug-object-based checks for duplicate call_rcu() invocations to be deterministically tested.

Quoted 8 lines
Cc Mathieu Desnoyers <[email protected]>
Cc Sedat Dilek <[email protected]>
Cc Davidlohr Bueso <[email protected]>
Cc Rik van Riel <[email protected]>
Cc Thomas Gleixner <[email protected]>
Cc Linus Torvalds <[email protected]>

Two comments below; with those fixed,

kernel/rcutorture.c module_param(fqs_stutter, int, 0444); · line 105

Quoted 7 lines

---

kernel/rcutorture.c +2 -0
@@ -100,6 +101,8 @@ module_param(fqs_stutter, int, 0444);
 MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)");
 module_param(n_barrier_cbs, int, 0444);
 MODULE_PARM_DESC(n_barrier_cbs, "# of callbacks/kthreads for barrier testing");
+module_param(object_debug, int, 0444);
+MODULE_PARM_DESC(object_debug, "Enable debug-object double call_rcu() testing");

modules-next has a change to ignore and warn about
unknown module parameters. Thus, I'd suggest wrapping the ifdef around this module parameter, so it doesn't exist at all without CONFIG_DEBUG_OBJECTS_RCU_HEAD.

Quoted 3 lines

Alternatively, consider providing the test unconditionally, and just printing a big warning message saying that it's going to cause corruption in the !CONFIG_DEBUG_OBJECTS_RCU_HEAD case.

Quoted 7 lines

I currently do something like the above. The module parameter is defined unconditionally, but the actual tests are under #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD. If you specify object_debug for a !CONFIG_DEBUG_OBJECTS_RCU_HEAD kernel, the pr_alert() below happens, and the test is omitted, thus avoiding the list corruption.

Seem reasonable?

Quoted 8 lines

That's exactly the bit I was commenting on. I'm saying that you should either make the test unconditional (perhaps with a warning saying it's about to cause list corruption), or you should compile out the module parameter as well and then you don't need the pr_alert (since current kernels will emit a warning when you pass a non-existent module parameter).

Personally, I'd go with the latter.

Ah, the problem is the ugly ifdef in the middle of a function. Yeah, that is a problem in need of fixing. No idea what I was thinking...

How about if I pull that block of code out into its own function, and #ifdef the function body. For example, something like that shown below.

[...]

Quoted 20 lines

static void rcu_test_debug_objects(void)
{

#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
	struct rcu_head rh1;
	struct rcu_head rh2;

	init_rcu_head_on_stack(&rh1);
	init_rcu_head_on_stack(&rh2);
	pr_alert("rcutorture: WARN: Duplicate call_rcu() test starting.\n");
	local_irq_disable(); /* Make it hard to finish grace period. */
	call_rcu(&rh1, rcu_torture_leak_cb); /* start grace period. */
	call_rcu(&rh2, rcu_torture_err_cb);
	call_rcu(&rh2, rcu_torture_err_cb); /* duplicate callback. */
	local_irq_enable();
	rcu_barrier();
	pr_alert("rcutorture: WARN: Duplicate call_rcu() test complete.\n");
	destroy_rcu_head_on_stack(&rh1);
	destroy_rcu_head_on_stack(&rh2);
#else /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
	pr_alert("rcutorture: !CONFIG_DEBUG_OBJECTS_RCU_HEAD, not testing duplicate call_rcu()\n");
Quoted 3 lines

#endif /* #else #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */ }

That's a major improvement, but I'd still suggest a couple more changes:
move the if for the config option into that function inside the ifdef, wrap the config parameter itself in an ifdef so it doesn't exist without CONFIG_DEBUG_OBJECTS_RCU_HEAD, and drop the #else branch since the kernel will already emit a warning if you use the module parameter with !CONFIG_DEBUG_OBJECTS_RCU_HEAD.

- Josh Triplett

#15 lore raw

Re: [PATCH tip/core/rcu 1/5] rcu: Add duplicate-callback tests to rcutorture

Quoted 86 lines · Josh Triplett
Quoted 61 lines · Paul E. McKenney
Quoted 46 lines · Josh Triplett
Quoted 37 lines · Paul E. McKenney
Quoted 32 lines · Josh Triplett
Quoted 6 lines · Paul E. McKenney

From: "Paul E. McKenney" <[email protected]>

This commit adds a object_debug option to rcutorture to allow the debug-object-based checks for duplicate call_rcu() invocations to be deterministically tested.

Quoted 8 lines
Cc Mathieu Desnoyers <[email protected]>
Cc Sedat Dilek <[email protected]>
Cc Davidlohr Bueso <[email protected]>
Cc Rik van Riel <[email protected]>
Cc Thomas Gleixner <[email protected]>
Cc Linus Torvalds <[email protected]>

Two comments below; with those fixed,

kernel/rcutorture.c module_param(fqs_stutter, int, 0444); · line 105

Quoted 7 lines

---

kernel/rcutorture.c +2 -0
@@ -100,6 +101,8 @@ module_param(fqs_stutter, int, 0444);
 MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)");
 module_param(n_barrier_cbs, int, 0444);
 MODULE_PARM_DESC(n_barrier_cbs, "# of callbacks/kthreads for barrier testing");
+module_param(object_debug, int, 0444);
+MODULE_PARM_DESC(object_debug, "Enable debug-object double call_rcu() testing");

modules-next has a change to ignore and warn about
unknown module parameters. Thus, I'd suggest wrapping the ifdef around this module parameter, so it doesn't exist at all without CONFIG_DEBUG_OBJECTS_RCU_HEAD.

Quoted 3 lines

Alternatively, consider providing the test unconditionally, and just printing a big warning message saying that it's going to cause corruption in the !CONFIG_DEBUG_OBJECTS_RCU_HEAD case.

Quoted 7 lines

I currently do something like the above. The module parameter is defined unconditionally, but the actual tests are under #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD. If you specify object_debug for a !CONFIG_DEBUG_OBJECTS_RCU_HEAD kernel, the pr_alert() below happens, and the test is omitted, thus avoiding the list corruption.

Seem reasonable?

Quoted 8 lines

That's exactly the bit I was commenting on. I'm saying that you should either make the test unconditional (perhaps with a warning saying it's about to cause list corruption), or you should compile out the module parameter as well and then you don't need the pr_alert (since current kernels will emit a warning when you pass a non-existent module parameter).

Personally, I'd go with the latter.

Ah, the problem is the ugly ifdef in the middle of a function. Yeah, that is a problem in need of fixing. No idea what I was thinking...

How about if I pull that block of code out into its own function, and #ifdef the function body. For example, something like that shown below.

[...]

Quoted 20 lines

static void rcu_test_debug_objects(void)
{

#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
	struct rcu_head rh1;
	struct rcu_head rh2;

	init_rcu_head_on_stack(&rh1);
	init_rcu_head_on_stack(&rh2);
	pr_alert("rcutorture: WARN: Duplicate call_rcu() test starting.\n");
	local_irq_disable(); /* Make it hard to finish grace period. */
	call_rcu(&rh1, rcu_torture_leak_cb); /* start grace period. */
	call_rcu(&rh2, rcu_torture_err_cb);
	call_rcu(&rh2, rcu_torture_err_cb); /* duplicate callback. */
	local_irq_enable();
	rcu_barrier();
	pr_alert("rcutorture: WARN: Duplicate call_rcu() test complete.\n");
	destroy_rcu_head_on_stack(&rh1);
	destroy_rcu_head_on_stack(&rh2);
#else /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
	pr_alert("rcutorture: !CONFIG_DEBUG_OBJECTS_RCU_HEAD, not testing duplicate call_rcu()\n");
Quoted 2 lines

#endif /* #else #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */ }

Quoted 6 lines

That's a major improvement, but I'd still suggest a couple more changes:
move the if for the config option into that function inside the ifdef, wrap the config parameter itself in an ifdef so it doesn't exist without CONFIG_DEBUG_OBJECTS_RCU_HEAD, and drop the #else branch since the kernel will already emit a warning if you use the module parameter with !CONFIG_DEBUG_OBJECTS_RCU_HEAD.

I really feel the need to distinguish between "that is never a valid parameter to rcutorture" (given by the module-parameter parser) and "that parameter is valid, but cannot be used in this case, and here are the consequences", so I will keep the pr_alert(). But definitely fix the mid-function #ifdef!

Thanx, Paul

maintainer Reviewed-by
#16 lore raw

Re: [PATCH tip/core/rcu 1/5] rcu: Add duplicate-callback tests to rcutorture

Quoted 94 lines · Paul E. McKenney
Quoted 86 lines · Josh Triplett
Quoted 61 lines · Paul E. McKenney
Quoted 46 lines · Josh Triplett
Quoted 37 lines · Paul E. McKenney
Quoted 32 lines · Josh Triplett
Quoted 6 lines · Paul E. McKenney

From: "Paul E. McKenney" <[email protected]>

This commit adds a object_debug option to rcutorture to allow the debug-object-based checks for duplicate call_rcu() invocations to be deterministically tested.

Quoted 8 lines
Cc Mathieu Desnoyers <[email protected]>
Cc Sedat Dilek <[email protected]>
Cc Davidlohr Bueso <[email protected]>
Cc Rik van Riel <[email protected]>
Cc Thomas Gleixner <[email protected]>
Cc Linus Torvalds <[email protected]>

Two comments below; with those fixed,

Review module_param(fqs_stutter, int, 0444); · line 105

Quoted 7 lines

---

(quoted diff) +2 -0
@@ -100,6 +101,8 @@ module_param(fqs_stutter, int, 0444);
 MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)");
 module_param(n_barrier_cbs, int, 0444);
 MODULE_PARM_DESC(n_barrier_cbs, "# of callbacks/kthreads for barrier testing");
+module_param(object_debug, int, 0444);
+MODULE_PARM_DESC(object_debug, "Enable debug-object double call_rcu() testing");

modules-next has a change to ignore and warn about
unknown module parameters. Thus, I'd suggest wrapping the ifdef around this module parameter, so it doesn't exist at all without CONFIG_DEBUG_OBJECTS_RCU_HEAD.

Quoted 3 lines

Alternatively, consider providing the test unconditionally, and just printing a big warning message saying that it's going to cause corruption in the !CONFIG_DEBUG_OBJECTS_RCU_HEAD case.

Quoted 7 lines

I currently do something like the above. The module parameter is defined unconditionally, but the actual tests are under #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD. If you specify object_debug for a !CONFIG_DEBUG_OBJECTS_RCU_HEAD kernel, the pr_alert() below happens, and the test is omitted, thus avoiding the list corruption.

Seem reasonable?

Quoted 8 lines

That's exactly the bit I was commenting on. I'm saying that you should either make the test unconditional (perhaps with a warning saying it's about to cause list corruption), or you should compile out the module parameter as well and then you don't need the pr_alert (since current kernels will emit a warning when you pass a non-existent module parameter).

Personally, I'd go with the latter.

Ah, the problem is the ugly ifdef in the middle of a function. Yeah, that is a problem in need of fixing. No idea what I was thinking...

How about if I pull that block of code out into its own function, and #ifdef the function body. For example, something like that shown below.

[...]

Quoted 20 lines

static void rcu_test_debug_objects(void)
{

#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
	struct rcu_head rh1;
	struct rcu_head rh2;

	init_rcu_head_on_stack(&rh1);
	init_rcu_head_on_stack(&rh2);
	pr_alert("rcutorture: WARN: Duplicate call_rcu() test starting.\n");
	local_irq_disable(); /* Make it hard to finish grace period. */
	call_rcu(&rh1, rcu_torture_leak_cb); /* start grace period. */
	call_rcu(&rh2, rcu_torture_err_cb);
	call_rcu(&rh2, rcu_torture_err_cb); /* duplicate callback. */
	local_irq_enable();
	rcu_barrier();
	pr_alert("rcutorture: WARN: Duplicate call_rcu() test complete.\n");
	destroy_rcu_head_on_stack(&rh1);
	destroy_rcu_head_on_stack(&rh2);
#else /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
	pr_alert("rcutorture: !CONFIG_DEBUG_OBJECTS_RCU_HEAD, not testing duplicate call_rcu()\n");
Quoted 2 lines

#endif /* #else #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */ }

Quoted 6 lines

That's a major improvement, but I'd still suggest a couple more changes:
move the if for the config option into that function inside the ifdef, wrap the config parameter itself in an ifdef so it doesn't exist without CONFIG_DEBUG_OBJECTS_RCU_HEAD, and drop the #else branch since the kernel will already emit a warning if you use the module parameter with !CONFIG_DEBUG_OBJECTS_RCU_HEAD.

Quoted 5 lines

I really feel the need to distinguish between "that is never a valid parameter to rcutorture" (given by the module-parameter parser) and "that parameter is valid, but cannot be used in this case, and here are the consequences", so I will keep the pr_alert(). But definitely fix the mid-function #ifdef!

OK; I can live with that.

maintainer Reviewed-by on the v1 series
#17 lore raw
In reply to Paul E. McKenney
Quoted 7 lines · Paul E. McKenney

Hello!

This series provides some rcutorture updates:

1. Add a debug_object option to rcutorture to allow testing
of RCU's debug-objects facilities.

Quoted 8 lines

2. Increase rcutorture test coverage by concurrently testing
synchronous, asynchronous, and expedited grace periods.

3. Sort the extensive list of rcutorture module parameters.

4. Remove the unused "oldbatch" variable.

5. Emit CPU-online failure message to the console.

Comments on 1 and 3; for 2, 4, and 5:

#18 lore raw

PATCH 1/5 rcu: Add duplicate-callback tests to rcutorture

In reply to Paul E. McKenney

From: "Paul E. McKenney" <[email protected]>

This commit adds a object_debug option to rcutorture to allow the debug-object-based checks for duplicate call_rcu() invocations to be deterministically tested.

Cc Mathieu Desnoyers <[email protected]>
Cc Sedat Dilek <[email protected]>
Cc Davidlohr Bueso <[email protected]>
Cc Rik van Riel <[email protected]>
Cc Thomas Gleixner <[email protected]>
Cc Linus Torvalds <[email protected]>
[ paulmck: Banish mid-function ifdef, more or less per Josh Triplett. ]
---
 kernel/rcutorture.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)
kernel/rcutorture.c +45 -0
index 3d936f0f..f5cf2bb 100644
@@ -66,6 +66,7 @@ static int fqs_duration;	/* Duration of bursts (us), 0 to disable. */
 static int fqs_holdoff;		/* Hold time within burst (us). */
 static int fqs_stutter = 3;	/* Wait time between bursts (s). */
 static int n_barrier_cbs;	/* Number of callbacks to test RCU barriers. */
+static int object_debug;	/* Test object-debug double call_rcu()?. */
 static int onoff_interval;	/* Wait time between CPU hotplugs, 0=disable. */
 static int onoff_holdoff;	/* Seconds after boot before CPU hotplugs. */
 static int shutdown_secs;	/* Shutdown time (s).  <=0 for no shutdown. */
@@ -100,6 +101,8 @@ module_param(fqs_stutter, int, 0444);
 MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)");
 module_param(n_barrier_cbs, int, 0444);
 MODULE_PARM_DESC(n_barrier_cbs, "# of callbacks/kthreads for barrier testing");
+module_param(object_debug, int, 0444);
+MODULE_PARM_DESC(object_debug, "Enable debug-object double call_rcu() testing");
 module_param(onoff_interval, int, 0444);
 MODULE_PARM_DESC(onoff_interval, "Time between CPU hotplugs (s), 0=disable");
 module_param(onoff_holdoff, int, 0444);
@@ -1934,6 +1937,46 @@ rcu_torture_cleanup(void)
 		rcu_torture_print_module_parms(cur_ops, "End of test: SUCCESS");
 }
 
+#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
+static void rcu_torture_leak_cb(struct rcu_head *rhp)
+{
+}
+
+static void rcu_torture_err_cb(struct rcu_head *rhp)
+{
+	/* This -might- happen due to race conditions, but is unlikely. */
+	pr_alert("rcutorture: duplicated callback was invoked.\n");
+}
+#endif /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
+
+/*
+ * Verify that double-free causes debug-objects to complain, but only
+ * if CONFIG_DEBUG_OBJECTS_RCU_HEAD=y.  Otherwise, say that the test
+ * cannot be carried out.
+ */
+static void rcu_test_debug_objects(void)
+{
+#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
+	struct rcu_head rh1;
+	struct rcu_head rh2;
+
+	init_rcu_head_on_stack(&rh1);
+	init_rcu_head_on_stack(&rh2);
+	pr_alert("rcutorture: WARN: Duplicate call_rcu() test starting.\n");
+	local_irq_disable(); /* Make it hard to finish grace period. */
+	call_rcu(&rh1, rcu_torture_leak_cb); /* start grace period. */
+	call_rcu(&rh2, rcu_torture_err_cb);
+	call_rcu(&rh2, rcu_torture_err_cb); /* duplicate callback. */
+	local_irq_enable();
+	rcu_barrier();
+	pr_alert("rcutorture: WARN: Duplicate call_rcu() test complete.\n");
+	destroy_rcu_head_on_stack(&rh1);
+	destroy_rcu_head_on_stack(&rh2);
+#else /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
+	pr_alert("rcutorture: !CONFIG_DEBUG_OBJECTS_RCU_HEAD, not testing duplicate call_rcu()\n");
+#endif /* #else #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
+}
+
 static int __init
 rcu_torture_init(void)
 {
@@ -2163,6 +2206,8 @@ rcu_torture_init(void)
 		firsterr = retval;
 		goto unwind;
 	}
+	if (object_debug)
+		rcu_test_debug_objects();
 	rcutorture_record_test_transition();
 	mutex_unlock(&fullstop_mutex);
 	return 0;
Signature · 1 line
1.8.1.5
#19 lore raw

PATCH 2/5 rcu: Increase rcutorture test coverage

From: "Paul E. McKenney" <[email protected]>

Currently, rcutorture has separate torture_types to test synchronous, asynchronous, and expedited grace-period primitives. This has two disadvantages: (1) Three times the number of runs to cover the combinations and (2) Little testing of concurrent combinations of the three options. This commit therefore adds a pair of module parameters that control normal and expedited state, with the default being both types, randomly selected, by the fakewriter processes, thus reducing source-code size and increasing test coverage. In addtion, the writer task switches between asynchronous-normal and expedited grace-period primitives driven by the same pair of module parameters.

---
 Documentation/RCU/torture.txt |  10 ++
 kernel/rcutorture.c           | 226 ++++++++++++------------------------------
 2 files changed, 73 insertions(+), 163 deletions(-)
Documentation/RCU/torture.txt +10 -0
index d8a5023..dac02a6 100644
@@ -42,6 +42,16 @@ fqs_holdoff	Holdoff time (in microseconds) between consecutive calls
 fqs_stutter	Wait time (in seconds) between consecutive bursts
 		of calls to force_quiescent_state().
 
+gp_normal	Make the fake writers use normal synchronous grace-period
+		primitives.
+
+gp_exp		Make the fake writers use expedited synchronous grace-period
+		primitives.  If both gp_normal and gp_exp are set, or
+		if neither gp_normal nor gp_exp are set, then randomly
+		choose the primitive so that about 50% are normal and
+		50% expedited.  By default, neither are set, which
+		gives best overall test coverage.
+
 irqreader	Says to invoke RCU readers from irq level.  This is currently
 		done via timers.  Defaults to "1" for variants of RCU that
 		permit this.  (Or, more accurately, variants of RCU that do
kernel/rcutorture.c +63 -163

342 lines not on this page · raw message

Signature · 1 line
1.8.1.5
#20 lore raw

PATCH 3/5 rcu: Sort rcutorture module parameters

In reply to Paul E. McKenney

From: "Paul E. McKenney" <[email protected]>

There are getting to be too many module parameters to permit the current semi-random order, so this patch orders them.

---
 kernel/rcutorture.c | 101 +++++++++++++++++++++++++---------------------------
 1 file changed, 49 insertions(+), 52 deletions(-)
kernel/rcutorture.c +49 -52
index 10820b7..949a8f2 100644
@@ -52,81 +52,78 @@
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Paul E. McKenney <[email protected]> and Josh Triplett <[email protected]>");
 
-static int nreaders = -1;	/* # reader threads, defaults to 2*ncpus */
-static int nfakewriters = 4;	/* # fake writer threads */
-static int stat_interval = 60;	/* Interval between stats, in seconds. */
-				/*  Zero means "only at end of test". */
-static bool verbose;		/* Print more debug info. */
-static bool test_no_idle_hz = true;
-				/* Test RCU support for tickless idle CPUs. */
-static int shuffle_interval = 3; /* Interval between shuffles (in sec)*/
-static int stutter = 5;		/* Start/stop testing interval (in sec) */
-static int irqreader = 1;	/* RCU readers from irq (timers). */
-static int fqs_duration;	/* Duration of bursts (us), 0 to disable. */
-static int fqs_holdoff;		/* Hold time within burst (us). */
-static int fqs_stutter = 3;	/* Wait time between bursts (s). */
-static bool gp_exp;		/* Use expedited GP wait primitives. */
-static bool gp_normal;		/* Use normal GP wait primitives. */
-static int n_barrier_cbs;	/* Number of callbacks to test RCU barriers. */
-static int object_debug;	/* Test object-debug double call_rcu()?. */
-static int onoff_interval;	/* Wait time between CPU hotplugs, 0=disable. */
-static int onoff_holdoff;	/* Seconds after boot before CPU hotplugs. */
-static int shutdown_secs;	/* Shutdown time (s).  <=0 for no shutdown. */
-static int stall_cpu;		/* CPU-stall duration (s).  0 for no stall. */
-static int stall_cpu_holdoff = 10; /* Time to wait until stall (s).  */
-static int test_boost = 1;	/* Test RCU prio boost: 0=no, 1=maybe, 2=yes. */
-static int test_boost_interval = 7; /* Interval between boost tests, seconds. */
-static int test_boost_duration = 4; /* Duration of each boost test, seconds. */
-static char *torture_type = "rcu"; /* What RCU implementation to torture. */
-
-module_param(nreaders, int, 0444);
-MODULE_PARM_DESC(nreaders, "Number of RCU reader threads");
-module_param(nfakewriters, int, 0444);
-MODULE_PARM_DESC(nfakewriters, "Number of RCU fake writer threads");
-module_param(stat_interval, int, 0644);
-MODULE_PARM_DESC(stat_interval, "Number of seconds between stats printk()s");
-module_param(verbose, bool, 0444);
-MODULE_PARM_DESC(verbose, "Enable verbose debugging printk()s");
-module_param(test_no_idle_hz, bool, 0444);
-MODULE_PARM_DESC(test_no_idle_hz, "Test support for tickless idle CPUs");
-module_param(shuffle_interval, int, 0444);
-MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles");
-module_param(stutter, int, 0444);
-MODULE_PARM_DESC(stutter, "Number of seconds to run/halt test");
-module_param(irqreader, int, 0444);
-MODULE_PARM_DESC(irqreader, "Allow RCU readers from irq handlers");
+static int fqs_duration;
 module_param(fqs_duration, int, 0444);
-MODULE_PARM_DESC(fqs_duration, "Duration of fqs bursts (us)");
+MODULE_PARM_DESC(fqs_duration, "Duration of fqs bursts (us), 0 to disable");
+static int fqs_holdoff;
 module_param(fqs_holdoff, int, 0444);
 MODULE_PARM_DESC(fqs_holdoff, "Holdoff time within fqs bursts (us)");
+static int fqs_stutter = 3;
 module_param(fqs_stutter, int, 0444);
 MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)");
-module_param(gp_normal, bool, 0444);
-MODULE_PARM_DESC(gp_normal, "Use normal (non-expedited) GP wait primitives");
+static bool gp_exp;
 module_param(gp_exp, bool, 0444);
 MODULE_PARM_DESC(gp_exp, "Use expedited GP wait primitives");
+static bool gp_normal;
+module_param(gp_normal, bool, 0444);
+MODULE_PARM_DESC(gp_normal, "Use normal (non-expedited) GP wait primitives");
+static int irqreader = 1;
+module_param(irqreader, int, 0444);
+MODULE_PARM_DESC(irqreader, "Allow RCU readers from irq handlers");
+static int n_barrier_cbs;
 module_param(n_barrier_cbs, int, 0444);
 MODULE_PARM_DESC(n_barrier_cbs, "# of callbacks/kthreads for barrier testing");
+static int nfakewriters = 4;
+module_param(nfakewriters, int, 0444);
+MODULE_PARM_DESC(nfakewriters, "Number of RCU fake writer threads");
+static int nreaders = -1;
+module_param(nreaders, int, 0444);
+MODULE_PARM_DESC(nreaders, "Number of RCU reader threads");
+static int object_debug;
 module_param(object_debug, int, 0444);
 MODULE_PARM_DESC(object_debug, "Enable debug-object double call_rcu() testing");
-module_param(onoff_interval, int, 0444);
-MODULE_PARM_DESC(onoff_interval, "Time between CPU hotplugs (s), 0=disable");
+static int onoff_holdoff;
 module_param(onoff_holdoff, int, 0444);
 MODULE_PARM_DESC(onoff_holdoff, "Time after boot before CPU hotplugs (s)");
+static int onoff_interval;
+module_param(onoff_interval, int, 0444);
+MODULE_PARM_DESC(onoff_interval, "Time between CPU hotplugs (s), 0=disable");
+static int shuffle_interval = 3;
+module_param(shuffle_interval, int, 0444);
+MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles");
+static int shutdown_secs;
 module_param(shutdown_secs, int, 0444);
-MODULE_PARM_DESC(shutdown_secs, "Shutdown time (s), zero to disable.");
+MODULE_PARM_DESC(shutdown_secs, "Shutdown time (s), <= zero to disable.");
+static int stall_cpu;
 module_param(stall_cpu, int, 0444);
 MODULE_PARM_DESC(stall_cpu, "Stall duration (s), zero to disable.");
+static int stall_cpu_holdoff = 10;
 module_param(stall_cpu_holdoff, int, 0444);
 MODULE_PARM_DESC(stall_cpu_holdoff, "Time to wait before starting stall (s).");
+static int stat_interval = 60;
+module_param(stat_interval, int, 0644);
+MODULE_PARM_DESC(stat_interval, "Number of seconds between stats printk()s");
+static int stutter = 5;
+module_param(stutter, int, 0444);
+MODULE_PARM_DESC(stutter, "Number of seconds to run/halt test");
+static int test_boost = 1;
 module_param(test_boost, int, 0444);
 MODULE_PARM_DESC(test_boost, "Test RCU prio boost: 0=no, 1=maybe, 2=yes.");
-module_param(test_boost_interval, int, 0444);
-MODULE_PARM_DESC(test_boost_interval, "Interval between boost tests, seconds.");
+static int test_boost_duration = 4;
 module_param(test_boost_duration, int, 0444);
 MODULE_PARM_DESC(test_boost_duration, "Duration of each boost test, seconds.");
+static int test_boost_interval = 7;
+module_param(test_boost_interval, int, 0444);
+MODULE_PARM_DESC(test_boost_interval, "Interval between boost tests, seconds.");
+static bool test_no_idle_hz = true;
+module_param(test_no_idle_hz, bool, 0444);
+MODULE_PARM_DESC(test_no_idle_hz, "Test support for tickless idle CPUs");
+static char *torture_type = "rcu";
 module_param(torture_type, charp, 0444);
-MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, srcu)");
+MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, ...)");
+static bool verbose;
+module_param(verbose, bool, 0444);
+MODULE_PARM_DESC(verbose, "Enable verbose debugging printk()s");
 
 #define TORTURE_FLAG "-torture:"
 #define PRINTK_STRING(s) \
Signature · 1 line
1.8.1.5
#21 lore raw

PATCH 4/5 rcu: Remove unused variable from rcu_torture_writer()

In reply to Paul E. McKenney

From: "Paul E. McKenney" <[email protected]>

The oldbatch variable in rcu_torture_writer() is stored to, but never loaded from. This commit therefore removes it.

---
 kernel/rcutorture.c | 2 --
 1 file changed, 2 deletions(-)
kernel/rcutorture.c +0 -2
index 949a8f2..869dac2 100644
@@ -797,7 +797,6 @@ rcu_torture_writer(void *arg)
 {
 	bool exp;
 	int i;
-	long oldbatch = rcu_batches_completed();
 	struct rcu_torture *rp;
 	struct rcu_torture *rp1;
 	struct rcu_torture *old_rp;
@@ -851,7 +850,6 @@ rcu_torture_writer(void *arg)
 			}
 		}
 		rcutorture_record_progress(++rcu_torture_current_version);
-		oldbatch = cur_ops->completed();
 		rcu_stutter_wait("rcu_torture_writer");
 	} while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
 	VERBOSE_PRINTK_STRING("rcu_torture_writer task stopping");
Signature · 1 line
1.8.1.5
#22 lore raw

PATCH 5/5 rcu: Make rcutorture emit online failures if verbose

In reply to Paul E. McKenney

From: "Paul E. McKenney" <[email protected]>

Although rcutorture counts CPU-hotplug online failures, it does not explicitly record which CPUs were having trouble coming online. This commit therefore emits a console message when online failure occurs.

---
 kernel/rcutorture.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
kernel/rcutorture.c +7 -1
index 869dac2..a4a73d4 100644
@@ -1434,7 +1434,13 @@ rcu_torture_onoff(void *arg)
 					 torture_type, cpu);
 			starttime = jiffies;
 			n_online_attempts++;
-			if (cpu_up(cpu) == 0) {
+			ret = cpu_up(cpu);
+			if (ret) {
+				if (verbose)
+					pr_alert("%s" TORTURE_FLAG
+						 "rcu_torture_onoff task: online %d failed: errno %d\n",
+						 torture_type, cpu, ret);
+			} else {
 				if (verbose)
 					pr_alert("%s" TORTURE_FLAG
 						 "rcu_torture_onoff task: onlined %d\n",
Signature · 1 line
1.8.1.5
maintainer Reviewed-by on v1 1/5
#23 lore raw

Re: [PATCH tip/core/rcu 1/5] rcu: Add duplicate-callback tests to rcutorture

In reply to Paul E. McKenney
Quoted 6 lines · Paul E. McKenney

From: "Paul E. McKenney" <[email protected]>

This commit adds a object_debug option to rcutorture to allow the debug-object-based checks for duplicate call_rcu() invocations to be deterministically tested.

Quoted 9 lines
Cc Mathieu Desnoyers <[email protected]>
Cc Sedat Dilek <[email protected]>
Cc Davidlohr Bueso <[email protected]>
Cc Rik van Riel <[email protected]>
Cc Thomas Gleixner <[email protected]>
Cc Linus Torvalds <[email protected]>
[ paulmck: Banish mid-function ifdef, more or less per Josh Triplett. ]
Quoted 84 lines
---
 kernel/rcutorture.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)
kernel/rcutorture.c +45 -0
index 3d936f0f..f5cf2bb 100644
@@ -66,6 +66,7 @@ static int fqs_duration;	/* Duration of bursts (us), 0 to disable. */
 static int fqs_holdoff;		/* Hold time within burst (us). */
 static int fqs_stutter = 3;	/* Wait time between bursts (s). */
 static int n_barrier_cbs;	/* Number of callbacks to test RCU barriers. */
+static int object_debug;	/* Test object-debug double call_rcu()?. */
 static int onoff_interval;	/* Wait time between CPU hotplugs, 0=disable. */
 static int onoff_holdoff;	/* Seconds after boot before CPU hotplugs. */
 static int shutdown_secs;	/* Shutdown time (s).  <=0 for no shutdown. */
@@ -100,6 +101,8 @@ module_param(fqs_stutter, int, 0444);
 MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)");
 module_param(n_barrier_cbs, int, 0444);
 MODULE_PARM_DESC(n_barrier_cbs, "# of callbacks/kthreads for barrier testing");
+module_param(object_debug, int, 0444);
+MODULE_PARM_DESC(object_debug, "Enable debug-object double call_rcu() testing");
 module_param(onoff_interval, int, 0444);
 MODULE_PARM_DESC(onoff_interval, "Time between CPU hotplugs (s), 0=disable");
 module_param(onoff_holdoff, int, 0444);
@@ -1934,6 +1937,46 @@ rcu_torture_cleanup(void)
 		rcu_torture_print_module_parms(cur_ops, "End of test: SUCCESS");
 }
 
+#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
+static void rcu_torture_leak_cb(struct rcu_head *rhp)
+{
+}
+
+static void rcu_torture_err_cb(struct rcu_head *rhp)
+{
+	/* This -might- happen due to race conditions, but is unlikely. */
+	pr_alert("rcutorture: duplicated callback was invoked.\n");
+}
+#endif /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
+
+/*
+ * Verify that double-free causes debug-objects to complain, but only
+ * if CONFIG_DEBUG_OBJECTS_RCU_HEAD=y.  Otherwise, say that the test
+ * cannot be carried out.
+ */
+static void rcu_test_debug_objects(void)
+{
+#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
+	struct rcu_head rh1;
+	struct rcu_head rh2;
+
+	init_rcu_head_on_stack(&rh1);
+	init_rcu_head_on_stack(&rh2);
+	pr_alert("rcutorture: WARN: Duplicate call_rcu() test starting.\n");
+	local_irq_disable(); /* Make it hard to finish grace period. */
+	call_rcu(&rh1, rcu_torture_leak_cb); /* start grace period. */
+	call_rcu(&rh2, rcu_torture_err_cb);
+	call_rcu(&rh2, rcu_torture_err_cb); /* duplicate callback. */
+	local_irq_enable();
+	rcu_barrier();
+	pr_alert("rcutorture: WARN: Duplicate call_rcu() test complete.\n");
+	destroy_rcu_head_on_stack(&rh1);
+	destroy_rcu_head_on_stack(&rh2);
+#else /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
+	pr_alert("rcutorture: !CONFIG_DEBUG_OBJECTS_RCU_HEAD, not testing duplicate call_rcu()\n");
+#endif /* #else #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
+}
+
 static int __init
 rcu_torture_init(void)
 {
@@ -2163,6 +2206,8 @@ rcu_torture_init(void)
 		firsterr = retval;
 		goto unwind;
 	}
+	if (object_debug)
+		rcu_test_debug_objects();
 	rcutorture_record_test_transition();
 	mutex_unlock(&fullstop_mutex);
 	return 0;
Signature · 1 line
1.8.1.5
#24 lore raw

Re: [PATCH tip/core/rcu 1/5] rcu: Add duplicate-callback tests to rcutorture

In reply to Paul E. McKenney
Quoted 61 lines · Paul E. McKenney

From: "Paul E. McKenney" <[email protected]>

This commit adds a object_debug option to rcutorture to allow the debug-object-based checks for duplicate call_rcu() invocations to be deterministically tested.

Cc Mathieu Desnoyers <[email protected]>
Cc Sedat Dilek <[email protected]>
Cc Davidlohr Bueso <[email protected]>
Cc Rik van Riel <[email protected]>
Cc Thomas Gleixner <[email protected]>
Cc Linus Torvalds <[email protected]>
[ paulmck: Banish mid-function ifdef, more or less per Josh Triplett. ]
---
 kernel/rcutorture.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)
kernel/rcutorture.c +20 -0
index 3d936f0f..f5cf2bb 100644
@@ -66,6 +66,7 @@ static int fqs_duration;	/* Duration of bursts (us), 0 to disable. */
 static int fqs_holdoff;		/* Hold time within burst (us). */
 static int fqs_stutter = 3;	/* Wait time between bursts (s). */
 static int n_barrier_cbs;	/* Number of callbacks to test RCU barriers. */
+static int object_debug;	/* Test object-debug double call_rcu()?. */
 static int onoff_interval;	/* Wait time between CPU hotplugs, 0=disable. */
 static int onoff_holdoff;	/* Seconds after boot before CPU hotplugs. */
 static int shutdown_secs;	/* Shutdown time (s).  <=0 for no shutdown. */
@@ -100,6 +101,8 @@ module_param(fqs_stutter, int, 0444);
 MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)");
 module_param(n_barrier_cbs, int, 0444);
 MODULE_PARM_DESC(n_barrier_cbs, "# of callbacks/kthreads for barrier testing");
+module_param(object_debug, int, 0444);
+MODULE_PARM_DESC(object_debug, "Enable debug-object double call_rcu() testing");
 module_param(onoff_interval, int, 0444);
 MODULE_PARM_DESC(onoff_interval, "Time between CPU hotplugs (s), 0=disable");
 module_param(onoff_holdoff, int, 0444);
@@ -1934,6 +1937,46 @@ rcu_torture_cleanup(void)
 		rcu_torture_print_module_parms(cur_ops, "End of test: SUCCESS");
 }
 
+#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
+static void rcu_torture_leak_cb(struct rcu_head *rhp)
+{
+}
+
+static void rcu_torture_err_cb(struct rcu_head *rhp)
+{
+	/* This -might- happen due to race conditions, but is unlikely. */
+	pr_alert("rcutorture: duplicated callback was invoked.\n");
+}
+#endif /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
+
+/*
+ * Verify that double-free causes debug-objects to complain, but only
+ * if CONFIG_DEBUG_OBJECTS_RCU_HEAD=y.  Otherwise, say that the test
+ * cannot be carried out.
+ */

kernel/rcutorture.c rcu_torture_cleanup(void) · line 1966

Quoted 10 lines
kernel/rcutorture.c +10 -0
+static void rcu_test_debug_objects(void)
+{
+#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
+	struct rcu_head rh1;
+	struct rcu_head rh2;
+
+	init_rcu_head_on_stack(&rh1);
+	init_rcu_head_on_stack(&rh2);
+	pr_alert("rcutorture: WARN: Duplicate call_rcu() test starting.\n");
+	local_irq_disable(); /* Make it hard to finish grace period. */

you can use rcu_read_lock() directly.

Quoted 25 lines
kernel/rcutorture.c +15 -0
+	call_rcu(&rh1, rcu_torture_leak_cb); /* start grace period. */
+	call_rcu(&rh2, rcu_torture_err_cb);
+	call_rcu(&rh2, rcu_torture_err_cb); /* duplicate callback. */
+	local_irq_enable();
+	rcu_barrier();
+	pr_alert("rcutorture: WARN: Duplicate call_rcu() test complete.\n");
+	destroy_rcu_head_on_stack(&rh1);
+	destroy_rcu_head_on_stack(&rh2);
+#else /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
+	pr_alert("rcutorture: !CONFIG_DEBUG_OBJECTS_RCU_HEAD, not testing duplicate call_rcu()\n");
+#endif /* #else #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
+}
+
 static int __init
 rcu_torture_init(void)
 {
@@ -2163,6 +2206,8 @@ rcu_torture_init(void)
 		firsterr = retval;
 		goto unwind;
 	}
+	if (object_debug)
+		rcu_test_debug_objects();
 	rcutorture_record_test_transition();
 	mutex_unlock(&fullstop_mutex);
 	return 0;
#25 lore raw

Re: [PATCH tip/core/rcu 1/5] rcu: Add duplicate-callback tests to rcutorture

Quoted 66 lines · Lai Jiangshan
Quoted 65 lines · Paul E. McKenney

From: "Paul E. McKenney" <[email protected]>

This commit adds a object_debug option to rcutorture to allow the debug-object-based checks for duplicate call_rcu() invocations to be deterministically tested.

Cc Mathieu Desnoyers <[email protected]>
Cc Sedat Dilek <[email protected]>
Cc Davidlohr Bueso <[email protected]>
Cc Rik van Riel <[email protected]>
Cc Thomas Gleixner <[email protected]>
Cc Linus Torvalds <[email protected]>
[ paulmck: Banish mid-function ifdef, more or less per Josh Triplett. ]
---
 kernel/rcutorture.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)
kernel/rcutorture.c +24 -0
index 3d936f0f..f5cf2bb 100644
@@ -66,6 +66,7 @@ static int fqs_duration;	/* Duration of bursts (us), 0 to disable. */
 static int fqs_holdoff;		/* Hold time within burst (us). */
 static int fqs_stutter = 3;	/* Wait time between bursts (s). */
 static int n_barrier_cbs;	/* Number of callbacks to test RCU barriers. */
+static int object_debug;	/* Test object-debug double call_rcu()?. */
 static int onoff_interval;	/* Wait time between CPU hotplugs, 0=disable. */
 static int onoff_holdoff;	/* Seconds after boot before CPU hotplugs. */
 static int shutdown_secs;	/* Shutdown time (s).  <=0 for no shutdown. */
@@ -100,6 +101,8 @@ module_param(fqs_stutter, int, 0444);
 MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)");
 module_param(n_barrier_cbs, int, 0444);
 MODULE_PARM_DESC(n_barrier_cbs, "# of callbacks/kthreads for barrier testing");
+module_param(object_debug, int, 0444);
+MODULE_PARM_DESC(object_debug, "Enable debug-object double call_rcu() testing");
 module_param(onoff_interval, int, 0444);
 MODULE_PARM_DESC(onoff_interval, "Time between CPU hotplugs (s), 0=disable");
 module_param(onoff_holdoff, int, 0444);
@@ -1934,6 +1937,46 @@ rcu_torture_cleanup(void)
 		rcu_torture_print_module_parms(cur_ops, "End of test: SUCCESS");
 }
 
+#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
+static void rcu_torture_leak_cb(struct rcu_head *rhp)
+{
+}
+
+static void rcu_torture_err_cb(struct rcu_head *rhp)
+{
+	/* This -might- happen due to race conditions, but is unlikely. */
+	pr_alert("rcutorture: duplicated callback was invoked.\n");
+}
+#endif /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
+
+/*
+ * Verify that double-free causes debug-objects to complain, but only
+ * if CONFIG_DEBUG_OBJECTS_RCU_HEAD=y.  Otherwise, say that the test
+ * cannot be carried out.
+ */
+static void rcu_test_debug_objects(void)
+{
+#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
+	struct rcu_head rh1;
Quoted 8 lines

kernel/rcutorture.c rcu_torture_cleanup(void) · line 1966

Quoted 6 lines
kernel/rcutorture.c +6 -0
+	struct rcu_head rh2;
+
+	init_rcu_head_on_stack(&rh1);
+	init_rcu_head_on_stack(&rh2);
+	pr_alert("rcutorture: WARN: Duplicate call_rcu() test starting.\n");
+	local_irq_disable(); /* Make it hard to finish grace period. */

you can use rcu_read_lock() directly.

I could do that as well, but it doesn't do everything that local_irq_disable() does.

Right, which means that my comment is bad. Fixing both, thank you!

Quoted 1 line

kernel/rcutorture.c rcu_torture_cleanup(void) · line 1967

Quoted 1 line
kernel/rcutorture.c +1 -0
+	call_rcu(&rh1, rcu_torture_leak_cb); /* start grace period. */

And the one above cannot start a grace period due to irqs being enabled. Which is -almost- always OK, but...

Quoted 1 line

kernel/rcutorture.c rcu_torture_cleanup(void) · line 1968

Quoted 1 line
kernel/rcutorture.c +1 -0
+	call_rcu(&rh2, rcu_torture_err_cb);

And this one should invoke rcu_torture_leak_cb instead of rcu_torture_err_cb(). Just results in a confusing error message, but...

OK, a few more fixes, then!

Quoted 10 lines

kernel/rcutorture.c rcu_torture_cleanup(void) · line 1978

Quoted 10 lines
kernel/rcutorture.c +10 -0
+	call_rcu(&rh2, rcu_torture_err_cb); /* duplicate callback. */
+	local_irq_enable();
+	rcu_barrier();
+	pr_alert("rcutorture: WARN: Duplicate call_rcu() test complete.\n");
+	destroy_rcu_head_on_stack(&rh1);
+	destroy_rcu_head_on_stack(&rh2);
+#else /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
+	pr_alert("rcutorture: !CONFIG_DEBUG_OBJECTS_RCU_HEAD, not testing duplicate call_rcu()\n");
+#endif /* #else #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
+}

The result is as follows. Better?

Thanx, Paul

#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
static void rcu_torture_leak_cb(struct rcu_head *rhp) {
}

static void rcu_torture_err_cb(struct rcu_head *rhp)
{
/*
* This -might- happen due to race conditions, but is unlikely.
* The scenario that leads to this happening is that the
* first of the pair of duplicate callbacks is queued,
* someone else starts a grace period that includes that
* callback, then the second of the pair must wait for the
* next grace period. Unlikely, but can happen. If it
* does happen, the debug-objects subsystem won't have splatted. */
pr_alert("rcutorture: duplicated callback was invoked.\n");
}
#endif /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */

/*
* Verify that double-free causes debug-objects to complain, but only
* if CONFIG_DEBUG_OBJECTS_RCU_HEAD=y. Otherwise, say that the test
* cannot be carried out.
*/
static void rcu_test_debug_objects(void)
{

#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
	struct rcu_head rh1;
	struct rcu_head rh2;

	init_rcu_head_on_stack(&rh1);
	init_rcu_head_on_stack(&rh2);
	pr_alert("rcutorture: WARN: Duplicate call_rcu() test starting.\n");
	preempt_disable(); /* Prevent preemption from interrupting test. */
	rcu_read_lock(); /* Make it impossible to finish a grace period. */
	call_rcu(&rh1, rcu_torture_leak_cb); /* Start grace period. */
	local_irq_disable(); /* Make it harder to start a new grace period. */
	call_rcu(&rh2, rcu_torture_leak_cb);
	call_rcu(&rh2, rcu_torture_err_cb); /* Duplicate callback. */
	local_irq_enable();
	rcu_read_unlock();
	preempt_enable();
	rcu_barrier();
	pr_alert("rcutorture: WARN: Duplicate call_rcu() test complete.\n");
	destroy_rcu_head_on_stack(&rh1);
	destroy_rcu_head_on_stack(&rh2);
#else /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
	pr_alert("rcutorture: !CONFIG_DEBUG_OBJECTS_RCU_HEAD, not testing duplicate call_rcu()\n");

#endif /* #else #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */ }

Quoted 14 lines
Quoted 13 lines
kernel/rcutorture.c +3 -0
+
 static int __init
 rcu_torture_init(void)
 {
@@ -2163,6 +2206,8 @@ rcu_torture_init(void)
 		firsterr = retval;
 		goto unwind;
 	}
+	if (object_debug)
+		rcu_test_debug_objects();
 	rcutorture_record_test_transition();
 	mutex_unlock(&fullstop_mutex);
 	return 0;
#26 lore raw

Re: [PATCH tip/core/rcu 1/5] rcu: Add duplicate-callback tests to rcutorture

Quoted 86 lines · Paul E. McKenney
Quoted 66 lines · Lai Jiangshan
Quoted 65 lines · Paul E. McKenney

From: "Paul E. McKenney" <[email protected]>

This commit adds a object_debug option to rcutorture to allow the debug-object-based checks for duplicate call_rcu() invocations to be deterministically tested.

Cc Mathieu Desnoyers <[email protected]>
Cc Sedat Dilek <[email protected]>
Cc Davidlohr Bueso <[email protected]>
Cc Rik van Riel <[email protected]>
Cc Thomas Gleixner <[email protected]>
Cc Linus Torvalds <[email protected]>
[ paulmck: Banish mid-function ifdef, more or less per Josh Triplett. ]
---
 kernel/rcutorture.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)
kernel/rcutorture.c +24 -0
index 3d936f0f..f5cf2bb 100644
@@ -66,6 +66,7 @@ static int fqs_duration;	/* Duration of bursts (us), 0 to disable. */
 static int fqs_holdoff;		/* Hold time within burst (us). */
 static int fqs_stutter = 3;	/* Wait time between bursts (s). */
 static int n_barrier_cbs;	/* Number of callbacks to test RCU barriers. */
+static int object_debug;	/* Test object-debug double call_rcu()?. */
 static int onoff_interval;	/* Wait time between CPU hotplugs, 0=disable. */
 static int onoff_holdoff;	/* Seconds after boot before CPU hotplugs. */
 static int shutdown_secs;	/* Shutdown time (s).  <=0 for no shutdown. */
@@ -100,6 +101,8 @@ module_param(fqs_stutter, int, 0444);
 MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)");
 module_param(n_barrier_cbs, int, 0444);
 MODULE_PARM_DESC(n_barrier_cbs, "# of callbacks/kthreads for barrier testing");
+module_param(object_debug, int, 0444);
+MODULE_PARM_DESC(object_debug, "Enable debug-object double call_rcu() testing");
 module_param(onoff_interval, int, 0444);
 MODULE_PARM_DESC(onoff_interval, "Time between CPU hotplugs (s), 0=disable");
 module_param(onoff_holdoff, int, 0444);
@@ -1934,6 +1937,46 @@ rcu_torture_cleanup(void)
 		rcu_torture_print_module_parms(cur_ops, "End of test: SUCCESS");
 }
 
+#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
+static void rcu_torture_leak_cb(struct rcu_head *rhp)
+{
+}
+
+static void rcu_torture_err_cb(struct rcu_head *rhp)
+{
+	/* This -might- happen due to race conditions, but is unlikely. */
+	pr_alert("rcutorture: duplicated callback was invoked.\n");
+}
+#endif /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
+
+/*
+ * Verify that double-free causes debug-objects to complain, but only
+ * if CONFIG_DEBUG_OBJECTS_RCU_HEAD=y.  Otherwise, say that the test
+ * cannot be carried out.
+ */
+static void rcu_test_debug_objects(void)
+{
+#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
+	struct rcu_head rh1;
Quoted 8 lines

kernel/rcutorture.c rcu_torture_cleanup(void) · line 1966

Quoted 6 lines
kernel/rcutorture.c +6 -0
+	struct rcu_head rh2;
+
+	init_rcu_head_on_stack(&rh1);
+	init_rcu_head_on_stack(&rh2);
+	pr_alert("rcutorture: WARN: Duplicate call_rcu() test starting.\n");
+	local_irq_disable(); /* Make it hard to finish grace period. */

you can use rcu_read_lock() directly.

I could do that as well, but it doesn't do everything that local_irq_disable() does.

Right, which means that my comment is bad. Fixing both, thank you!

Quoted 1 line

kernel/rcutorture.c rcu_torture_cleanup(void) · line 1967

Quoted 1 line
kernel/rcutorture.c +1 -0
+	call_rcu(&rh1, rcu_torture_leak_cb); /* start grace period. */

And the one above cannot start a grace period due to irqs being enabled. Which is -almost- always OK, but...

Quoted 4 lines
Quoted 1 line

kernel/rcutorture.c rcu_torture_cleanup(void) · line 1968

Quoted 1 line
kernel/rcutorture.c +1 -0
+	call_rcu(&rh2, rcu_torture_err_cb);

And this one should invoke rcu_torture_leak_cb instead of rcu_torture_err_cb(). Just results in a confusing error message, but...

I still don't understand why rcu_torture_err_cb() will be called when:

rcu_read_lock();
call_rcu(&rh2, rcu_torture_leak_cb);
call_rcu(&rh2, rcu_torture_err_cb); // rh2 will be still queued here,

				    // debug-objects will find it and
				    // change it to rcu_leak_callback()

rcu_read_unlock();

Quoted 91 lines

OK, a few more fixes, then!

Quoted 10 lines

kernel/rcutorture.c rcu_torture_cleanup(void) · line 1978

Quoted 10 lines
kernel/rcutorture.c +10 -0
+	call_rcu(&rh2, rcu_torture_err_cb); /* duplicate callback. */
+	local_irq_enable();
+	rcu_barrier();
+	pr_alert("rcutorture: WARN: Duplicate call_rcu() test complete.\n");
+	destroy_rcu_head_on_stack(&rh1);
+	destroy_rcu_head_on_stack(&rh2);
+#else /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
+	pr_alert("rcutorture: !CONFIG_DEBUG_OBJECTS_RCU_HEAD, not testing duplicate call_rcu()\n");
+#endif /* #else #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
+}

The result is as follows. Better?

Thanx, Paul

#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
static void rcu_torture_leak_cb(struct rcu_head *rhp) {
}

static void rcu_torture_err_cb(struct rcu_head *rhp)
{
/*
* This -might- happen due to race conditions, but is unlikely.
* The scenario that leads to this happening is that the
* first of the pair of duplicate callbacks is queued,
* someone else starts a grace period that includes that
* callback, then the second of the pair must wait for the
* next grace period. Unlikely, but can happen. If it
* does happen, the debug-objects subsystem won't have splatted. */
pr_alert("rcutorture: duplicated callback was invoked.\n");
}
#endif /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */

/*
* Verify that double-free causes debug-objects to complain, but only
* if CONFIG_DEBUG_OBJECTS_RCU_HEAD=y. Otherwise, say that the test
* cannot be carried out.
*/
static void rcu_test_debug_objects(void)
{

#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
	struct rcu_head rh1;
	struct rcu_head rh2;

	init_rcu_head_on_stack(&rh1);
	init_rcu_head_on_stack(&rh2);
	pr_alert("rcutorture: WARN: Duplicate call_rcu() test starting.\n");
	preempt_disable(); /* Prevent preemption from interrupting test. */
	rcu_read_lock(); /* Make it impossible to finish a grace period. */
	call_rcu(&rh1, rcu_torture_leak_cb); /* Start grace period. */
	local_irq_disable(); /* Make it harder to start a new grace period. */
	call_rcu(&rh2, rcu_torture_leak_cb);
	call_rcu(&rh2, rcu_torture_err_cb); /* Duplicate callback. */
	local_irq_enable();
	rcu_read_unlock();
	preempt_enable();
	rcu_barrier();
	pr_alert("rcutorture: WARN: Duplicate call_rcu() test complete.\n");
	destroy_rcu_head_on_stack(&rh1);
	destroy_rcu_head_on_stack(&rh2);
#else /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
	pr_alert("rcutorture: !CONFIG_DEBUG_OBJECTS_RCU_HEAD, not testing duplicate call_rcu()\n");

#endif /* #else #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */ }

Quoted 5 lines
Quoted 5 lines
kernel/rcutorture.c +1 -0
+
 static int __init
 rcu_torture_init(void)
 {
@@ -2163,6 +2206,8 @@ rcu_torture_init(void)
Quoted 9 lines

kernel/rcutorture.c rcu_torture_init(void) · line 2213

Quoted 8 lines
kernel/rcutorture.c +2 -0
 		firsterr = retval;
 		goto unwind;
 	}
+	if (object_debug)
+		rcu_test_debug_objects();
 	rcutorture_record_test_transition();
 	mutex_unlock(&fullstop_mutex);
 	return 0;

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

#27 lore raw

Re: [PATCH tip/core/rcu 1/5] rcu: Add duplicate-callback tests to rcutorture

Quoted 92 lines · Lai Jiangshan
Quoted 86 lines · Paul E. McKenney
Quoted 66 lines · Lai Jiangshan
Quoted 65 lines · Paul E. McKenney

From: "Paul E. McKenney" <[email protected]>

This commit adds a object_debug option to rcutorture to allow the debug-object-based checks for duplicate call_rcu() invocations to be deterministically tested.

Cc Mathieu Desnoyers <[email protected]>
Cc Sedat Dilek <[email protected]>
Cc Davidlohr Bueso <[email protected]>
Cc Rik van Riel <[email protected]>
Cc Thomas Gleixner <[email protected]>
Cc Linus Torvalds <[email protected]>
[ paulmck: Banish mid-function ifdef, more or less per Josh Triplett. ]
---
 kernel/rcutorture.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)
kernel/rcutorture.c +24 -0
index 3d936f0f..f5cf2bb 100644
@@ -66,6 +66,7 @@ static int fqs_duration;	/* Duration of bursts (us), 0 to disable. */
 static int fqs_holdoff;		/* Hold time within burst (us). */
 static int fqs_stutter = 3;	/* Wait time between bursts (s). */
 static int n_barrier_cbs;	/* Number of callbacks to test RCU barriers. */
+static int object_debug;	/* Test object-debug double call_rcu()?. */
 static int onoff_interval;	/* Wait time between CPU hotplugs, 0=disable. */
 static int onoff_holdoff;	/* Seconds after boot before CPU hotplugs. */
 static int shutdown_secs;	/* Shutdown time (s).  <=0 for no shutdown. */
@@ -100,6 +101,8 @@ module_param(fqs_stutter, int, 0444);
 MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)");
 module_param(n_barrier_cbs, int, 0444);
 MODULE_PARM_DESC(n_barrier_cbs, "# of callbacks/kthreads for barrier testing");
+module_param(object_debug, int, 0444);
+MODULE_PARM_DESC(object_debug, "Enable debug-object double call_rcu() testing");
 module_param(onoff_interval, int, 0444);
 MODULE_PARM_DESC(onoff_interval, "Time between CPU hotplugs (s), 0=disable");
 module_param(onoff_holdoff, int, 0444);
@@ -1934,6 +1937,46 @@ rcu_torture_cleanup(void)
 		rcu_torture_print_module_parms(cur_ops, "End of test: SUCCESS");
 }
 
+#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
+static void rcu_torture_leak_cb(struct rcu_head *rhp)
+{
+}
+
+static void rcu_torture_err_cb(struct rcu_head *rhp)
+{
+	/* This -might- happen due to race conditions, but is unlikely. */
+	pr_alert("rcutorture: duplicated callback was invoked.\n");
+}
+#endif /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
+
+/*
+ * Verify that double-free causes debug-objects to complain, but only
+ * if CONFIG_DEBUG_OBJECTS_RCU_HEAD=y.  Otherwise, say that the test
+ * cannot be carried out.
+ */
+static void rcu_test_debug_objects(void)
+{
+#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
+	struct rcu_head rh1;
Quoted 8 lines

kernel/rcutorture.c rcu_torture_cleanup(void) · line 1966

Quoted 6 lines
kernel/rcutorture.c +6 -0
+	struct rcu_head rh2;
+
+	init_rcu_head_on_stack(&rh1);
+	init_rcu_head_on_stack(&rh2);
+	pr_alert("rcutorture: WARN: Duplicate call_rcu() test starting.\n");
+	local_irq_disable(); /* Make it hard to finish grace period. */

you can use rcu_read_lock() directly.

I could do that as well, but it doesn't do everything that local_irq_disable() does.

Right, which means that my comment is bad. Fixing both, thank you!

Quoted 1 line

kernel/rcutorture.c rcu_torture_cleanup(void) · line 1967

Quoted 1 line
kernel/rcutorture.c +1 -0
+	call_rcu(&rh1, rcu_torture_leak_cb); /* start grace period. */

And the one above cannot start a grace period due to irqs being enabled. Which is -almost- always OK, but...

Quoted 4 lines
Quoted 1 line

kernel/rcutorture.c rcu_torture_cleanup(void) · line 1968

Quoted 1 line
kernel/rcutorture.c +1 -0
+	call_rcu(&rh2, rcu_torture_err_cb);

And this one should invoke rcu_torture_leak_cb instead of rcu_torture_err_cb(). Just results in a confusing error message, but...

Quoted 8 lines

I still don't understand why rcu_torture_err_cb() will be called when:

rcu_read_lock();
call_rcu(&rh2, rcu_torture_leak_cb);
call_rcu(&rh2, rcu_torture_err_cb); // rh2 will be still queued here,

				    // debug-objects will find it and
				    // change it to rcu_leak_callback()

rcu_read_unlock();

Fair point, no chance of the second rh2 callback being queued after the first one is invoked! I will leave the message. Whoever sees it with the current code will have something to tell their grandchildren.

Thanx, Paul

Quoted 91 lines
Quoted 90 lines

OK, a few more fixes, then!

Quoted 10 lines

kernel/rcutorture.c rcu_torture_cleanup(void) · line 1978

Quoted 10 lines
kernel/rcutorture.c +10 -0
+	call_rcu(&rh2, rcu_torture_err_cb); /* duplicate callback. */
+	local_irq_enable();
+	rcu_barrier();
+	pr_alert("rcutorture: WARN: Duplicate call_rcu() test complete.\n");
+	destroy_rcu_head_on_stack(&rh1);
+	destroy_rcu_head_on_stack(&rh2);
+#else /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
+	pr_alert("rcutorture: !CONFIG_DEBUG_OBJECTS_RCU_HEAD, not testing duplicate call_rcu()\n");
+#endif /* #else #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
+}

The result is as follows. Better?

Thanx, Paul

#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
static void rcu_torture_leak_cb(struct rcu_head *rhp) {
}

static void rcu_torture_err_cb(struct rcu_head *rhp)
{
/*
* This -might- happen due to race conditions, but is unlikely.
* The scenario that leads to this happening is that the
* first of the pair of duplicate callbacks is queued,
* someone else starts a grace period that includes that
* callback, then the second of the pair must wait for the
* next grace period. Unlikely, but can happen. If it
* does happen, the debug-objects subsystem won't have splatted. */
pr_alert("rcutorture: duplicated callback was invoked.\n");
}
#endif /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */

/*
* Verify that double-free causes debug-objects to complain, but only
* if CONFIG_DEBUG_OBJECTS_RCU_HEAD=y. Otherwise, say that the test
* cannot be carried out.
*/
static void rcu_test_debug_objects(void)
{

#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
	struct rcu_head rh1;
	struct rcu_head rh2;

	init_rcu_head_on_stack(&rh1);
	init_rcu_head_on_stack(&rh2);
	pr_alert("rcutorture: WARN: Duplicate call_rcu() test starting.\n");
	preempt_disable(); /* Prevent preemption from interrupting test. */
	rcu_read_lock(); /* Make it impossible to finish a grace period. */
	call_rcu(&rh1, rcu_torture_leak_cb); /* Start grace period. */
	local_irq_disable(); /* Make it harder to start a new grace period. */
	call_rcu(&rh2, rcu_torture_leak_cb);
	call_rcu(&rh2, rcu_torture_err_cb); /* Duplicate callback. */
	local_irq_enable();
	rcu_read_unlock();
	preempt_enable();
	rcu_barrier();
	pr_alert("rcutorture: WARN: Duplicate call_rcu() test complete.\n");
	destroy_rcu_head_on_stack(&rh1);
	destroy_rcu_head_on_stack(&rh2);
#else /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
	pr_alert("rcutorture: !CONFIG_DEBUG_OBJECTS_RCU_HEAD, not testing duplicate call_rcu()\n");

#endif /* #else #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */ }

Quoted 5 lines
Quoted 5 lines
kernel/rcutorture.c +1 -0
+
 static int __init
 rcu_torture_init(void)
 {
@@ -2163,6 +2206,8 @@ rcu_torture_init(void)
Quoted 9 lines

kernel/rcutorture.c rcu_torture_init(void) · line 2213

Quoted 8 lines
kernel/rcutorture.c +2 -0
 		firsterr = retval;
 		goto unwind;
 	}
+	if (object_debug)
+		rcu_test_debug_objects();
 	rcutorture_record_test_transition();
 	mutex_unlock(&fullstop_mutex);
 	return 0;

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

#28 lore raw

Re: [PATCH tip/core/rcu 1/5] rcu: Add duplicate-callback tests to rcutorture

In reply to Paul E. McKenney

* Paul E. McKenney ([email protected]) wrote:
[...]

Quoted 1 line

The result is as follows. Better?

Hi Paul,

Pitching in late in the thread, so that I can get a share of the fun ;-)

Quoted 7 lines

Thanx, Paul

#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
static void rcu_torture_leak_cb(struct rcu_head *rhp) {
}

Quoted 15 lines

static void rcu_torture_err_cb(struct rcu_head *rhp)
{
/*
* This -might- happen due to race conditions, but is unlikely.
* The scenario that leads to this happening is that the
* first of the pair of duplicate callbacks is queued,
* someone else starts a grace period that includes that
* callback, then the second of the pair must wait for the
* next grace period. Unlikely, but can happen. If it
* does happen, the debug-objects subsystem won't have splatted. */
pr_alert("rcutorture: duplicated callback was invoked.\n");
}
#endif /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */

Hrm. Putting an #ifdef within a function when not utterly needed is usually a bad idea. How about:

/*
* Verify that double-free causes debug-objects to complain, but only
* if CONFIG_DEBUG_OBJECTS_RCU_HEAD=y. Otherwise, say that the test
* cannot be carried out.
*/
#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
static void rcu_test_debug_objects(void)
{
struct rcu_head rh1;
struct rcu_head rh2;

init_rcu_head_on_stack(&rh1);
init_rcu_head_on_stack(&rh2);
pr_alert("rcutorture: WARN: Duplicate call_rcu() test starting.\n"); preempt_disable(); /* Prevent preemption from interrupting test. */ rcu_read_lock(); /* Make it impossible to finish a grace period. */ call_rcu(&rh1, rcu_torture_leak_cb); /* Start grace period. */ local_irq_disable(); /* Make it harder to start a new grace period. */ call_rcu(&rh2, rcu_torture_leak_cb);
call_rcu(&rh2, rcu_torture_err_cb); /* Duplicate callback. */ local_irq_enable();
rcu_read_unlock();
preempt_enable();
rcu_barrier();
pr_alert("rcutorture: WARN: Duplicate call_rcu() test complete.\n"); destroy_rcu_head_on_stack(&rh1);
destroy_rcu_head_on_stack(&rh2);
}
#else /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
static void rcu_test_debug_objects(void)
{
pr_alert("rcutorture: !CONFIG_DEBUG_OBJECTS_RCU_HEAD, not testing duplicate call_rcu()\n");
}
#endif /* #else #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */

More comments inlined in the code below,

Quoted 7 lines

/*
* Verify that double-free causes debug-objects to complain, but only
* if CONFIG_DEBUG_OBJECTS_RCU_HEAD=y. Otherwise, say that the test
* cannot be carried out.
*/
static void rcu_test_debug_objects(void)
{

Quoted 10 lines
#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
	struct rcu_head rh1;
	struct rcu_head rh2;

	init_rcu_head_on_stack(&rh1);
	init_rcu_head_on_stack(&rh2);
	pr_alert("rcutorture: WARN: Duplicate call_rcu() test starting.\n");
	preempt_disable(); /* Prevent preemption from interrupting test. */
	rcu_read_lock(); /* Make it impossible to finish a grace period. */
	call_rcu(&rh1, rcu_torture_leak_cb); /* Start grace period. */

Are we really "starting" a grace period ? If rcu_test_debug_objects() is executed after some callbacks are already queued, are we, by definition, "starting" the grace period ?

Also, I find it weird to have, in that order:

1) preempt_disable()
2) rcu_read_lock()
3) local_irq_disable()

I would rather expect:

1) rcu_read_lock()
2) preempt_disable()
3) local_irq_disable()

So they come in increasing order of impact on the system: with non-preemptable RCU, the read-lock and preempt disable mean the same thing, however, with preemptable RCU, the impact of preempt disable seems larger than the impact of RCU read lock: preemption is still enabled when within a RCU critical section. Both will work, but I find this call order slightly weird.

Also, if your goal is to increase the chances that call_rcu() enqueues both callbacks into the same grace period, you might want to issue a rcu_barrier() early in this function, so that call_rcu() has even more chances to enqueue the callbacks into the same grace period.

However, if you care about testing enqueue into same _and_ different grace periods, you might want to turn this single-shot test into a stress-test by calling it repeatedly.

Thanks!

Mathieu

Quoted 30 lines
	local_irq_disable(); /* Make it harder to start a new grace period. */
	call_rcu(&rh2, rcu_torture_leak_cb);
	call_rcu(&rh2, rcu_torture_err_cb); /* Duplicate callback. */
	local_irq_enable();
	rcu_read_unlock();
	preempt_enable();
	rcu_barrier();
	pr_alert("rcutorture: WARN: Duplicate call_rcu() test complete.\n");
	destroy_rcu_head_on_stack(&rh1);
	destroy_rcu_head_on_stack(&rh2);
#else /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
	pr_alert("rcutorture: !CONFIG_DEBUG_OBJECTS_RCU_HEAD, not testing duplicate call_rcu()\n");

#endif /* #else #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */ }

Quoted 14 lines
Quoted 13 lines
kernel/rcutorture.c +3 -0
+
 static int __init
 rcu_torture_init(void)
 {
@@ -2163,6 +2206,8 @@ rcu_torture_init(void)
 		firsterr = retval;
 		goto unwind;
 	}
+	if (object_debug)
+		rcu_test_debug_objects();
 	rcutorture_record_test_transition();
 	mutex_unlock(&fullstop_mutex);
 	return 0;
Signature · 3 lines
Mathieu Desnoyers
EfficiOS Inc.
http://www.efficios.com
#29 lore raw

Re: [PATCH tip/core/rcu 1/5] rcu: Add duplicate-callback tests to rcutorture

Quoted 61 lines · Mathieu Desnoyers

* Paul E. McKenney ([email protected]) wrote:
[...]

Quoted 1 line

The result is as follows. Better?

Hi Paul,

Pitching in late in the thread, so that I can get a share of the fun ;-)

Quoted 7 lines

Thanx, Paul

#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
static void rcu_torture_leak_cb(struct rcu_head *rhp) {
}

Quoted 15 lines

static void rcu_torture_err_cb(struct rcu_head *rhp)
{
/*
* This -might- happen due to race conditions, but is unlikely.
* The scenario that leads to this happening is that the
* first of the pair of duplicate callbacks is queued,
* someone else starts a grace period that includes that
* callback, then the second of the pair must wait for the
* next grace period. Unlikely, but can happen. If it
* does happen, the debug-objects subsystem won't have splatted. */
pr_alert("rcutorture: duplicated callback was invoked.\n");
}
#endif /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */

Hrm. Putting an #ifdef within a function when not utterly needed is usually a bad idea. How about:

/*
* Verify that double-free causes debug-objects to complain, but only
* if CONFIG_DEBUG_OBJECTS_RCU_HEAD=y. Otherwise, say that the test
* cannot be carried out.
*/
#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
static void rcu_test_debug_objects(void)
{

(quoted diff) +0 -0
 	struct rcu_head rh1;
 	struct rcu_head rh2;
 
 	init_rcu_head_on_stack(&rh1);
 	init_rcu_head_on_stack(&rh2);
 	pr_alert("rcutorture: WARN: Duplicate call_rcu() test starting.\n");
 	preempt_disable(); /* Prevent preemption from interrupting test. */
 	rcu_read_lock(); /* Make it impossible to finish a grace period. */
 	call_rcu(&rh1, rcu_torture_leak_cb); /* Start grace period. */
 	local_irq_disable(); /* Make it harder to start a new grace period. */
 	call_rcu(&rh2, rcu_torture_leak_cb);
 	call_rcu(&rh2, rcu_torture_err_cb); /* Duplicate callback. */
 	local_irq_enable();
 	rcu_read_unlock();
 	preempt_enable();
 	rcu_barrier();
 	pr_alert("rcutorture: WARN: Duplicate call_rcu() test complete.\n");
 	destroy_rcu_head_on_stack(&rh1);
 	destroy_rcu_head_on_stack(&rh2);
Quoted 7 lines

}
#else /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
static void rcu_test_debug_objects(void)
{
pr_alert("rcutorture: !CONFIG_DEBUG_OBJECTS_RCU_HEAD, not testing duplicate call_rcu()\n");
}
#endif /* #else #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */

The objection to this is that it duplicates the function header, both copies of which must be updated. See Josh's and my discussion on this point earlier in the thread. Who knows, Josh might eventually convince me to individually ifdef the functions in kernel/rcutree_plugin.h, but I am not quite there yet. ;-)

That said, I do see two benefits of individual ifdef:

1. It is easy to see when a given function is included.
As it is, there are runs of many hundreds of lines of code where it might not be obvious to the casual reader.

2. Duplicated code is asking for silent rebase and merge errors.
This can happen when a change to the function header collides with a change that duplicates the function under ifdef.

So perhaps I will eventually convert to the individual-ifdef style. At the moment, I am in no hurry.

Quoted 36 lines

More comments inlined in the code below,

Quoted 7 lines

/*
* Verify that double-free causes debug-objects to complain, but only
* if CONFIG_DEBUG_OBJECTS_RCU_HEAD=y. Otherwise, say that the test
* cannot be carried out.
*/
static void rcu_test_debug_objects(void)
{

Quoted 10 lines
#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
	struct rcu_head rh1;
	struct rcu_head rh2;

	init_rcu_head_on_stack(&rh1);
	init_rcu_head_on_stack(&rh2);
	pr_alert("rcutorture: WARN: Duplicate call_rcu() test starting.\n");
	preempt_disable(); /* Prevent preemption from interrupting test. */
	rcu_read_lock(); /* Make it impossible to finish a grace period. */
	call_rcu(&rh1, rcu_torture_leak_cb); /* Start grace period. */

Are we really "starting" a grace period ? If rcu_test_debug_objects() is executed after some callbacks are already queued, are we, by definition, "starting" the grace period ?

Also, I find it weird to have, in that order:

1) preempt_disable()
2) rcu_read_lock()
3) local_irq_disable()

I would rather expect:

1) rcu_read_lock()
2) preempt_disable()
3) local_irq_disable()

Quoted 6 lines

So they come in increasing order of impact on the system: with non-preemptable RCU, the read-lock and preempt disable mean the same thing, however, with preemptable RCU, the impact of preempt disable seems larger than the impact of RCU read lock: preemption is still enabled when within a RCU critical section. Both will work, but I find this call order slightly weird.

If this was code that ran normally, I would agree with you. Your suggested ordering would reduce the scheduling-latency impact due to this code, among other things.

However, this code is a one-off that runs only once during an rcutorture run that explicitly calls for it using rcutorture's new object_debug module parameter.

Quoted 4 lines

Also, if your goal is to increase the chances that call_rcu() enqueues both callbacks into the same grace period, you might want to issue a rcu_barrier() early in this function, so that call_rcu() has even more chances to enqueue the callbacks into the same grace period.

The problem is that neither rcu_barrier() nor synchronize_rcu() clean up at a well-defined point in time. In both cases, the task will be awakened at some time after the operation completes, by which time any number of new grace periods might have started and completed.

Quoted 3 lines

However, if you care about testing enqueue into same _and_ different grace periods, you might want to turn this single-shot test into a stress-test by calling it repeatedly.

Good point, and I might do that. However, the above code has not yet failed to produce a debug-objects splat. When and if it does fail to splat, then running the code repeatedly would definitely be one of the fixes that I would consider. (Another potential fix being to simply load the rcutorture module a few times in succession, though your suggestion would in fact work better for my current testing setup.)

Thank you for your review and comments!

Thanx, Paul

Quoted 40 lines

Thanks!

Mathieu

Quoted 30 lines
	local_irq_disable(); /* Make it harder to start a new grace period. */
	call_rcu(&rh2, rcu_torture_leak_cb);
	call_rcu(&rh2, rcu_torture_err_cb); /* Duplicate callback. */
	local_irq_enable();
	rcu_read_unlock();
	preempt_enable();
	rcu_barrier();
	pr_alert("rcutorture: WARN: Duplicate call_rcu() test complete.\n");
	destroy_rcu_head_on_stack(&rh1);
	destroy_rcu_head_on_stack(&rh2);
#else /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
	pr_alert("rcutorture: !CONFIG_DEBUG_OBJECTS_RCU_HEAD, not testing duplicate call_rcu()\n");

#endif /* #else #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */ }

Quoted 14 lines
Quoted 13 lines
kernel/rcutorture.c +3 -0
+
 static int __init
 rcu_torture_init(void)
 {
@@ -2163,6 +2206,8 @@ rcu_torture_init(void)
 		firsterr = retval;
 		goto unwind;
 	}
+	if (object_debug)
+		rcu_test_debug_objects();
 	rcutorture_record_test_transition();
 	mutex_unlock(&fullstop_mutex);
 	return 0;
Signature · 3 lines
Mathieu Desnoyers
EfficiOS Inc.
http://www.efficios.com