summaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>2012-02-01 15:56:54 -0500
committerKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>2012-02-03 16:05:42 -0500
commit41bd956de3dfdc3a43708fe2e0c8096c69064a1e (patch)
tree1a2a31181c6c89dd754c46376fd82b3e0ba77e5e /arch/x86
parent5b02aa1e6e7cf7d3bbf8027dc7e05e0eb2f1e828 (diff)
downloadlinux-41bd956de3dfdc3a43708fe2e0c8096c69064a1e.tar.gz
linux-41bd956de3dfdc3a43708fe2e0c8096c69064a1e.tar.bz2
linux-41bd956de3dfdc3a43708fe2e0c8096c69064a1e.zip
xen/smp: Fix CPU online/offline bug triggering a BUG: scheduling while atomic.
When a user offlines a VCPU and then onlines it, we get: NMI watchdog disabled (cpu2): hardware events not enabled BUG: scheduling while atomic: swapper/2/0/0x00000002 Modules linked in: dm_multipath dm_mod xen_evtchn iscsi_boot_sysfs iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi scsi_mod libcrc32c crc32c radeon fbco ttm bitblit softcursor drm_kms_helper xen_blkfront xen_netfront xen_fbfront fb_sys_fops sysimgblt sysfillrect syscopyarea xen_kbdfront xenfs [last unloaded: Pid: 0, comm: swapper/2 Tainted: G O 3.2.0phase15.1-00003-gd6f7f5b-dirty #4 Call Trace: [<ffffffff81070571>] __schedule_bug+0x61/0x70 [<ffffffff8158eb78>] __schedule+0x798/0x850 [<ffffffff8158ed6a>] schedule+0x3a/0x50 [<ffffffff810349be>] cpu_idle+0xbe/0xe0 [<ffffffff81583599>] cpu_bringup_and_idle+0xe/0x10 The reason for this should be obvious from this call-chain: cpu_bringup_and_idle: \- cpu_bringup | \-[preempt_disable] | |- cpu_idle \- play_dead [assuming the user offlined the VCPU] | \ | +- (xen_play_dead) | \- HYPERVISOR_VCPU_off [so VCPU is dead, once user | | onlines it starts from here] | \- cpu_bringup [preempt_disable] | +- preempt_enable_no_reschedule() +- schedule() \- preempt_enable() So we have two preempt_disble() and one preempt_enable(). Calling preempt_enable() after the cpu_bringup() in the xen_play_dead fixes the imbalance. Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/xen/smp.c7
1 files changed, 7 insertions, 0 deletions
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c
index 041d4fe9dfe4..501d4e0244ba 100644
--- a/arch/x86/xen/smp.c
+++ b/arch/x86/xen/smp.c
@@ -409,6 +409,13 @@ static void __cpuinit xen_play_dead(void) /* used only with HOTPLUG_CPU */
play_dead_common();
HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL);
cpu_bringup();
+ /*
+ * Balance out the preempt calls - as we are running in cpu_idle
+ * loop which has been called at bootup from cpu_bringup_and_idle.
+ * The cpucpu_bringup_and_idle called cpu_bringup which made a
+ * preempt_disable() So this preempt_enable will balance it out.
+ */
+ preempt_enable();
}
#else /* !CONFIG_HOTPLUG_CPU */