]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
rcu/nocb: Handle concurrent nocb kthreads creation
authorNeeraj Upadhyay <quic_neeraju@quicinc.com>
Sat, 11 Dec 2021 17:01:39 +0000 (22:31 +0530)
committerDavid Woodhouse <dwmw@amazon.co.uk>
Thu, 16 Dec 2021 19:47:54 +0000 (19:47 +0000)
When multiple CPUs in the same nocb gp/cb group concurrently
come online, they might try to concurrently create the same
rcuog kthread. Fix this by using nocb gp CPU's spawn mutex to
provide mutual exclusion for the rcuog kthread creation code.

Signed-off-by: Neeraj Upadhyay <quic_neeraju@quicinc.com>
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
kernel/rcu/tree.h
kernel/rcu/tree_nocb.h

index 055e30b3e5e0dfdb57620f242e0a2b5bf716ba54..d7785f569a4e6ef5a9543c924d8e2cf3e1570d91 100644 (file)
@@ -210,6 +210,8 @@ struct rcu_data {
        int nocb_defer_wakeup;          /* Defer wakeup of nocb_kthread. */
        struct timer_list nocb_timer;   /* Enforce finite deferral. */
        unsigned long nocb_gp_adv_time; /* Last call_rcu() CB adv (jiffies). */
+       struct mutex nocb_gp_kthread_mutex; /* Exclusion for nocb gp kthread */
+                                           /* spawning */
 
        /* The following fields are used by call_rcu, hence own cacheline. */
        raw_spinlock_t nocb_bypass_lock ____cacheline_internodealigned_in_smp;
index 368ef7b9af4fee6bfa4492a4e7960d1a0d1b3f5c..1ad54b2336e6a71c1227b45b855ef2e9ef35986d 100644 (file)
@@ -1171,6 +1171,7 @@ static void __init rcu_boot_init_nocb_percpu_data(struct rcu_data *rdp)
        raw_spin_lock_init(&rdp->nocb_gp_lock);
        timer_setup(&rdp->nocb_timer, do_nocb_deferred_wakeup_timer, 0);
        rcu_cblist_init(&rdp->nocb_bypass);
+       mutex_init(&rdp->nocb_gp_kthread_mutex);
 }
 
 /*
@@ -1193,13 +1194,17 @@ static void rcu_spawn_one_nocb_kthread(int cpu)
 
        /* If we didn't spawn the GP kthread first, reorganize! */
        rdp_gp = rdp->nocb_gp_rdp;
+       mutex_lock(&rdp_gp->nocb_gp_kthread_mutex);
        if (!rdp_gp->nocb_gp_kthread) {
                t = kthread_run(rcu_nocb_gp_kthread, rdp_gp,
                                "rcuog/%d", rdp_gp->cpu);
-               if (WARN_ONCE(IS_ERR(t), "%s: Could not start rcuo GP kthread, OOM is now expected behavior\n", __func__))
+               if (WARN_ONCE(IS_ERR(t), "%s: Could not start rcuo GP kthread, OOM is now expected behavior\n", __func__)) {
+                       mutex_unlock(&rdp_gp->nocb_gp_kthread_mutex);
                        return;
+               }
                WRITE_ONCE(rdp_gp->nocb_gp_kthread, t);
        }
+       mutex_unlock(&rdp_gp->nocb_gp_kthread_mutex);
 
        /* Spawn the kthread for this CPU. */
        t = kthread_run(rcu_nocb_cb_kthread, rdp,