From: sashiko-bot@kernel.org
To: "slack up" <yxcnew@outlook.com>
Cc: kvm@vger.kernel.org
Subject: Re: [RFC PATCH 2/3] RISC-V: KVM: Preserve guest Vector state across vCPU put/load
Date: Tue, 27 Oct 2026 14:11:06 +0000 [thread overview]
Message-ID: <sashiko-outbox-186708@kernel.org> (raw)
In-Reply-To: <OSQPR01MB63262D568C71BC3510AAC4A4C2602@OSQPR01MB6326.apcprd01.prod.exchangelabs.com>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Critical] RISC-V: KVM: missing vector owner invalidation on preempt_v start race
- [High] RISC-V: KVM: vector owner invalidation runs before enter_from_user_mode()
- [Low] RISC-V: KVM: missing kernel-parameters.txt entry for vector_owner_fastpath
--
commit f4e86411e0473662833880eb7f87be358e15d73e
Author: Xiaochun Yu <yxcnew@outlook.com>
RISC-V: KVM: Preserve guest Vector state across vCPU put/load
This commit introduces per-hart Vector owner tracking in RISC-V KVM so that a
vCPU reloaded on the same hart can restore only Vector control CSRs when its
Vector data registers remain resident in hardware. The optimization is gated
behind a read-only vector_owner_fastpath module parameter and hooks into the
generic RISC-V Vector context invalidation callback.
> diff --git a/arch/riscv/kvm/vcpu_vector.c b/arch/riscv/kvm/vcpu_vector.c
> index fefc2857f753a..c197d3d7b539d 100644
> --- a/arch/riscv/kvm/vcpu_vector.c
> +++ b/arch/riscv/kvm/vcpu_vector.c
> @@ -17,7 +19,50 @@
> #include <asm/kvm_vcpu_vector.h>
> #include <asm/vector.h>
>
> +#include "trace.h"
> +
> #ifdef CONFIG_RISCV_ISA_V
[ ... ]
> +static DEFINE_PER_CPU(struct kvm_riscv_vector_owner,
> + kvm_riscv_vector_owner);
> +static atomic64_t kvm_riscv_vector_owner_cookie = ATOMIC64_INIT(0);
> +static bool kvm_riscv_vector_owner_fastpath;
> +module_param_named(vector_owner_fastpath, kvm_riscv_vector_owner_fastpath,
> + bool, 0444);
> +MODULE_PARM_DESC(vector_owner_fastpath,
> + "Preserve matched guest Vector registers across vCPU put/load");
[Severity: Low]
Since vector_owner_fastpath is a read-only module parameter checked during
initialization in kvm_riscv_v_init() (and passed on the kernel command line
as kvm.vector_owner_fastpath when KVM is built-in), should this parameter
also be documented in Documentation/admin-guide/kernel-parameters.txt?
> +
> +bool kvm_riscv_vcpu_vector_owner_enabled(void)
> +{
> + return READ_ONCE(kvm_riscv_vector_owner_fastpath);
> +}
[ ... ]
> +bool kvm_riscv_vcpu_vector_owner_load(struct kvm_vcpu *vcpu, int cpu)
> +{
> + struct kvm_riscv_vector_owner *owner;
> + unsigned long guest_vs = vcpu->arch.guest_context.sstatus & SR_VS;
> + unsigned long host_vs = task_pt_regs(current)->status & SR_VS;
> + enum kvm_riscv_vector_owner_reason reason;
> + bool eligible = false;
> +
> + if (!kvm_riscv_vcpu_vector_owner_enabled())
> + return false;
> +
> + owner = this_cpu_ptr(&kvm_riscv_vector_owner);
> + if (guest_vs == SR_VS_OFF) {
> + reason = KVM_RISCV_VECTOR_OWNER_GUEST_OFF;
> + } else if (host_vs != SR_VS_OFF) {
> + reason = KVM_RISCV_VECTOR_OWNER_HOST_ON;
> + } else if (!owner->identity) {
> + reason = vcpu->arch.last_exit_cpu == cpu ?
> + KVM_RISCV_VECTOR_OWNER_EMPTY :
> + KVM_RISCV_VECTOR_OWNER_MIGRATION;
> + } else if (owner->identity != (unsigned long)vcpu) {
> + reason = KVM_RISCV_VECTOR_OWNER_OTHER_VCPU;
> + } else if (owner->cookie != vcpu->arch.vector_owner_cookie) {
> + reason = KVM_RISCV_VECTOR_OWNER_COOKIE;
> + } else if (owner->generation != vcpu->arch.vector_state_generation) {
> + reason = KVM_RISCV_VECTOR_OWNER_GENERATION;
> + } else {
> + reason = KVM_RISCV_VECTOR_OWNER_HIT;
> + eligible = true;
> + }
[Severity: Critical]
Can a preemption window in riscv_v_start_kernel_context() allow a kernel
Vector user to clobber the hardware Vector registers without invalidating
kvm_riscv_vector_owner, causing kvm_riscv_vcpu_vector_owner_load() to
falsely report KVM_RISCV_VECTOR_OWNER_HIT?
With CONFIG_RISCV_ISA_V_PREEMPTIVE=y, kernel_vector_begin() calls
riscv_v_start_kernel_context() in arch/riscv/kernel/kernel_mode_vector.c:
/* Transfer the ownership of V from user to kernel, then save */
get_cpu_vector_context();
__riscv_flush_vector_context();
put_cpu_vector_context();
/*
* A voluntary context switch caused by put_cpu_vector_context() can
* raise the NEED_RESTORE flag if preempt_v starts too early due to a
* failed risv_v_is_on() check.
*
* This causes the next context_nesting_end pollute the v-reg from
* the stale context memory in kernel-mode vector.
*/
riscv_v_start(RISCV_PREEMPT_V);
__riscv_flush_vector_context() calls
riscv_v_owner_invalidate(RISCV_V_INVALIDATE_KERNEL_VECTOR) on the initial
hart, and then put_cpu_vector_context() clears RISCV_KERNEL_MODE_V and
re-enables bottom halves or preemption before RISCV_PREEMPT_V is set on
current->thread.riscv_v_flags.
If the task is preempted at put_cpu_vector_context() before
riscv_v_start(RISCV_PREEMPT_V) runs:
1. A vCPU thread can run on this hart and publish itself in
kvm_riscv_vector_owner via kvm_arch_vcpu_put() ->
kvm_riscv_vcpu_vector_owner_put(), or the preempted task can migrate to
another hart that already has a published kvm_riscv_vector_owner.
2. When the task is scheduled back in, __switch_to_vector() in
arch/riscv/include/asm/vector.h checks riscv_preempt_v_started(next):
if (riscv_preempt_v_started(next)) {
riscv_v_owner_invalidate(RISCV_V_INVALIDATE_KERNEL_VECTOR);
...
} else {
riscv_v_vstate_set_restore(next, task_pt_regs(next));
}
Because RISCV_PREEMPT_V is not yet set, __switch_to_vector() skips
riscv_v_owner_invalidate(RISCV_V_INVALIDATE_KERNEL_VECTOR).
3. The task then executes riscv_v_start(RISCV_PREEMPT_V), returns to
kernel_vector_begin(), enables Vector, and overwrites v0..v31 with host
kernel data while kvm_riscv_vector_owner on that hart still matches the
vCPU.
4. When that vCPU reloads on the same hart,
kvm_riscv_vcpu_vector_owner_load() sees a matching owner, cookie, and
generation and requests RISCV_V_VCPU_CSR_RESTORE.
kvm_riscv_vcpu_enter_exit() in arch/riscv/kvm/vcpu.c then restores only
the Vector CSRs via __kvm_riscv_vector_restore_csrs() and enters the
guest with host kernel Vector register contents in v0..v31.
> +
> + trace_kvm_riscv_vector_owner(vcpu->vcpu_id, cpu, 0, eligible,
> + reason, host_vs, guest_vs,
> + vcpu->arch.vector_state_generation);
[ ... ]
> +void kvm_riscv_vcpu_vector_owner_invalidate(enum riscv_v_invalidate_reason reason)
> +{
> + struct kvm_riscv_vector_owner *owner;
> + struct kvm_vcpu *vcpu;
> + enum kvm_riscv_vector_owner_reason trace_reason;
> + unsigned long host_vs;
> + u32 flags;
[ ... ]
> + preempt_disable();
> + flags = riscv_v_flags();
> + if (flags & RISCV_V_VCPU_CSR_RESTORE) {
> + vcpu = *this_cpu_ptr(kvm_get_running_vcpus());
> + if (!WARN_ON_ONCE(!vcpu)) {
> + flags &= ~RISCV_V_VCPU_CSR_RESTORE;
> + flags |= RISCV_V_VCPU_NEED_RESTORE;
> + riscv_v_flags_set(flags);
> + host_vs = task_pt_regs(current)->status & SR_VS;
> + trace_kvm_riscv_vector_owner(vcpu->vcpu_id,
> + smp_processor_id(), 2, false,
> + trace_reason, host_vs,
> + vcpu->arch.guest_context.sstatus & SR_VS,
> + vcpu->arch.vector_state_generation);
> + }
> + }
> +
> + owner = this_cpu_ptr(&kvm_riscv_vector_owner);
> + if (!owner->identity)
> + goto out;
> +
> + host_vs = task_pt_regs(current)->status & SR_VS;
> + trace_kvm_riscv_vector_owner(owner->vcpu_id, smp_processor_id(), 2,
> + false, trace_reason, host_vs,
> + owner->guest_vs, owner->generation);
> + owner->identity = 0;
> + owner->cookie = 0;
> + owner->generation = 0;
> + owner->vcpu_id = 0;
> + owner->guest_vs = 0;
> +
> +out:
> + preempt_enable();
> +}
[Severity: High]
When kvm_riscv_v_init() in arch/riscv/include/asm/kvm_vcpu_vector.h registers
kvm_riscv_vcpu_vector_owner_invalidate(), can this callback and its RCU
dispatch in __riscv_v_owner_invalidate() run from do_trap_ecall_u() before
enter_from_user_mode() transitions RCU and lockdep out of user mode?
In arch/riscv/kernel/traps.c, do_trap_ecall_u() is a noinstr trap handler
that calls riscv_v_vstate_discard(regs) before entering the kernel context:
if (user_mode(regs)) {
long syscall = regs->a7;
regs->epc += 4;
regs->orig_a0 = regs->a0;
regs->a0 = -ENOSYS;
riscv_v_vstate_discard(regs);
if (likely(syscall_enter_from_user_mode_randomize_stack(regs, &syscall))) {
When a user task with active Vector state issues a syscall,
riscv_v_vstate_discard(regs) in arch/riscv/include/asm/vector.h calls
riscv_v_owner_invalidate(RISCV_V_INVALIDATE_TASK_DISCARD) ->
__riscv_v_owner_invalidate() in arch/riscv/kernel/kernel_mode_vector.c:
rcu_read_lock();
invalidate_callback = rcu_dereference(kvm_invalidate_vector_ctx_callback);
if (invalidate_callback)
invalidate_callback(reason);
rcu_read_unlock();
Because enter_from_user_mode() is only invoked later inside
syscall_enter_from_user_mode_randomize_stack(), on configurations with
CONFIG_CONTEXT_TRACKING_USER=y (such as NO_HZ_FULL), RCU is still in
CT_STATE_USER (!rcu_is_watching()) and lockdep_hardirqs_off() has not run
yet. Calling rcu_read_lock(), rcu_dereference(), preempt_disable(), and
trace_kvm_riscv_vector_owner() here will trigger RCU and tracepoint lockdep
warnings and leave the callback invocation unprotected by synchronize_rcu()
during kvm_riscv_v_exit().
--
Sashiko AI review · https://sashiko.dev/#/patchset/OSQPR01MB63265385597FE472C4209353C2602@OSQPR01MB6326.apcprd01.prod.exchangelabs.com?part=2
next prev parent reply other threads:[~2026-10-27 14:11 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-27 13:13 [RFC PATCH 0/3] RISC-V: KVM: Preserve resident guest Vector state slack up
2026-10-27 13:13 ` slack up
2026-10-27 13:13 ` slack up
2026-10-27 13:13 ` [RFC PATCH 1/3] riscv: vector: Add a guest owner invalidation hook slack up
2026-10-27 13:13 ` slack up
2026-10-27 13:13 ` slack up
2026-10-27 14:03 ` sashiko-bot
2026-10-27 13:13 ` [RFC PATCH 2/3] RISC-V: KVM: Preserve guest Vector state across vCPU put/load slack up
2026-10-27 13:13 ` slack up
2026-10-27 13:13 ` slack up
2026-10-27 14:11 ` sashiko-bot [this message]
2026-10-27 13:13 ` [RFC PATCH 3/3] KVM: riscv: selftests: Add Vector owner regression tests slack up
2026-10-27 13:13 ` slack up
2026-10-27 13:13 ` slack up
2026-10-27 14:03 ` sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=sashiko-outbox-186708@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=kvm@vger.kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
--cc=yxcnew@outlook.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.