KVM support may be compiled as dynamic module, which triggers the following splat on modprobe (under CONFIG_DEBUG_PREEMPT): KVM: vmx: using Hyper-V Enlightened VMCS BUG: using smp_processor_id() in preemptible [00000000] code: modprobe/466 caller is debug_smp_processor_id+0x17/0x19 CPU: 0 PID: 466 Comm: modprobe Kdump: loaded Not tainted 4.19.43 #1 Hardware name: Microsoft Corporation Virtual Machine/Virtual Machine, BIOS 090007 06/02/2017 Call Trace: dump_stack+0x61/0x7e check_preemption_disabled+0xd4/0xe6 debug_smp_processor_id+0x17/0x19 set_hv_tscchange_cb+0x1b/0x89 kvm_arch_init+0x14a/0x163 [kvm] kvm_init+0x30/0x259 [kvm] vmx_init+0xed/0x3db [kvm_intel] do_one_initcall+0x89/0x1bc do_init_module+0x5f/0x207 load_module+0x1b34/0x209b __ia32_sys_init_module+0x17/0x19 do_fast_syscall_32+0x121/0x1fa entry_SYSENTER_compat+0x7f/0x91 Hold cpus_read_lock() so that MSR will be written for an online CPU, even if set_hv_tscchange_cb() gets being preempted. While at it, cleanup smp_processor_id()'s in hv_cpu_init() and add a lockdep assert into hv_cpu_die(). Fixes: 93286261de1b4 ("x86/hyperv: Reenlightenment notifications support") Cc: Andy Lutomirski <luto@xxxxxxxxxx> Cc: Borislav Petkov <bp@xxxxxxxxx> Cc: Cathy Avery <cavery@xxxxxxxxxx> Cc: Haiyang Zhang <haiyangz@xxxxxxxxxxxxx> Cc: "H. Peter Anvin" <hpa@xxxxxxxxx> Cc: Ingo Molnar <mingo@xxxxxxxxxx> Cc: "K. Y. Srinivasan" <kys@xxxxxxxxxxxxx> Cc: "Michael Kelley (EOSG)" <Michael.H.Kelley@xxxxxxxxxxxxx> Cc: Mohammed Gamal <mmorsy@xxxxxxxxxx> Cc: Paolo Bonzini <pbonzini@xxxxxxxxxx> Cc: Peter Zijlstra <peterz@xxxxxxxxxxxxx> Cc: Radim Krčmář <rkrcmar@xxxxxxxxxx> Cc: Roman Kagan <rkagan@xxxxxxxxxxxxx> Cc: Sasha Levin <sashal@xxxxxxxxxx> Cc: Stephen Hemminger <sthemmin@xxxxxxxxxxxxx> Cc: Thomas Gleixner <tglx@xxxxxxxxxxxxx> Cc: Vitaly Kuznetsov <vkuznets@xxxxxxxxxx> Cc: devel@xxxxxxxxxxxxxxxxxxxxxx Cc: kvm@xxxxxxxxxxxxxxx Cc: linux-hyperv@xxxxxxxxxxxxxxx Cc: x86@xxxxxxxxxx Reported-by: Prasanna Panchamukhi <panchamukhi@xxxxxxxxxx> Signed-off-by: Dmitry Safonov <dima@xxxxxxxxxx> --- v1 link: lkml.kernel.org/r/20190611212003.26382-1-dima@xxxxxxxxxx NOTE that I hadn't a chance to test v2 on hyperv machine so far, ONLY BUILD TESTED. (In hope that the patch still makes sense and Kbuild bot will report any issue). arch/x86/hyperv/hv_init.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/arch/x86/hyperv/hv_init.c b/arch/x86/hyperv/hv_init.c index 1608050e9df9..ec7fd7d6c125 100644 --- a/arch/x86/hyperv/hv_init.c +++ b/arch/x86/hyperv/hv_init.c @@ -20,6 +20,7 @@ #include <linux/clockchips.h> #include <linux/hyperv.h> #include <linux/slab.h> +#include <linux/cpu.h> #include <linux/cpuhotplug.h> #ifdef CONFIG_HYPERV_TSCPAGE @@ -91,7 +92,7 @@ EXPORT_SYMBOL_GPL(hv_max_vp_index); static int hv_cpu_init(unsigned int cpu) { u64 msr_vp_index; - struct hv_vp_assist_page **hvp = &hv_vp_assist_page[smp_processor_id()]; + struct hv_vp_assist_page **hvp = &hv_vp_assist_page[cpu]; void **input_arg; struct page *pg; @@ -103,7 +104,7 @@ static int hv_cpu_init(unsigned int cpu) hv_get_vp_index(msr_vp_index); - hv_vp_index[smp_processor_id()] = msr_vp_index; + hv_vp_index[cpu] = msr_vp_index; if (msr_vp_index > hv_max_vp_index) hv_max_vp_index = msr_vp_index; @@ -182,7 +183,6 @@ void set_hv_tscchange_cb(void (*cb)(void)) struct hv_reenlightenment_control re_ctrl = { .vector = HYPERV_REENLIGHTENMENT_VECTOR, .enabled = 1, - .target_vp = hv_vp_index[smp_processor_id()] }; struct hv_tsc_emulation_control emu_ctrl = {.enabled = 1}; @@ -196,7 +196,16 @@ void set_hv_tscchange_cb(void (*cb)(void)) /* Make sure callback is registered before we write to MSRs */ wmb(); + /* + * As reenlightenment vector is global, there is no difference which + * CPU will register MSR, though it should be an online CPU. + * hv_cpu_die() callback guarantees that on CPU teardown + * another CPU will re-register MSR back. + */ + cpus_read_lock(); + re_ctrl.target_vp = hv_vp_index[raw_smp_processor_id()]; wrmsrl(HV_X64_MSR_REENLIGHTENMENT_CONTROL, *((u64 *)&re_ctrl)); + cpus_read_unlock(); wrmsrl(HV_X64_MSR_TSC_EMULATION_CONTROL, *((u64 *)&emu_ctrl)); } EXPORT_SYMBOL_GPL(set_hv_tscchange_cb); @@ -239,6 +248,7 @@ static int hv_cpu_die(unsigned int cpu) rdmsrl(HV_X64_MSR_REENLIGHTENMENT_CONTROL, *((u64 *)&re_ctrl)); if (re_ctrl.target_vp == hv_vp_index[cpu]) { + lockdep_assert_cpus_held(); /* Reassign to some other online CPU */ new_cpu = cpumask_any_but(cpu_online_mask, cpu); -- 2.22.0