Skip to content

Commit 2121cad

Browse files
yong-xuanavpatel
authored andcommitted
RISCV: KVM: Introduce mp_state_lock to avoid lock inversion
Documentation/virt/kvm/locking.rst advises that kvm->lock should be acquired outside vcpu->mutex and kvm->srcu. However, when KVM/RISC-V handling SBI_EXT_HSM_HART_START, the lock ordering is vcpu->mutex, kvm->srcu then kvm->lock. Although the lockdep checking no longer complains about this after commit f0f4475 ("rcu: Annotate SRCU's update-side lockdep dependencies"), it's necessary to replace kvm->lock with a new dedicated lock to ensure only one hart can execute the SBI_EXT_HSM_HART_START call for the target hart simultaneously. Additionally, this patch also rename "power_off" to "mp_state" with two possible values. The vcpu->mp_state_lock also protects the access of vcpu->mp_state. Signed-off-by: Yong-Xuan Wang <yongxuan.wang@sifive.com> Reviewed-by: Anup Patel <anup@brainfault.org> Link: https://lore.kernel.org/r/20240417074528.16506-2-yongxuan.wang@sifive.com Signed-off-by: Anup Patel <anup@brainfault.org>
1 parent f1c48c1 commit 2121cad

File tree

4 files changed

+73
-29
lines changed

4 files changed

+73
-29
lines changed

arch/riscv/include/asm/kvm_host.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,8 +264,9 @@ struct kvm_vcpu_arch {
264264
/* Cache pages needed to program page tables with spinlock held */
265265
struct kvm_mmu_memory_cache mmu_page_cache;
266266

267-
/* VCPU power-off state */
268-
bool power_off;
267+
/* VCPU power state */
268+
struct kvm_mp_state mp_state;
269+
spinlock_t mp_state_lock;
269270

270271
/* Don't run the VCPU (blocked) */
271272
bool pause;
@@ -386,8 +387,11 @@ int kvm_riscv_vcpu_unset_interrupt(struct kvm_vcpu *vcpu, unsigned int irq);
386387
void kvm_riscv_vcpu_flush_interrupts(struct kvm_vcpu *vcpu);
387388
void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu);
388389
bool kvm_riscv_vcpu_has_interrupts(struct kvm_vcpu *vcpu, u64 mask);
390+
void __kvm_riscv_vcpu_power_off(struct kvm_vcpu *vcpu);
389391
void kvm_riscv_vcpu_power_off(struct kvm_vcpu *vcpu);
392+
void __kvm_riscv_vcpu_power_on(struct kvm_vcpu *vcpu);
390393
void kvm_riscv_vcpu_power_on(struct kvm_vcpu *vcpu);
394+
bool kvm_riscv_vcpu_stopped(struct kvm_vcpu *vcpu);
391395

392396
void kvm_riscv_vcpu_sbi_sta_reset(struct kvm_vcpu *vcpu);
393397
void kvm_riscv_vcpu_record_steal_time(struct kvm_vcpu *vcpu);

arch/riscv/kvm/vcpu.c

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
102102
struct kvm_cpu_context *cntx;
103103
struct kvm_vcpu_csr *reset_csr = &vcpu->arch.guest_reset_csr;
104104

105+
spin_lock_init(&vcpu->arch.mp_state_lock);
106+
105107
/* Mark this VCPU never ran */
106108
vcpu->arch.ran_atleast_once = false;
107109
vcpu->arch.mmu_page_cache.gfp_zero = __GFP_ZERO;
@@ -201,7 +203,7 @@ void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu)
201203
int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
202204
{
203205
return (kvm_riscv_vcpu_has_interrupts(vcpu, -1UL) &&
204-
!vcpu->arch.power_off && !vcpu->arch.pause);
206+
!kvm_riscv_vcpu_stopped(vcpu) && !vcpu->arch.pause);
205207
}
206208

207209
int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
@@ -429,26 +431,42 @@ bool kvm_riscv_vcpu_has_interrupts(struct kvm_vcpu *vcpu, u64 mask)
429431
return kvm_riscv_vcpu_aia_has_interrupts(vcpu, mask);
430432
}
431433

432-
void kvm_riscv_vcpu_power_off(struct kvm_vcpu *vcpu)
434+
void __kvm_riscv_vcpu_power_off(struct kvm_vcpu *vcpu)
433435
{
434-
vcpu->arch.power_off = true;
436+
WRITE_ONCE(vcpu->arch.mp_state.mp_state, KVM_MP_STATE_STOPPED);
435437
kvm_make_request(KVM_REQ_SLEEP, vcpu);
436438
kvm_vcpu_kick(vcpu);
437439
}
438440

439-
void kvm_riscv_vcpu_power_on(struct kvm_vcpu *vcpu)
441+
void kvm_riscv_vcpu_power_off(struct kvm_vcpu *vcpu)
440442
{
441-
vcpu->arch.power_off = false;
443+
spin_lock(&vcpu->arch.mp_state_lock);
444+
__kvm_riscv_vcpu_power_off(vcpu);
445+
spin_unlock(&vcpu->arch.mp_state_lock);
446+
}
447+
448+
void __kvm_riscv_vcpu_power_on(struct kvm_vcpu *vcpu)
449+
{
450+
WRITE_ONCE(vcpu->arch.mp_state.mp_state, KVM_MP_STATE_RUNNABLE);
442451
kvm_vcpu_wake_up(vcpu);
443452
}
444453

454+
void kvm_riscv_vcpu_power_on(struct kvm_vcpu *vcpu)
455+
{
456+
spin_lock(&vcpu->arch.mp_state_lock);
457+
__kvm_riscv_vcpu_power_on(vcpu);
458+
spin_unlock(&vcpu->arch.mp_state_lock);
459+
}
460+
461+
bool kvm_riscv_vcpu_stopped(struct kvm_vcpu *vcpu)
462+
{
463+
return READ_ONCE(vcpu->arch.mp_state.mp_state) == KVM_MP_STATE_STOPPED;
464+
}
465+
445466
int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,
446467
struct kvm_mp_state *mp_state)
447468
{
448-
if (vcpu->arch.power_off)
449-
mp_state->mp_state = KVM_MP_STATE_STOPPED;
450-
else
451-
mp_state->mp_state = KVM_MP_STATE_RUNNABLE;
469+
*mp_state = READ_ONCE(vcpu->arch.mp_state);
452470

453471
return 0;
454472
}
@@ -458,17 +476,21 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
458476
{
459477
int ret = 0;
460478

479+
spin_lock(&vcpu->arch.mp_state_lock);
480+
461481
switch (mp_state->mp_state) {
462482
case KVM_MP_STATE_RUNNABLE:
463-
vcpu->arch.power_off = false;
483+
WRITE_ONCE(vcpu->arch.mp_state, *mp_state);
464484
break;
465485
case KVM_MP_STATE_STOPPED:
466-
kvm_riscv_vcpu_power_off(vcpu);
486+
__kvm_riscv_vcpu_power_off(vcpu);
467487
break;
468488
default:
469489
ret = -EINVAL;
470490
}
471491

492+
spin_unlock(&vcpu->arch.mp_state_lock);
493+
472494
return ret;
473495
}
474496

@@ -596,11 +618,11 @@ static void kvm_riscv_check_vcpu_requests(struct kvm_vcpu *vcpu)
596618
if (kvm_check_request(KVM_REQ_SLEEP, vcpu)) {
597619
kvm_vcpu_srcu_read_unlock(vcpu);
598620
rcuwait_wait_event(wait,
599-
(!vcpu->arch.power_off) && (!vcpu->arch.pause),
621+
(!kvm_riscv_vcpu_stopped(vcpu)) && (!vcpu->arch.pause),
600622
TASK_INTERRUPTIBLE);
601623
kvm_vcpu_srcu_read_lock(vcpu);
602624

603-
if (vcpu->arch.power_off || vcpu->arch.pause) {
625+
if (kvm_riscv_vcpu_stopped(vcpu) || vcpu->arch.pause) {
604626
/*
605627
* Awaken to handle a signal, request to
606628
* sleep again later.

arch/riscv/kvm/vcpu_sbi.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,11 @@ void kvm_riscv_vcpu_sbi_system_reset(struct kvm_vcpu *vcpu,
138138
unsigned long i;
139139
struct kvm_vcpu *tmp;
140140

141-
kvm_for_each_vcpu(i, tmp, vcpu->kvm)
142-
tmp->arch.power_off = true;
141+
kvm_for_each_vcpu(i, tmp, vcpu->kvm) {
142+
spin_lock(&vcpu->arch.mp_state_lock);
143+
WRITE_ONCE(tmp->arch.mp_state.mp_state, KVM_MP_STATE_STOPPED);
144+
spin_unlock(&vcpu->arch.mp_state_lock);
145+
}
143146
kvm_make_all_cpus_request(vcpu->kvm, KVM_REQ_SLEEP);
144147

145148
memset(&run->system_event, 0, sizeof(run->system_event));

arch/riscv/kvm/vcpu_sbi_hsm.c

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,18 @@ static int kvm_sbi_hsm_vcpu_start(struct kvm_vcpu *vcpu)
1818
struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
1919
struct kvm_vcpu *target_vcpu;
2020
unsigned long target_vcpuid = cp->a0;
21+
int ret = 0;
2122

2223
target_vcpu = kvm_get_vcpu_by_id(vcpu->kvm, target_vcpuid);
2324
if (!target_vcpu)
2425
return SBI_ERR_INVALID_PARAM;
25-
if (!target_vcpu->arch.power_off)
26-
return SBI_ERR_ALREADY_AVAILABLE;
26+
27+
spin_lock(&target_vcpu->arch.mp_state_lock);
28+
29+
if (!kvm_riscv_vcpu_stopped(target_vcpu)) {
30+
ret = SBI_ERR_ALREADY_AVAILABLE;
31+
goto out;
32+
}
2733

2834
reset_cntx = &target_vcpu->arch.guest_reset_context;
2935
/* start address */
@@ -34,19 +40,31 @@ static int kvm_sbi_hsm_vcpu_start(struct kvm_vcpu *vcpu)
3440
reset_cntx->a1 = cp->a2;
3541
kvm_make_request(KVM_REQ_VCPU_RESET, target_vcpu);
3642

37-
kvm_riscv_vcpu_power_on(target_vcpu);
43+
__kvm_riscv_vcpu_power_on(target_vcpu);
3844

39-
return 0;
45+
out:
46+
spin_unlock(&target_vcpu->arch.mp_state_lock);
47+
48+
return ret;
4049
}
4150

4251
static int kvm_sbi_hsm_vcpu_stop(struct kvm_vcpu *vcpu)
4352
{
44-
if (vcpu->arch.power_off)
45-
return SBI_ERR_FAILURE;
53+
int ret = 0;
4654

47-
kvm_riscv_vcpu_power_off(vcpu);
55+
spin_lock(&vcpu->arch.mp_state_lock);
4856

49-
return 0;
57+
if (kvm_riscv_vcpu_stopped(vcpu)) {
58+
ret = SBI_ERR_FAILURE;
59+
goto out;
60+
}
61+
62+
__kvm_riscv_vcpu_power_off(vcpu);
63+
64+
out:
65+
spin_unlock(&vcpu->arch.mp_state_lock);
66+
67+
return ret;
5068
}
5169

5270
static int kvm_sbi_hsm_vcpu_get_status(struct kvm_vcpu *vcpu)
@@ -58,7 +76,7 @@ static int kvm_sbi_hsm_vcpu_get_status(struct kvm_vcpu *vcpu)
5876
target_vcpu = kvm_get_vcpu_by_id(vcpu->kvm, target_vcpuid);
5977
if (!target_vcpu)
6078
return SBI_ERR_INVALID_PARAM;
61-
if (!target_vcpu->arch.power_off)
79+
if (!kvm_riscv_vcpu_stopped(target_vcpu))
6280
return SBI_HSM_STATE_STARTED;
6381
else if (vcpu->stat.generic.blocking)
6482
return SBI_HSM_STATE_SUSPENDED;
@@ -71,14 +89,11 @@ static int kvm_sbi_ext_hsm_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,
7189
{
7290
int ret = 0;
7391
struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
74-
struct kvm *kvm = vcpu->kvm;
7592
unsigned long funcid = cp->a6;
7693

7794
switch (funcid) {
7895
case SBI_EXT_HSM_HART_START:
79-
mutex_lock(&kvm->lock);
8096
ret = kvm_sbi_hsm_vcpu_start(vcpu);
81-
mutex_unlock(&kvm->lock);
8297
break;
8398
case SBI_EXT_HSM_HART_STOP:
8499
ret = kvm_sbi_hsm_vcpu_stop(vcpu);

0 commit comments

Comments
 (0)