From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1760243AbaJ3OIx (ORCPT ); Thu, 30 Oct 2014 10:08:53 -0400 Received: from mx1.redhat.com ([209.132.183.28]:40863 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1760163AbaJ3OIv (ORCPT ); Thu, 30 Oct 2014 10:08:51 -0400 From: =?UTF-8?q?Radim=20Kr=C4=8Dm=C3=A1=C5=99?= To: linux-kernel@vger.kernel.org Cc: kvm@vger.kernel.org, Paolo Bonzini , Gleb Natapov , Marcelo Tosatti Subject: [PATCH 1/3] KVM: x86: detect SPIV changes under APICv Date: Thu, 30 Oct 2014 15:06:45 +0100 Message-Id: <1414678007-9377-2-git-send-email-rkrcmar@redhat.com> In-Reply-To: <1414678007-9377-1-git-send-email-rkrcmar@redhat.com> References: <1414678007-9377-1-git-send-email-rkrcmar@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org APICv traps register writes, so we can't retrieve previous value. (A bit of blame on Intel.) This caused a migration bug: LAPIC is enabled, so our restore code correctly lowers apic_sw_enabled, but doesn't increase it after APICv is disabled, so we get below zero when freeing it; resulting in this trace: WARNING: at kernel/jump_label.c:81 __static_key_slow_dec+0xa6/0xb0() jump label: negative count! [] dump_stack+0x19/0x1b [] warn_slowpath_common+0x61/0x80 [] warn_slowpath_fmt+0x5c/0x80 [] __static_key_slow_dec+0xa6/0xb0 [] static_key_slow_dec_deferred+0x16/0x20 [] kvm_free_lapic+0x88/0xa0 [kvm] [] kvm_arch_vcpu_uninit+0x2e/0xe0 [kvm] [] kvm_vcpu_uninit+0x21/0x40 [kvm] [] vmx_free_vcpu+0x47/0x70 [kvm_intel] [] kvm_arch_vcpu_free+0x50/0x60 [kvm] [] kvm_arch_destroy_vm+0x102/0x260 [kvm] [] ? synchronize_srcu+0x1d/0x20 [] kvm_put_kvm+0xe1/0x1c0 [kvm] [] kvm_vcpu_release+0x18/0x20 [kvm] [] __fput+0x102/0x310 [] ____fput+0xe/0x10 [] task_work_run+0xb4/0xe0 [] do_exit+0x304/0xc60 [] ? _raw_spin_unlock_irq+0x2c/0x50 [] ? trace_hardirqs_on_caller+0xfd/0x1c0 [] do_group_exit+0x4c/0xc0 [] SyS_exit_group+0x14/0x20 [] system_call_fastpath+0x16/0x1b Signed-off-by: Radim Krčmář --- arch/x86/kvm/lapic.c | 10 ++++++---- arch/x86/kvm/lapic.h | 1 + 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index b8345dd..f538b14 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -201,11 +201,13 @@ out: static inline void apic_set_spiv(struct kvm_lapic *apic, u32 val) { - u32 prev = kvm_apic_get_reg(apic, APIC_SPIV); + bool enabled = val & APIC_SPIV_APIC_ENABLED; apic_set_reg(apic, APIC_SPIV, val); - if ((prev ^ val) & APIC_SPIV_APIC_ENABLED) { - if (val & APIC_SPIV_APIC_ENABLED) { + + if (enabled != apic->sw_enabled) { + apic->sw_enabled = enabled; + if (enabled) { static_key_slow_dec_deferred(&apic_sw_disabled); recalculate_apic_map(apic->vcpu->kvm); } else @@ -1320,7 +1322,7 @@ void kvm_free_lapic(struct kvm_vcpu *vcpu) if (!(vcpu->arch.apic_base & MSR_IA32_APICBASE_ENABLE)) static_key_slow_dec_deferred(&apic_hw_disabled); - if (!(kvm_apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_APIC_ENABLED)) + if (!apic->sw_enabled) static_key_slow_dec_deferred(&apic_sw_disabled); if (apic->regs) diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index 6a11845..5fcc3d3 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h @@ -33,6 +33,7 @@ struct kvm_lapic { * Note: Only one register, the TPR, is used by the microcode. */ void *regs; + bool sw_enabled; gpa_t vapic_addr; struct gfn_to_hva_cache vapic_cache; unsigned long pending_events; -- 2.1.0