[tip: core/rcu] rcu/nocb: Don't deoffload an offline CPU with pending work

From: tip-bot2 for Frederic Weisbecker
Date: Fri Feb 12 2021 - 07:57:55 EST


The following commit has been merged into the core/rcu branch of tip:

Commit-ID: ef005345e6e49859e225f549c88c985e79477bb9
Gitweb: https://git.kernel.org/tip/ef005345e6e49859e225f549c88c985e79477bb9
Author: Frederic Weisbecker <frederic@xxxxxxxxxx>
AuthorDate: Fri, 13 Nov 2020 13:13:20 +01:00
Committer: Paul E. McKenney <paulmck@xxxxxxxxxx>
CommitterDate: Wed, 06 Jan 2021 16:24:19 -08:00

rcu/nocb: Don't deoffload an offline CPU with pending work

Offloaded CPUs do not migrate their callbacks, instead relying on
their rcuo kthread to invoke them. But if the CPU is offline, it
will be running neither its RCU_SOFTIRQ handler nor its rcuc kthread.
This means that de-offloading an offline CPU that still has pending
callbacks will strand those callbacks. This commit therefore refuses
to toggle offline CPUs having pending callbacks.

Cc: Josh Triplett <josh@xxxxxxxxxxxxxxxx>
Cc: Steven Rostedt <rostedt@xxxxxxxxxxx>
Cc: Mathieu Desnoyers <mathieu.desnoyers@xxxxxxxxxxxx>
Cc: Lai Jiangshan <jiangshanlai@xxxxxxxxx>
Cc: Joel Fernandes <joel@xxxxxxxxxxxxxxxxx>
Cc: Neeraj Upadhyay <neeraju@xxxxxxxxxxxxxx>
Cc: Thomas Gleixner <tglx@xxxxxxxxxxxxx>
Suggested-by: Paul E. McKenney <paulmck@xxxxxxxxxx>
Tested-by: Boqun Feng <boqun.feng@xxxxxxxxx>
Signed-off-by: Frederic Weisbecker <frederic@xxxxxxxxxx>
Signed-off-by: Paul E. McKenney <paulmck@xxxxxxxxxx>
---
kernel/rcu/tree_plugin.h | 9 +++++++++
1 file changed, 9 insertions(+)

diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h
index 1b870d0..b70cc91 100644
--- a/kernel/rcu/tree_plugin.h
+++ b/kernel/rcu/tree_plugin.h
@@ -2227,6 +2227,15 @@ static int __rcu_nocb_rdp_deoffload(struct rcu_data *rdp)
printk("De-offloading %d\n", rdp->cpu);

rcu_nocb_lock_irqsave(rdp, flags);
+ /*
+ * If there are still pending work offloaded, the offline
+ * CPU won't help much handling them.
+ */
+ if (cpu_is_offline(rdp->cpu) && !rcu_segcblist_empty(&rdp->cblist)) {
+ rcu_nocb_unlock_irqrestore(rdp, flags);
+ return -EBUSY;
+ }
+
rcu_segcblist_offload(cblist, false);

if (rdp->nocb_cb_sleep) {