aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeir Fraser <keir@xen.org>2011-01-14 14:19:55 +0000
committerKeir Fraser <keir@xen.org>2011-01-14 14:19:55 +0000
commit00e9c7bcb6397e85a8596cda619997982b6411e7 (patch)
tree883da4d5780df6f5278cf3b88b97f05a1798aba5
parent9d9af7dca878fb6f85ddf3cf3cb43df273f6b5a0 (diff)
downloadxen-00e9c7bcb6397e85a8596cda619997982b6411e7.tar.gz
xen-00e9c7bcb6397e85a8596cda619997982b6411e7.tar.bz2
xen-00e9c7bcb6397e85a8596cda619997982b6411e7.zip
x86: On CPU online/offline from dom0, try flushing RCU work on EBUSY.
Although the caller should react appropriately to EBUSY, if the error is due to pending RCU work then we can help things along by executing rcu_barrier() and then retrying. To this end, this changeset is an optimisation only. Signed-off-by: Keir Fraser <keir@xen.org>
-rw-r--r--xen/arch/x86/platform_hypercall.c31
-rw-r--r--xen/arch/x86/sysctl.c27
2 files changed, 40 insertions, 18 deletions
diff --git a/xen/arch/x86/platform_hypercall.c b/xen/arch/x86/platform_hypercall.c
index 812df80228..2733fc3b9e 100644
--- a/xen/arch/x86/platform_hypercall.c
+++ b/xen/arch/x86/platform_hypercall.c
@@ -55,11 +55,9 @@ static long cpu_frequency_change_helper(void *data)
return cpu_frequency_change(this_cpu(freq));
}
-static long cpu_down_helper(void *data)
-{
- int cpu = (unsigned long)data;
- return cpu_down(cpu);
-}
+/* from sysctl.c */
+long cpu_up_helper(void *data);
+long cpu_down_helper(void *data);
ret_t do_platform_op(XEN_GUEST_HANDLE(xen_platform_op_t) u_xenpf_op)
{
@@ -443,40 +441,43 @@ ret_t do_platform_op(XEN_GUEST_HANDLE(xen_platform_op_t) u_xenpf_op)
case XENPF_cpu_online:
{
- int cpu;
+ int cpu = op->u.cpu_ol.cpuid;
- cpu = op->u.cpu_ol.cpuid;
- if (!cpu_present(cpu))
+ if ( !cpu_present(cpu) )
{
ret = -EINVAL;
break;
}
- else if (cpu_online(cpu))
+
+ if ( cpu_online(cpu) )
{
ret = 0;
break;
}
- ret = cpu_up(cpu);
+ ret = continue_hypercall_on_cpu(
+ 0, cpu_up_helper, (void *)(unsigned long)cpu);
break;
}
case XENPF_cpu_offline:
{
- int cpu;
+ int cpu = op->u.cpu_ol.cpuid;
- cpu = op->u.cpu_ol.cpuid;
- if (!cpu_present(cpu))
+ if ( !cpu_present(cpu) )
{
ret = -EINVAL;
break;
- } else if (!cpu_online(cpu))
+ }
+
+ if ( !cpu_online(cpu) )
{
ret = 0;
break;
}
+
ret = continue_hypercall_on_cpu(
- 0, cpu_down_helper, (void *)(unsigned long)cpu);
+ 0, cpu_down_helper, (void *)(unsigned long)cpu);
break;
}
break;
diff --git a/xen/arch/x86/sysctl.c b/xen/arch/x86/sysctl.c
index 7bd20b9d0d..042bde4c46 100644
--- a/xen/arch/x86/sysctl.c
+++ b/xen/arch/x86/sysctl.c
@@ -30,10 +30,30 @@
#define get_xen_guest_handle(val, hnd) do { val = (hnd).p; } while (0)
-static long cpu_down_helper(void *data)
+long cpu_up_helper(void *data)
{
int cpu = (unsigned long)data;
- return cpu_down(cpu);
+ int ret = cpu_up(cpu);
+ if ( ret == -EBUSY )
+ {
+ /* On EBUSY, flush RCU work and have one more go. */
+ rcu_barrier();
+ ret = cpu_up(cpu);
+ }
+ return ret;
+}
+
+long cpu_down_helper(void *data)
+{
+ int cpu = (unsigned long)data;
+ int ret = cpu_down(cpu);
+ if ( ret == -EBUSY )
+ {
+ /* On EBUSY, flush RCU work and have one more go. */
+ rcu_barrier();
+ ret = cpu_down(cpu);
+ }
+ return ret;
}
extern int __node_distance(int a, int b);
@@ -170,7 +190,8 @@ long arch_do_sysctl(
switch ( sysctl->u.cpu_hotplug.op )
{
case XEN_SYSCTL_CPU_HOTPLUG_ONLINE:
- ret = cpu_up(cpu);
+ ret = continue_hypercall_on_cpu(
+ 0, cpu_up_helper, (void *)(unsigned long)cpu);
break;
case XEN_SYSCTL_CPU_HOTPLUG_OFFLINE:
ret = continue_hypercall_on_cpu(