summaryrefslogtreecommitdiff
path: root/rust/kernel/alloc.rs
diff options
context:
space:
mode:
authorXie Bo <xb@ultrarisc.com>2026-07-15 10:03:59 +0800
committerAnup Patel <anup@brainfault.org>2026-07-15 13:37:48 +0530
commitd024a0a7879e6f37c0152aacf6d8e37b214a1738 (patch)
treee0856188f0575a23ec5113acf434e60ef4d22c63 /rust/kernel/alloc.rs
parent4d638dc09128de1cb8311dff51e5de7d606d9346 (diff)
downloadlinux-d024a0a7879e6f37c0152aacf6d8e37b214a1738.tar.gz
linux-d024a0a7879e6f37c0152aacf6d8e37b214a1738.zip
RISC-V: KVM: Serialize virtual interrupt pending state updates
KVM RISC-V tracks guest local interrupt state with two bitmaps: - irqs_pending: interrupts that should be visible to the guest - irqs_pending_mask: interrupts whose pending state changed The current code updates those bitmaps with independent atomic bitops and assumes a multiple-producer, single-consumer protocol. That model does not actually hold. kvm_riscv_vcpu_sync_interrupts() is not a pure consumer. When the guest changes guest-visible HVIP state, sync_interrupts() writes both irqs_pending and irqs_pending_mask to reflect the new guest state back into KVM state. As a result, irqs_pending and irqs_pending_mask form a single logical state transition, but they are not updated atomically as a pair. This allows a race where a newly injected interrupt is lost. For example: CPU0 CPU1 ---- ---- kvm_riscv_vcpu_set_interrupt(VS_SOFT) set_bit(VS_SOFT, irqs_pending) kvm_riscv_vcpu_sync_interrupts() sees guest-cleared HVIP.VSSIP sets irqs_pending_mask clear_bit(IRQ_VS_SOFT, irqs_pending) set_bit(VS_SOFT, irqs_pending_mask) kvm_vcpu_kick() After that interleaving, a later flush can update HVIP without VSSIP even though a new virtual interrupt was injected. In practice, the guest can remain blocked in WFI with work pending. The same pending/mask protocol is shared by VS soft interrupts, PMU overflow delivery, and AIA high interrupt synchronization, so the race is not limited to one interrupt source. Fix this by serializing all updates to irqs_pending and irqs_pending_mask with a per-vCPU raw spinlock. This keeps the pending bit and the dirty mask as one state transition across: - set/unset interrupt - guest HVIP sync - interrupt flush to guest CSR state - vCPU reset - AIA CSR writes that clear dirty state Use non-atomic bitmap operations while holding the lock. Hold the lock across the AIA sync, flush, and pending checks as well, so both bitmap words share the same serialization domain. This intentionally replaces the existing lockless protocol instead of trying to repair it with additional barriers. The problem is not memory ordering on a single field; it is that two separate bitmaps encode one shared state machine while both producers and sync paths can modify them. A per-vCPU raw spinlock keeps the fix small, local, and suitable for backporting. Fixes: cce69aff689e ("RISC-V: KVM: Implement VCPU interrupts and requests handling") Cc: stable@vger.kernel.org Signed-off-by: Xie Bo <xb@ultrarisc.com> Reviewed-by: Anup Patel <anup@brainfault.org> Link: https://lore.kernel.org/r/20260715020359.1521354-2-xb@ultrarisc.com Signed-off-by: Anup Patel <anup@brainfault.org>
Diffstat (limited to 'rust/kernel/alloc.rs')
0 files changed, 0 insertions, 0 deletions