* [PATCH v2] RISC-V: KVM: Convert IMSIC vsfile_lock to a raw spinlock
@ 2026-10-19 13:47 Andrew Jones
2026-10-19 17:16 ` Andrew Jones
0 siblings, 1 reply; 2+ messages in thread
From: Andrew Jones @ 2026-10-19 13:47 UTC (permalink / raw)
To: kvm-riscv; +Cc: anup, atish.patra, pjw, palmer, kvm, linux-riscv, linux-kernel
kvm_riscv_vcpu_aia_imsic_put() runs from the scheduler preemption
notifier with the raw runqueue lock held, so it must not take
vsfile_lock, an rwlock_t, which sleeps on PREEMPT_RT. All vsfile_lock
critical sections are short, so a raw spinlock is fine.
Fixes: 4cec89db80ba ("RISC-V: KVM: Move HGEI[E|P] CSR access to IMSIC virtualization")
Signed-off-by: Andrew Jones <andrew.jones@linux.dev>
---
v2:
- Convert vsfile_lock to raw_spinlock_t instead of adding a separate
hgei_lock [Anup]
---
arch/riscv/kvm/aia_imsic.c | 36 ++++++++++++++++++------------------
1 file changed, 18 insertions(+), 18 deletions(-)
diff --git a/arch/riscv/kvm/aia_imsic.c b/arch/riscv/kvm/aia_imsic.c
index f17dc559a709..bad0ce20edc1 100644
--- a/arch/riscv/kvm/aia_imsic.c
+++ b/arch/riscv/kvm/aia_imsic.c
@@ -47,7 +47,7 @@ struct imsic {
*/
/* IMSIC VS-file */
- rwlock_t vsfile_lock;
+ raw_spinlock_t vsfile_lock;
int vsfile_cpu;
int vsfile_hgei;
void __iomem *vsfile_va;
@@ -593,13 +593,13 @@ static void imsic_vsfile_cleanup(struct imsic *imsic)
* VCPU is being destroyed.
*/
- write_lock_irqsave(&imsic->vsfile_lock, flags);
+ raw_spin_lock_irqsave(&imsic->vsfile_lock, flags);
old_vsfile_hgei = imsic->vsfile_hgei;
old_vsfile_cpu = imsic->vsfile_cpu;
imsic->vsfile_cpu = imsic->vsfile_hgei = -1;
imsic->vsfile_va = NULL;
imsic->vsfile_pa = 0;
- write_unlock_irqrestore(&imsic->vsfile_lock, flags);
+ raw_spin_unlock_irqrestore(&imsic->vsfile_lock, flags);
memset(imsic->swfile, 0, sizeof(*imsic->swfile));
@@ -687,7 +687,7 @@ bool kvm_riscv_vcpu_aia_imsic_has_interrupt(struct kvm_vcpu *vcpu)
* only check for interrupt when IMSIC VS-file is being used.
*/
- read_lock_irqsave(&imsic->vsfile_lock, flags);
+ raw_spin_lock_irqsave(&imsic->vsfile_lock, flags);
if (imsic->vsfile_cpu > -1) {
/*
* This function is typically called from kvm_vcpu_block() via
@@ -702,7 +702,7 @@ bool kvm_riscv_vcpu_aia_imsic_has_interrupt(struct kvm_vcpu *vcpu)
else
ret = !!(csr_read(CSR_HGEIP) & BIT(imsic->vsfile_hgei));
}
- read_unlock_irqrestore(&imsic->vsfile_lock, flags);
+ raw_spin_unlock_irqrestore(&imsic->vsfile_lock, flags);
return ret;
}
@@ -727,10 +727,10 @@ void kvm_riscv_vcpu_aia_imsic_put(struct kvm_vcpu *vcpu)
if (!kvm_vcpu_is_blocking(vcpu))
return;
- read_lock_irqsave(&imsic->vsfile_lock, flags);
+ raw_spin_lock_irqsave(&imsic->vsfile_lock, flags);
if (imsic->vsfile_cpu > -1)
csr_set(CSR_HGEIE, BIT(imsic->vsfile_hgei));
- read_unlock_irqrestore(&imsic->vsfile_lock, flags);
+ raw_spin_unlock_irqrestore(&imsic->vsfile_lock, flags);
}
void kvm_riscv_vcpu_aia_imsic_release(struct kvm_vcpu *vcpu)
@@ -744,13 +744,13 @@ void kvm_riscv_vcpu_aia_imsic_release(struct kvm_vcpu *vcpu)
return;
/* Read and clear IMSIC VS-file details */
- write_lock_irqsave(&imsic->vsfile_lock, flags);
+ raw_spin_lock_irqsave(&imsic->vsfile_lock, flags);
old_vsfile_hgei = imsic->vsfile_hgei;
old_vsfile_cpu = imsic->vsfile_cpu;
imsic->vsfile_cpu = imsic->vsfile_hgei = -1;
imsic->vsfile_va = NULL;
imsic->vsfile_pa = 0;
- write_unlock_irqrestore(&imsic->vsfile_lock, flags);
+ raw_spin_unlock_irqrestore(&imsic->vsfile_lock, flags);
/* Do nothing, if no IMSIC VS-file to release */
if (old_vsfile_cpu < 0)
@@ -807,10 +807,10 @@ int kvm_riscv_vcpu_aia_imsic_update(struct kvm_vcpu *vcpu)
return 1;
/* Read old IMSIC VS-file details */
- read_lock_irqsave(&imsic->vsfile_lock, flags);
+ raw_spin_lock_irqsave(&imsic->vsfile_lock, flags);
old_vsfile_hgei = imsic->vsfile_hgei;
old_vsfile_cpu = imsic->vsfile_cpu;
- read_unlock_irqrestore(&imsic->vsfile_lock, flags);
+ raw_spin_unlock_irqrestore(&imsic->vsfile_lock, flags);
/* Do nothing if we are continuing on same CPU */
if (old_vsfile_cpu == vcpu->cpu)
@@ -860,12 +860,12 @@ int kvm_riscv_vcpu_aia_imsic_update(struct kvm_vcpu *vcpu)
/* TODO: Update the IOMMU mapping ??? */
/* Update new IMSIC VS-file details in IMSIC context */
- write_lock_irqsave(&imsic->vsfile_lock, flags);
+ raw_spin_lock_irqsave(&imsic->vsfile_lock, flags);
imsic->vsfile_hgei = new_vsfile_hgei;
imsic->vsfile_cpu = vcpu->cpu;
imsic->vsfile_va = new_vsfile_va;
imsic->vsfile_pa = new_vsfile_pa;
- write_unlock_irqrestore(&imsic->vsfile_lock, flags);
+ raw_spin_unlock_irqrestore(&imsic->vsfile_lock, flags);
/*
* At this point, all interrupt producers have been moved
@@ -975,7 +975,7 @@ int kvm_riscv_aia_imsic_rw_attr(struct kvm *kvm, unsigned long type,
}
isel = KVM_DEV_RISCV_AIA_IMSIC_GET_ISEL(type);
- read_lock_irqsave(&imsic->vsfile_lock, flags);
+ raw_spin_lock_irqsave(&imsic->vsfile_lock, flags);
rc = 0;
vsfile_hgei = imsic->vsfile_hgei;
@@ -990,7 +990,7 @@ int kvm_riscv_aia_imsic_rw_attr(struct kvm *kvm, unsigned long type,
isel, val, 0, 0);
}
- read_unlock_irqrestore(&imsic->vsfile_lock, flags);
+ raw_spin_unlock_irqrestore(&imsic->vsfile_lock, flags);
if (!rc && vsfile_cpu >= 0)
rc = imsic_vsfile_rw(vsfile_hgei, vsfile_cpu, imsic->nr_eix,
@@ -1052,7 +1052,7 @@ int kvm_riscv_vcpu_aia_imsic_inject(struct kvm_vcpu *vcpu,
if (imsic->nr_msis <= iid)
return -EINVAL;
- read_lock_irqsave(&imsic->vsfile_lock, flags);
+ raw_spin_lock_irqsave(&imsic->vsfile_lock, flags);
if (imsic->vsfile_cpu >= 0) {
writel(iid, imsic->vsfile_va + IMSIC_MMIO_SETIPNUM_LE);
@@ -1062,7 +1062,7 @@ int kvm_riscv_vcpu_aia_imsic_inject(struct kvm_vcpu *vcpu,
imsic_swfile_extirq_update(vcpu);
}
- read_unlock_irqrestore(&imsic->vsfile_lock, flags);
+ raw_spin_unlock_irqrestore(&imsic->vsfile_lock, flags);
return 0;
}
@@ -1118,7 +1118,7 @@ int kvm_riscv_vcpu_aia_imsic_init(struct kvm_vcpu *vcpu)
/* Setup IMSIC context */
imsic->nr_msis = kvm->arch.aia.nr_ids + 1;
- rwlock_init(&imsic->vsfile_lock);
+ raw_spin_lock_init(&imsic->vsfile_lock);
imsic->nr_eix = BITS_TO_U64(imsic->nr_msis);
imsic->nr_hw_eix = BITS_TO_U64(kvm_riscv_aia_max_ids);
imsic->vsfile_hgei = imsic->vsfile_cpu = -1;
--
2.56.0
^ permalink raw reply [flat|nested] 2+ messages in thread* Re: [PATCH v2] RISC-V: KVM: Convert IMSIC vsfile_lock to a raw spinlock
2026-10-19 13:47 [PATCH v2] RISC-V: KVM: Convert IMSIC vsfile_lock to a raw spinlock Andrew Jones
@ 2026-10-19 17:16 ` Andrew Jones
0 siblings, 0 replies; 2+ messages in thread
From: Andrew Jones @ 2026-10-19 17:16 UTC (permalink / raw)
To: kvm-riscv; +Cc: anup, atish.patra, pjw, palmer, kvm, linux-riscv, linux-kernel
On Mon, Oct 19, 2026 at 03:47:09PM +0200, Andrew Jones wrote:
> kvm_riscv_vcpu_aia_imsic_put() runs from the scheduler preemption
> notifier with the raw runqueue lock held, so it must not take
> vsfile_lock, an rwlock_t, which sleeps on PREEMPT_RT. All vsfile_lock
> critical sections are short, so a raw spinlock is fine.
>
> Fixes: 4cec89db80ba ("RISC-V: KVM: Move HGEI[E|P] CSR access to IMSIC virtualization")
> Signed-off-by: Andrew Jones <andrew.jones@linux.dev>
> ---
> v2:
> - Convert vsfile_lock to raw_spinlock_t instead of adding a separate
> hgei_lock [Anup]
Hi Anup,
Sashiko found an ABBA deadlock with this v2[1]. Making vsfile_lock
exclusive serializes kvm_riscv_vcpu_aia_imsic_put(), which runs under
rq->__lock, against the SW-file inject paths, which kick the vCPU
(pi_lock/rq->__lock) while holding vsfile_lock. Lockdep confirms it with
an EMUL mode guest, and the host then hangs (I should have tested with
EMUL before...). v1 doesn't have the problem, since its hgei_lock never
has anything that wakes tasks nested under it. I tested v1 in both EMUL
mode and hwaccel mode [again] with lockdep and it's good.
Should we take v1 instead?
[1] https://sashiko.dev/#/patchset/20261019134709.2610129-1-andrew.jones@linux.dev?part=1
Thanks,
drew
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-10-19 17:16 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-19 13:47 [PATCH v2] RISC-V: KVM: Convert IMSIC vsfile_lock to a raw spinlock Andrew Jones
2026-10-19 17:16 ` Andrew Jones
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®