rcutorture: Make stutter_wait() caller restore priority

Currently, stutter_wait() will happily spin waiting for the stutter
interval to end even if the caller is running at a real-time priority
level.  This could starve normal-priority tasks for no good reason.  This
commit therefore drops the calling task's priority to SCHED_OTHER MAX_NICE
if stutter_wait() needs to wait.  But when it waits, stutter_wait()
returns true, which allows the caller to restore the priority if needed.
Callers that were already running at SCHED_OTHER MAX_NICE obviously
do not need any changes, but this commit also restores priority for
higher-priority callers.

Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
This commit is contained in:
Paul E. McKenney 2020-09-22 16:42:42 -07:00
Родитель c1e0628758
Коммит ab1b7880de
2 изменённых файлов: 22 добавлений и 11 удалений

Просмотреть файл

@ -912,7 +912,8 @@ static int rcu_torture_boost(void *arg)
oldstarttime = boost_starttime; oldstarttime = boost_starttime;
while (time_before(jiffies, oldstarttime)) { while (time_before(jiffies, oldstarttime)) {
schedule_timeout_interruptible(oldstarttime - jiffies); schedule_timeout_interruptible(oldstarttime - jiffies);
stutter_wait("rcu_torture_boost"); if (stutter_wait("rcu_torture_boost"))
sched_set_fifo_low(current);
if (torture_must_stop()) if (torture_must_stop())
goto checkwait; goto checkwait;
} }
@ -932,7 +933,8 @@ static int rcu_torture_boost(void *arg)
jiffies); jiffies);
call_rcu_time = jiffies; call_rcu_time = jiffies;
} }
stutter_wait("rcu_torture_boost"); if (stutter_wait("rcu_torture_boost"))
sched_set_fifo_low(current);
if (torture_must_stop()) if (torture_must_stop())
goto checkwait; goto checkwait;
} }
@ -964,7 +966,8 @@ static int rcu_torture_boost(void *arg)
} }
/* Go do the stutter. */ /* Go do the stutter. */
checkwait: stutter_wait("rcu_torture_boost"); checkwait: if (stutter_wait("rcu_torture_boost"))
sched_set_fifo_low(current);
} while (!torture_must_stop()); } while (!torture_must_stop());
/* Clean up and exit. */ /* Clean up and exit. */
@ -987,6 +990,7 @@ rcu_torture_fqs(void *arg)
{ {
unsigned long fqs_resume_time; unsigned long fqs_resume_time;
int fqs_burst_remaining; int fqs_burst_remaining;
int oldnice = task_nice(current);
VERBOSE_TOROUT_STRING("rcu_torture_fqs task started"); VERBOSE_TOROUT_STRING("rcu_torture_fqs task started");
do { do {
@ -1002,7 +1006,8 @@ rcu_torture_fqs(void *arg)
udelay(fqs_holdoff); udelay(fqs_holdoff);
fqs_burst_remaining -= fqs_holdoff; fqs_burst_remaining -= fqs_holdoff;
} }
stutter_wait("rcu_torture_fqs"); if (stutter_wait("rcu_torture_fqs"))
sched_set_normal(current, oldnice);
} while (!torture_must_stop()); } while (!torture_must_stop());
torture_kthread_stopping("rcu_torture_fqs"); torture_kthread_stopping("rcu_torture_fqs");
return 0; return 0;
@ -1022,9 +1027,11 @@ rcu_torture_writer(void *arg)
bool gp_cond1 = gp_cond, gp_exp1 = gp_exp, gp_normal1 = gp_normal; bool gp_cond1 = gp_cond, gp_exp1 = gp_exp, gp_normal1 = gp_normal;
bool gp_sync1 = gp_sync; bool gp_sync1 = gp_sync;
int i; int i;
int oldnice = task_nice(current);
struct rcu_torture *rp; struct rcu_torture *rp;
struct rcu_torture *old_rp; struct rcu_torture *old_rp;
static DEFINE_TORTURE_RANDOM(rand); static DEFINE_TORTURE_RANDOM(rand);
bool stutter_waited;
int synctype[] = { RTWS_DEF_FREE, RTWS_EXP_SYNC, int synctype[] = { RTWS_DEF_FREE, RTWS_EXP_SYNC,
RTWS_COND_GET, RTWS_SYNC }; RTWS_COND_GET, RTWS_SYNC };
int nsynctypes = 0; int nsynctypes = 0;
@ -1143,7 +1150,8 @@ rcu_torture_writer(void *arg)
!rcu_gp_is_normal(); !rcu_gp_is_normal();
} }
rcu_torture_writer_state = RTWS_STUTTER; rcu_torture_writer_state = RTWS_STUTTER;
if (stutter_wait("rcu_torture_writer") && stutter_waited = stutter_wait("rcu_torture_writer");
if (stutter_waited &&
!READ_ONCE(rcu_fwd_cb_nodelay) && !READ_ONCE(rcu_fwd_cb_nodelay) &&
!cur_ops->slow_gps && !cur_ops->slow_gps &&
!torture_must_stop() && !torture_must_stop() &&
@ -1155,6 +1163,8 @@ rcu_torture_writer(void *arg)
rcu_ftrace_dump(DUMP_ALL); rcu_ftrace_dump(DUMP_ALL);
WARN(1, "%s: rtort_pipe_count: %d\n", __func__, rcu_tortures[i].rtort_pipe_count); WARN(1, "%s: rtort_pipe_count: %d\n", __func__, rcu_tortures[i].rtort_pipe_count);
} }
if (stutter_waited)
sched_set_normal(current, oldnice);
} while (!torture_must_stop()); } while (!torture_must_stop());
rcu_torture_current = NULL; // Let stats task know that we are done. rcu_torture_current = NULL; // Let stats task know that we are done.
/* Reset expediting back to unexpedited. */ /* Reset expediting back to unexpedited. */
@ -2103,6 +2113,7 @@ static struct notifier_block rcutorture_oom_nb = {
/* Carry out grace-period forward-progress testing. */ /* Carry out grace-period forward-progress testing. */
static int rcu_torture_fwd_prog(void *args) static int rcu_torture_fwd_prog(void *args)
{ {
int oldnice = task_nice(current);
struct rcu_fwd *rfp = args; struct rcu_fwd *rfp = args;
int tested = 0; int tested = 0;
int tested_tries = 0; int tested_tries = 0;
@ -2121,7 +2132,8 @@ static int rcu_torture_fwd_prog(void *args)
rcu_torture_fwd_prog_cr(rfp); rcu_torture_fwd_prog_cr(rfp);
/* Avoid slow periods, better to test when busy. */ /* Avoid slow periods, better to test when busy. */
stutter_wait("rcu_torture_fwd_prog"); if (stutter_wait("rcu_torture_fwd_prog"))
sched_set_normal(current, oldnice);
} while (!torture_must_stop()); } while (!torture_must_stop());
/* Short runs might not contain a valid forward-progress attempt. */ /* Short runs might not contain a valid forward-progress attempt. */
WARN_ON(!tested && tested_tries >= 5); WARN_ON(!tested && tested_tries >= 5);

Просмотреть файл

@ -604,19 +604,19 @@ bool stutter_wait(const char *title)
{ {
ktime_t delay; ktime_t delay;
unsigned int i = 0; unsigned int i = 0;
int oldnice;
bool ret = false; bool ret = false;
int spt; int spt;
cond_resched_tasks_rcu_qs(); cond_resched_tasks_rcu_qs();
spt = READ_ONCE(stutter_pause_test); spt = READ_ONCE(stutter_pause_test);
for (; spt; spt = READ_ONCE(stutter_pause_test)) { for (; spt; spt = READ_ONCE(stutter_pause_test)) {
ret = true; if (!ret) {
sched_set_normal(current, MAX_NICE);
ret = true;
}
if (spt == 1) { if (spt == 1) {
schedule_timeout_interruptible(1); schedule_timeout_interruptible(1);
} else if (spt == 2) { } else if (spt == 2) {
oldnice = task_nice(current);
set_user_nice(current, MAX_NICE);
while (READ_ONCE(stutter_pause_test)) { while (READ_ONCE(stutter_pause_test)) {
if (!(i++ & 0xffff)) { if (!(i++ & 0xffff)) {
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
@ -625,7 +625,6 @@ bool stutter_wait(const char *title)
} }
cond_resched(); cond_resched();
} }
set_user_nice(current, oldnice);
} else { } else {
schedule_timeout_interruptible(round_jiffies_relative(HZ)); schedule_timeout_interruptible(round_jiffies_relative(HZ));
} }