Commit 4babd855 authored by Joel Fernandes (Google)'s avatar Joel Fernandes (Google) Committed by Paul E. McKenney

rcutorture: Add support to detect if boost kthread prio is too low

When rcutorture is built in to the kernel, an earlier patch detects
that and raises the priority of RCU's kthreads to allow rcutorture's
RCU priority boosting tests to succeed.

However, if rcutorture is built as a module, those priorities must be
raised manually via the rcutree.kthread_prio kernel boot parameter.
If this manual step is not taken, rcutorture's RCU priority boosting
tests will fail due to kthread starvation.  One approach would be to
raise the default priority, but that risks breaking existing users.
Another approach would be to allow runtime adjustment of RCU's kthread
priorities, but that introduces numerous "interesting" race conditions.
This patch therefore instead detects too-low priorities, and prints a
message and disables the RCU priority boosting tests in that case.
Signed-off-by: default avatarJoel Fernandes (Google) <joel@joelfernandes.org>
Signed-off-by: default avatarPaul E. McKenney <paulmck@linux.vnet.ibm.com>
parent 622be33f
...@@ -502,6 +502,7 @@ static inline void rcu_force_quiescent_state(void) { } ...@@ -502,6 +502,7 @@ static inline void rcu_force_quiescent_state(void) { }
static inline void rcu_bh_force_quiescent_state(void) { } static inline void rcu_bh_force_quiescent_state(void) { }
static inline void rcu_sched_force_quiescent_state(void) { } static inline void rcu_sched_force_quiescent_state(void) { }
static inline void show_rcu_gp_kthreads(void) { } static inline void show_rcu_gp_kthreads(void) { }
static inline int rcu_get_gp_kthreads_prio(void) { return 0; }
#else /* #ifdef CONFIG_TINY_RCU */ #else /* #ifdef CONFIG_TINY_RCU */
unsigned long rcu_get_gp_seq(void); unsigned long rcu_get_gp_seq(void);
unsigned long rcu_bh_get_gp_seq(void); unsigned long rcu_bh_get_gp_seq(void);
...@@ -510,6 +511,7 @@ unsigned long rcu_exp_batches_completed(void); ...@@ -510,6 +511,7 @@ unsigned long rcu_exp_batches_completed(void);
unsigned long rcu_exp_batches_completed_sched(void); unsigned long rcu_exp_batches_completed_sched(void);
unsigned long srcu_batches_completed(struct srcu_struct *sp); unsigned long srcu_batches_completed(struct srcu_struct *sp);
void show_rcu_gp_kthreads(void); void show_rcu_gp_kthreads(void);
int rcu_get_gp_kthreads_prio(void);
void rcu_force_quiescent_state(void); void rcu_force_quiescent_state(void);
void rcu_bh_force_quiescent_state(void); void rcu_bh_force_quiescent_state(void);
void rcu_sched_force_quiescent_state(void); void rcu_sched_force_quiescent_state(void);
......
...@@ -1787,6 +1787,32 @@ static void rcu_torture_barrier_cleanup(void) ...@@ -1787,6 +1787,32 @@ static void rcu_torture_barrier_cleanup(void)
} }
} }
static bool rcu_torture_can_boost(void)
{
static int boost_warn_once;
int prio;
if (!(test_boost == 1 && cur_ops->can_boost) && test_boost != 2)
return false;
prio = rcu_get_gp_kthreads_prio();
if (!prio)
return false;
if (prio < 2) {
if (boost_warn_once == 1)
return false;
pr_alert("%s: WARN: RCU kthread priority too low to test boosting. "
"Skipping RCU boost test. Try passing rcutree.kthread_prio > 1 "
"on the kernel command line.\n", KBUILD_MODNAME);
boost_warn_once = 1;
return false;
}
return true;
}
static enum cpuhp_state rcutor_hp; static enum cpuhp_state rcutor_hp;
static void static void
...@@ -1831,8 +1857,7 @@ rcu_torture_cleanup(void) ...@@ -1831,8 +1857,7 @@ rcu_torture_cleanup(void)
torture_stop_kthread(rcu_torture_fqs, fqs_task); torture_stop_kthread(rcu_torture_fqs, fqs_task);
for (i = 0; i < ncbflooders; i++) for (i = 0; i < ncbflooders; i++)
torture_stop_kthread(rcu_torture_cbflood, cbflood_task[i]); torture_stop_kthread(rcu_torture_cbflood, cbflood_task[i]);
if ((test_boost == 1 && cur_ops->can_boost) || if (rcu_torture_can_boost())
test_boost == 2)
cpuhp_remove_state(rcutor_hp); cpuhp_remove_state(rcutor_hp);
/* /*
...@@ -2056,8 +2081,7 @@ rcu_torture_init(void) ...@@ -2056,8 +2081,7 @@ rcu_torture_init(void)
test_boost_interval = 1; test_boost_interval = 1;
if (test_boost_duration < 2) if (test_boost_duration < 2)
test_boost_duration = 2; test_boost_duration = 2;
if ((test_boost == 1 && cur_ops->can_boost) || if (rcu_torture_can_boost()) {
test_boost == 2) {
boost_starttime = jiffies + test_boost_interval * HZ; boost_starttime = jiffies + test_boost_interval * HZ;
......
...@@ -180,6 +180,13 @@ module_param(gp_init_delay, int, 0444); ...@@ -180,6 +180,13 @@ module_param(gp_init_delay, int, 0444);
static int gp_cleanup_delay; static int gp_cleanup_delay;
module_param(gp_cleanup_delay, int, 0444); module_param(gp_cleanup_delay, int, 0444);
/* Retreive RCU kthreads priority for rcutorture */
int rcu_get_gp_kthreads_prio(void)
{
return kthread_prio;
}
EXPORT_SYMBOL_GPL(rcu_get_gp_kthreads_prio);
/* /*
* Number of grace periods between delays, normalized by the duration of * Number of grace periods between delays, normalized by the duration of
* the delay. The longer the delay, the more the grace periods between * the delay. The longer the delay, the more the grace periods between
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment