Merge tag 'usb-6.8-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
[linux-block.git] / kernel / rcu / tree.c
index 1ae8517778066284be5c7c15111b09a0f726f164..b2bccfd37c383d04692fb6a7a72eb71a1f62798b 100644 (file)
@@ -1013,6 +1013,38 @@ static bool rcu_future_gp_cleanup(struct rcu_node *rnp)
        return needmore;
 }
 
+static void swake_up_one_online_ipi(void *arg)
+{
+       struct swait_queue_head *wqh = arg;
+
+       swake_up_one(wqh);
+}
+
+static void swake_up_one_online(struct swait_queue_head *wqh)
+{
+       int cpu = get_cpu();
+
+       /*
+        * If called from rcutree_report_cpu_starting(), wake up
+        * is dangerous that late in the CPU-down hotplug process. The
+        * scheduler might queue an ignored hrtimer. Defer the wake up
+        * to an online CPU instead.
+        */
+       if (unlikely(cpu_is_offline(cpu))) {
+               int target;
+
+               target = cpumask_any_and(housekeeping_cpumask(HK_TYPE_RCU),
+                                        cpu_online_mask);
+
+               smp_call_function_single(target, swake_up_one_online_ipi,
+                                        wqh, 0);
+               put_cpu();
+       } else {
+               put_cpu();
+               swake_up_one(wqh);
+       }
+}
+
 /*
  * Awaken the grace-period kthread.  Don't do a self-awaken (unless in an
  * interrupt or softirq handler, in which case we just might immediately
@@ -1037,7 +1069,7 @@ static void rcu_gp_kthread_wake(void)
                return;
        WRITE_ONCE(rcu_state.gp_wake_time, jiffies);
        WRITE_ONCE(rcu_state.gp_wake_seq, READ_ONCE(rcu_state.gp_seq));
-       swake_up_one(&rcu_state.gp_wq);
+       swake_up_one_online(&rcu_state.gp_wq);
 }
 
 /*