rcutorture: Make stutter_wait() caller restore priority
authorPaul E. McKenney <paulmck@kernel.org>
Tue, 22 Sep 2020 23:42:42 +0000 (16:42 -0700)
committerPaul E. McKenney <paulmck@kernel.org>
Sat, 7 Nov 2020 01:13:54 +0000 (17:13 -0800)
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>
kernel/rcu/rcutorture.c
kernel/torture.c

index db3767110c6089e3a6a4691faebac86a9e50f71b..4391d2fab5de54d8c9e2fa4f38ab2d8971f7fb37 100644 (file)
@@ -912,7 +912,8 @@ static int rcu_torture_boost(void *arg)
                oldstarttime = boost_starttime;
                while (time_before(jiffies, oldstarttime)) {
                        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())
                                goto checkwait;
                }
@@ -932,7 +933,8 @@ static int rcu_torture_boost(void *arg)
                                                                 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())
                                goto checkwait;
                }
@@ -964,7 +966,8 @@ static int rcu_torture_boost(void *arg)
                }
 
                /* 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());
 
        /* Clean up and exit. */
@@ -987,6 +990,7 @@ rcu_torture_fqs(void *arg)
 {
        unsigned long fqs_resume_time;
        int fqs_burst_remaining;
+       int oldnice = task_nice(current);
 
        VERBOSE_TOROUT_STRING("rcu_torture_fqs task started");
        do {
@@ -1002,7 +1006,8 @@ rcu_torture_fqs(void *arg)
                        udelay(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());
        torture_kthread_stopping("rcu_torture_fqs");
        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_sync1 = gp_sync;
        int i;
+       int oldnice = task_nice(current);
        struct rcu_torture *rp;
        struct rcu_torture *old_rp;
        static DEFINE_TORTURE_RANDOM(rand);
+       bool stutter_waited;
        int synctype[] = { RTWS_DEF_FREE, RTWS_EXP_SYNC,
                           RTWS_COND_GET, RTWS_SYNC };
        int nsynctypes = 0;
@@ -1143,7 +1150,8 @@ rcu_torture_writer(void *arg)
                                       !rcu_gp_is_normal();
                }
                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) &&
                    !cur_ops->slow_gps &&
                    !torture_must_stop() &&
@@ -1155,6 +1163,8 @@ rcu_torture_writer(void *arg)
                                        rcu_ftrace_dump(DUMP_ALL);
                                        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());
        rcu_torture_current = NULL;  // Let stats task know that we are done.
        /* Reset expediting back to unexpedited. */
@@ -2103,6 +2113,7 @@ static struct notifier_block rcutorture_oom_nb = {
 /* Carry out grace-period forward-progress testing. */
 static int rcu_torture_fwd_prog(void *args)
 {
+       int oldnice = task_nice(current);
        struct rcu_fwd *rfp = args;
        int tested = 0;
        int tested_tries = 0;
@@ -2121,7 +2132,8 @@ static int rcu_torture_fwd_prog(void *args)
                        rcu_torture_fwd_prog_cr(rfp);
 
                /* 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());
        /* Short runs might not contain a valid forward-progress attempt. */
        WARN_ON(!tested && tested_tries >= 5);
index 56ff02bf444ff21893721287b9f0f9537cfab0a5..8562ac18d2eb531a6ade87793d086e377a622b75 100644 (file)
@@ -604,19 +604,19 @@ bool stutter_wait(const char *title)
 {
        ktime_t delay;
        unsigned int i = 0;
-       int oldnice;
        bool ret = false;
        int spt;
 
        cond_resched_tasks_rcu_qs();
        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) {
                        schedule_timeout_interruptible(1);
                } else if (spt == 2) {
-                       oldnice = task_nice(current);
-                       set_user_nice(current, MAX_NICE);
                        while (READ_ONCE(stutter_pause_test)) {
                                if (!(i++ & 0xffff)) {
                                        set_current_state(TASK_INTERRUPTIBLE);
@@ -625,7 +625,6 @@ bool stutter_wait(const char *title)
                                }
                                cond_resched();
                        }
-                       set_user_nice(current, oldnice);
                } else {
                        schedule_timeout_interruptible(round_jiffies_relative(HZ));
                }