Skip to content

Commit b2b656c

Browse files
ouptongregkh
authored andcommitted
KVM: arm64: Avoid lock inversion when setting the VM register width
commit c43120a upstream. kvm->lock must be taken outside of the vcpu->mutex. Of course, the locking documentation for KVM makes this abundantly clear. Nonetheless, the locking order in KVM/arm64 has been wrong for quite a while; we acquire the kvm->lock while holding the vcpu->mutex all over the shop. All was seemingly fine until commit 42a9000 ("KVM: Ensure lockdep knows about kvm->lock vs. vcpu->mutex ordering rule") caught us with our pants down, leading to lockdep barfing: ====================================================== WARNING: possible circular locking dependency detected 6.2.0-rc7+ #19 Not tainted ------------------------------------------------------ qemu-system-aar/859 is trying to acquire lock: ffff5aa69269eba0 (&host_kvm->lock){+.+.}-{3:3}, at: kvm_reset_vcpu+0x34/0x274 but task is already holding lock: ffff5aa68768c0b8 (&vcpu->mutex){+.+.}-{3:3}, at: kvm_vcpu_ioctl+0x8c/0xba0 which lock already depends on the new lock. Add a dedicated lock to serialize writes to VM-scoped configuration from the context of a vCPU. Protect the register width flags with the new lock, thus avoiding the need to grab the kvm->lock while holding vcpu->mutex in kvm_reset_vcpu(). Cc: [email protected] Reported-by: Jeremy Linton <[email protected]> Link: https://lore.kernel.org/kvmarm/[email protected]/ Tested-by: Jeremy Linton <[email protected]> Signed-off-by: Oliver Upton <[email protected]> Signed-off-by: Marc Zyngier <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 0fe6284 commit b2b656c

File tree

3 files changed

+24
-3
lines changed

3 files changed

+24
-3
lines changed

Diff for: arch/arm64/include/asm/kvm_host.h

+3
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,9 @@ struct kvm_arch {
191191
/* Mandated version of PSCI */
192192
u32 psci_version;
193193

194+
/* Protects VM-scoped configuration data */
195+
struct mutex config_lock;
196+
194197
/*
195198
* If we encounter a data abort without valid instruction syndrome
196199
* information, report this to user space. User space can (and

Diff for: arch/arm64/kvm/arm.c

+18
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,16 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
138138
{
139139
int ret;
140140

141+
mutex_init(&kvm->arch.config_lock);
142+
143+
#ifdef CONFIG_LOCKDEP
144+
/* Clue in lockdep that the config_lock must be taken inside kvm->lock */
145+
mutex_lock(&kvm->lock);
146+
mutex_lock(&kvm->arch.config_lock);
147+
mutex_unlock(&kvm->arch.config_lock);
148+
mutex_unlock(&kvm->lock);
149+
#endif
150+
141151
ret = kvm_share_hyp(kvm, kvm + 1);
142152
if (ret)
143153
return ret;
@@ -338,6 +348,14 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
338348

339349
spin_lock_init(&vcpu->arch.mp_state_lock);
340350

351+
#ifdef CONFIG_LOCKDEP
352+
/* Inform lockdep that the config_lock is acquired after vcpu->mutex */
353+
mutex_lock(&vcpu->mutex);
354+
mutex_lock(&vcpu->kvm->arch.config_lock);
355+
mutex_unlock(&vcpu->kvm->arch.config_lock);
356+
mutex_unlock(&vcpu->mutex);
357+
#endif
358+
341359
/* Force users to call KVM_ARM_VCPU_INIT */
342360
vcpu->arch.target = -1;
343361
bitmap_zero(vcpu->arch.features, KVM_VCPU_MAX_FEATURES);

Diff for: arch/arm64/kvm/reset.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ static int kvm_set_vm_width(struct kvm_vcpu *vcpu)
200200

201201
is32bit = vcpu_has_feature(vcpu, KVM_ARM_VCPU_EL1_32BIT);
202202

203-
lockdep_assert_held(&kvm->lock);
203+
lockdep_assert_held(&kvm->arch.config_lock);
204204

205205
if (test_bit(KVM_ARCH_FLAG_REG_WIDTH_CONFIGURED, &kvm->arch.flags)) {
206206
/*
@@ -253,9 +253,9 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
253253
bool loaded;
254254
u32 pstate;
255255

256-
mutex_lock(&vcpu->kvm->lock);
256+
mutex_lock(&vcpu->kvm->arch.config_lock);
257257
ret = kvm_set_vm_width(vcpu);
258-
mutex_unlock(&vcpu->kvm->lock);
258+
mutex_unlock(&vcpu->kvm->arch.config_lock);
259259

260260
if (ret)
261261
return ret;

0 commit comments

Comments
 (0)