rcutorture: Properly synchronize with OOM notifier
authorPaul E. McKenney <paulmck@kernel.org>
Mon, 20 Jul 2020 15:34:07 +0000 (08:34 -0700)
committerPaul E. McKenney <paulmck@kernel.org>
Tue, 25 Aug 2020 01:45:34 +0000 (18:45 -0700)
The current rcutorture forward-progress code assumes that it is the
only cause of out-of-memory (OOM) events.  For script-based rcutorture
testing, this assumption is in fact correct.  However, testing based
on modprobe/rmmod might well encounter external OOM events, which could
happen at any time.

This commit therefore properly synchronizes the interaction between
rcutorture's forward-progress testing and its OOM notifier by adding a
global mutex.

Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
kernel/rcu/rcutorture.c

index 7942be4..2b3f04e 100644 (file)
@@ -1796,6 +1796,7 @@ struct rcu_fwd {
        unsigned long rcu_launder_gp_seq_start;
 };
 
+static DEFINE_MUTEX(rcu_fwd_mutex);
 static struct rcu_fwd *rcu_fwds;
 static bool rcu_fwd_emergency_stop;
 
@@ -2062,8 +2063,14 @@ static void rcu_torture_fwd_prog_cr(struct rcu_fwd *rfp)
 static int rcutorture_oom_notify(struct notifier_block *self,
                                 unsigned long notused, void *nfreed)
 {
-       struct rcu_fwd *rfp = rcu_fwds;
+       struct rcu_fwd *rfp;
 
+       mutex_lock(&rcu_fwd_mutex);
+       rfp = rcu_fwds;
+       if (!rfp) {
+               mutex_unlock(&rcu_fwd_mutex);
+               return NOTIFY_OK;
+       }
        WARN(1, "%s invoked upon OOM during forward-progress testing.\n",
             __func__);
        rcu_torture_fwd_cb_hist(rfp);
@@ -2081,6 +2088,7 @@ static int rcutorture_oom_notify(struct notifier_block *self,
        smp_mb(); /* Frees before return to avoid redoing OOM. */
        (*(unsigned long *)nfreed)++; /* Forward progress CBs freed! */
        pr_info("%s returning after OOM processing.\n", __func__);
+       mutex_unlock(&rcu_fwd_mutex);
        return NOTIFY_OK;
 }
 
@@ -2148,7 +2156,9 @@ static int __init rcu_torture_fwd_prog_init(void)
                return -ENOMEM;
        spin_lock_init(&rfp->rcu_fwd_lock);
        rfp->rcu_fwd_cb_tail = &rfp->rcu_fwd_cb_head;
+       mutex_lock(&rcu_fwd_mutex);
        rcu_fwds = rfp;
+       mutex_unlock(&rcu_fwd_mutex);
        return torture_create_kthread(rcu_torture_fwd_prog, rfp, fwd_prog_task);
 }
 
@@ -2158,7 +2168,9 @@ static void rcu_torture_fwd_prog_cleanup(void)
 
        torture_stop_kthread(rcu_torture_fwd_prog, fwd_prog_task);
        rfp = rcu_fwds;
+       mutex_lock(&rcu_fwd_mutex);
        rcu_fwds = NULL;
+       mutex_unlock(&rcu_fwd_mutex);
        kfree(rfp);
 }