[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH v2] x86/cpu: Sync any remaining RCU callbacks after CPU up/down



During CPU down operation RCU callbacks are scheduled to finish
off some actions later as soon as CPU is fully dead (the same applies
to CPU up operation in case error path is taken). If in the same grace
period another CPU up operation is performed on the same CPU, RCU callback
will be called later on a CPU in a potentially wrong (already up again
instead of still being down) state leading to eventual state inconsistency
and/or crash.

In order to avoid it - flush RCU callbacks explicitly upon finishing off
the current operation.

Signed-off-by: Igor Druzhinin <igor.druzhinin@xxxxxxxxxx>
---
This got discovered trying to resume PV shim with multiple vCPUs on AMD
machine (where park_offline_cpus == 0). RCU callback responsible for
freeing percpu area on CPU offline got finally called after CPU went
online again as the guest performed regular vCPU offline/online operations
on resume.

Note: this patch requires RCU series from Juergen to be applied -
https://lists.xenproject.org/archives/html/xen-devel/2020-02/msg01221.html

v2: changed rcu_barrier() position, updated description
---
 xen/arch/x86/sysctl.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/xen/arch/x86/sysctl.c b/xen/arch/x86/sysctl.c
index 4a76f0f..dd5a24f 100644
--- a/xen/arch/x86/sysctl.c
+++ b/xen/arch/x86/sysctl.c
@@ -78,8 +78,11 @@ static void l3_cache_get(void *arg)
 long cpu_up_helper(void *data)
 {
     unsigned int cpu = (unsigned long)data;
-    int ret = cpu_up(cpu);
+    int ret;
 
+    /* Flush potentially scheduled RCU work from preceding CPU offline */
+    rcu_barrier();
+    ret = cpu_up(cpu);
     if ( ret == -EBUSY )
     {
         /* On EBUSY, flush RCU work and have one more go. */
@@ -104,7 +107,11 @@ long cpu_up_helper(void *data)
 long cpu_down_helper(void *data)
 {
     int cpu = (unsigned long)data;
-    int ret = cpu_down(cpu);
+    int ret;
+
+    /* Flush potentially scheduled RCU work from preceding CPU online */
+    rcu_barrier();
+    ret = cpu_down(cpu);
     if ( ret == -EBUSY )
     {
         /* On EBUSY, flush RCU work and have one more go. */
-- 
2.7.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.