summaryrefslogtreecommitdiff
path: root/arch/arm64/kvm/reset.c
diff options
context:
space:
mode:
authorOliver Upton <oliver.upton@linux.dev>2023-03-27 19:47:44 +0300
committerMarc Zyngier <maz@kernel.org>2023-03-29 16:08:31 +0300
commit0acc7239c20a8401b8968c2adace8f7c9b0295ae (patch)
tree0464287907d5ebde98be94c8b61a966d6e211075 /arch/arm64/kvm/reset.c
parent197b6b60ae7bc51dd0814953c562833143b292aa (diff)
downloadlinux-0acc7239c20a8401b8968c2adace8f7c9b0295ae.tar.xz
KVM: arm64: Avoid vcpu->mutex v. kvm->lock inversion in CPU_ON
KVM/arm64 had the lock ordering backwards on vcpu->mutex and kvm->lock from the very beginning. One such example is the way vCPU resets are handled: the kvm->lock is acquired while handling a guest CPU_ON PSCI call. Add a dedicated lock to serialize writes to kvm_vcpu_arch::{mp_state, reset_state}. Promote all accessors of mp_state to {READ,WRITE}_ONCE() as readers do not acquire the mp_state_lock. While at it, plug yet another race by taking the mp_state_lock in the KVM_SET_MP_STATE ioctl handler. As changes to MP state are now guarded with a dedicated lock, drop the kvm->lock acquisition from the PSCI CPU_ON path. Similarly, move the reader of reset_state outside of the kvm->lock and instead protect it with the mp_state_lock. Note that writes to reset_state::reset have been demoted to regular stores as both readers and writers acquire the mp_state_lock. While the kvm->lock inversion still exists in kvm_reset_vcpu(), at least now PSCI CPU_ON no longer depends on it for serializing vCPU reset. Cc: stable@vger.kernel.org Tested-by: Jeremy Linton <jeremy.linton@arm.com> Signed-off-by: Oliver Upton <oliver.upton@linux.dev> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20230327164747.2466958-2-oliver.upton@linux.dev
Diffstat (limited to 'arch/arm64/kvm/reset.c')
-rw-r--r--arch/arm64/kvm/reset.c9
1 files changed, 5 insertions, 4 deletions
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index 49a3257dec46..9e023546bde0 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -264,15 +264,16 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
mutex_lock(&vcpu->kvm->lock);
ret = kvm_set_vm_width(vcpu);
- if (!ret) {
- reset_state = vcpu->arch.reset_state;
- WRITE_ONCE(vcpu->arch.reset_state.reset, false);
- }
mutex_unlock(&vcpu->kvm->lock);
if (ret)
return ret;
+ spin_lock(&vcpu->arch.mp_state_lock);
+ reset_state = vcpu->arch.reset_state;
+ vcpu->arch.reset_state.reset = false;
+ spin_unlock(&vcpu->arch.mp_state_lock);
+
/* Reset PMU outside of the non-preemptible section */
kvm_pmu_vcpu_reset(vcpu);