* [PATCH v2 0/2] RISC-V: KVM: Optimize hfence request handling for SMP guests
@ 2026-07-07 12:50 Wang Yechao
2026-07-07 12:50 ` [PATCH v2 1/2] RISC-V: KVM: Introduce make_xfence_request_nodata for FENCE.I requests Wang Yechao
2026-07-07 12:50 ` [PATCH v2 2/2] RISC-V: KVM: Separate req and fallback_req masks in make_xfence_request Wang Yechao
0 siblings, 2 replies; 4+ messages in thread
From: Wang Yechao @ 2026-07-07 12:50 UTC (permalink / raw)
To: Anup Patel, kvm, kvm-riscv, linux-riscv, linux-kernel
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Atish Patra,
Alexandre Ghiti, Wang Yechao
This series improves the hfence request handling in RISC-V KVM,
targeting scenarios where multiple VCPUs are running an SMP guest.
The first patch Introduce make_xfence_request_nodata for FENCE.I
requests and moves the hfence data/type validation out of the
VCPU loop to avoid redundant checks on every iteration.
The second patch fixes a more subtle performance issue: when one
VCPU's hfence queue becomes full and triggers a fallback, the
current code applies the fallback to all VCPUs indiscriminately.
This unnecessarily degrades healthy VCPUs and can cause their
queues to fill up prematurely due to lack of processing it.
With these changes, fallback is applied only to the VCPUs that
actually need it, preserving the efficiency of the normal path
for others.
Changes in v2:
- Fix the patch01 broken the KVM_REQ_FENCE_I request(Sashiko AI review).
- Link to v1:
https://lore.kernel.org/linux-riscv/20260707113715.413265-1-wang.yechao255@zte.com.cn/
Wang Yechao (2):
RISC-V: KVM: Introduce make_xfence_request_nodata for FENCE.I requests
RISC-V: KVM: Separate req and fallback_req masks in
make_xfence_request
arch/riscv/kvm/tlb.c | 46 +++++++++++++++++++++++++++++++++-----------
1 file changed, 35 insertions(+), 11 deletions(-)
--
2.43.5
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v2 1/2] RISC-V: KVM: Introduce make_xfence_request_nodata for FENCE.I requests
2026-07-07 12:50 [PATCH v2 0/2] RISC-V: KVM: Optimize hfence request handling for SMP guests Wang Yechao
@ 2026-07-07 12:50 ` Wang Yechao
2026-07-07 13:03 ` sashiko-bot
2026-07-07 12:50 ` [PATCH v2 2/2] RISC-V: KVM: Separate req and fallback_req masks in make_xfence_request Wang Yechao
1 sibling, 1 reply; 4+ messages in thread
From: Wang Yechao @ 2026-07-07 12:50 UTC (permalink / raw)
To: Anup Patel, kvm, kvm-riscv, linux-riscv, linux-kernel
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Atish Patra,
Alexandre Ghiti, Wang Yechao
FENCE.I does not need hfence data, but it currently goes through the
generic make_xfence_request() path with NULL data, incurring unnecessary
per-VCPU checks.
Split out a separate make_xfence_request_nodata() function to handle
FENCE.I directly, and move the data validity check to the top of the
generic function to avoid redundant checks.
Signed-off-by: Wang Yechao <wang.yechao255@zte.com.cn>
---
arch/riscv/kvm/tlb.c | 32 +++++++++++++++++++++++++++-----
1 file changed, 27 insertions(+), 5 deletions(-)
diff --git a/arch/riscv/kvm/tlb.c b/arch/riscv/kvm/tlb.c
index 993b25ea94d67..5a9c75e458013 100644
--- a/arch/riscv/kvm/tlb.c
+++ b/arch/riscv/kvm/tlb.c
@@ -325,6 +325,29 @@ void kvm_riscv_hfence_process(struct kvm_vcpu *vcpu)
}
}
+static void make_xfence_request_nodata(struct kvm *kvm, unsigned long hbase,
+ unsigned long hmask, unsigned int req)
+{
+ unsigned long i;
+ struct kvm_vcpu *vcpu;
+ DECLARE_BITMAP(vcpu_mask, KVM_MAX_VCPUS);
+
+ bitmap_zero(vcpu_mask, KVM_MAX_VCPUS);
+ kvm_for_each_vcpu(i, vcpu, kvm) {
+ if (hbase != -1UL) {
+ if (vcpu->vcpu_id < hbase ||
+ vcpu->vcpu_id >= hbase + BITS_PER_LONG)
+ continue;
+ if (!(hmask & (1UL << (vcpu->vcpu_id - hbase))))
+ continue;
+ }
+
+ bitmap_set(vcpu_mask, i, 1);
+ }
+
+ kvm_make_vcpus_request_mask(kvm, req, vcpu_mask);
+}
+
static void make_xfence_request(struct kvm *kvm,
unsigned long hbase, unsigned long hmask,
unsigned int req, unsigned int fallback_req,
@@ -335,6 +358,9 @@ static void make_xfence_request(struct kvm *kvm,
unsigned int actual_req = req;
DECLARE_BITMAP(vcpu_mask, KVM_MAX_VCPUS);
+ if (!data || !data->type)
+ return;
+
bitmap_zero(vcpu_mask, KVM_MAX_VCPUS);
kvm_for_each_vcpu(i, vcpu, kvm) {
if (hbase != -1UL) {
@@ -347,9 +373,6 @@ static void make_xfence_request(struct kvm *kvm,
bitmap_set(vcpu_mask, i, 1);
- if (!data || !data->type)
- continue;
-
/*
* Enqueue hfence data to VCPU hfence queue. If we don't
* have space in the VCPU hfence queue then fallback to
@@ -365,8 +388,7 @@ static void make_xfence_request(struct kvm *kvm,
void kvm_riscv_fence_i(struct kvm *kvm,
unsigned long hbase, unsigned long hmask)
{
- make_xfence_request(kvm, hbase, hmask, KVM_REQ_FENCE_I,
- KVM_REQ_FENCE_I, NULL);
+ make_xfence_request_nodata(kvm, hbase, hmask, KVM_REQ_FENCE_I);
}
void kvm_riscv_hfence_gvma_vmid_gpa(struct kvm *kvm,
--
2.43.5
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v2 2/2] RISC-V: KVM: Separate req and fallback_req masks in make_xfence_request
2026-07-07 12:50 [PATCH v2 0/2] RISC-V: KVM: Optimize hfence request handling for SMP guests Wang Yechao
2026-07-07 12:50 ` [PATCH v2 1/2] RISC-V: KVM: Introduce make_xfence_request_nodata for FENCE.I requests Wang Yechao
@ 2026-07-07 12:50 ` Wang Yechao
1 sibling, 0 replies; 4+ messages in thread
From: Wang Yechao @ 2026-07-07 12:50 UTC (permalink / raw)
To: Anup Patel, kvm, kvm-riscv, linux-riscv, linux-kernel
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Atish Patra,
Alexandre Ghiti, Wang Yechao
When handling hfence requests in make_xfence_request(), the current code
uses a single 'actual_req' variable and a single vcpu_mask. If any VCPU
fails to enqueue the hfence data (because its queue is full), the request
falls back to 'fallback_req' for all VCPUs, even if other VCPUs still
have available queue space.
This can cause unnecessary fallback for healthy VCPUs, and more seriously,
those healthy VCPUs will not process their already-enqueued hfence
requests because no 'req' is set for them. As a result, their queues will
quickly become full as well, degrading performance for SMP guests.
Fix this by maintaining two separate bitmaps: one for VCPUs that
successfully enqueued the hfence data (req_vcpu_mask) and another for
those that failed (fallback_req_vcpu_mask). Then send the appropriate
requests to each group. This ensures that fallback is only applied to
VCPUs that actually need it, preserving the efficiency of the normal
path for others.
Fixes: 13acfec2dbcc ("RISC-V: KVM: Add remote HFENCE functions based on VCPU requests")
Signed-off-by: Wang Yechao <wang.yechao255@zte.com.cn>
---
arch/riscv/kvm/tlb.c | 16 +++++++++-------
1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/arch/riscv/kvm/tlb.c b/arch/riscv/kvm/tlb.c
index 5a9c75e458013..fd445e9fa3f94 100644
--- a/arch/riscv/kvm/tlb.c
+++ b/arch/riscv/kvm/tlb.c
@@ -355,13 +355,14 @@ static void make_xfence_request(struct kvm *kvm,
{
unsigned long i;
struct kvm_vcpu *vcpu;
- unsigned int actual_req = req;
- DECLARE_BITMAP(vcpu_mask, KVM_MAX_VCPUS);
+ DECLARE_BITMAP(req_vcpu_mask, KVM_MAX_VCPUS);
+ DECLARE_BITMAP(fallback_req_vcpu_mask, KVM_MAX_VCPUS);
if (!data || !data->type)
return;
- bitmap_zero(vcpu_mask, KVM_MAX_VCPUS);
+ bitmap_zero(req_vcpu_mask, KVM_MAX_VCPUS);
+ bitmap_zero(fallback_req_vcpu_mask, KVM_MAX_VCPUS);
kvm_for_each_vcpu(i, vcpu, kvm) {
if (hbase != -1UL) {
if (vcpu->vcpu_id < hbase ||
@@ -371,18 +372,19 @@ static void make_xfence_request(struct kvm *kvm,
continue;
}
- bitmap_set(vcpu_mask, i, 1);
-
/*
* Enqueue hfence data to VCPU hfence queue. If we don't
* have space in the VCPU hfence queue then fallback to
* a more conservative hfence request.
*/
if (!vcpu_hfence_enqueue(vcpu, data))
- actual_req = fallback_req;
+ bitmap_set(fallback_req_vcpu_mask, i, 1);
+ else
+ bitmap_set(req_vcpu_mask, i, 1);
}
- kvm_make_vcpus_request_mask(kvm, actual_req, vcpu_mask);
+ kvm_make_vcpus_request_mask(kvm, req, req_vcpu_mask);
+ kvm_make_vcpus_request_mask(kvm, fallback_req, fallback_req_vcpu_mask);
}
void kvm_riscv_fence_i(struct kvm *kvm,
--
2.43.5
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH v2 1/2] RISC-V: KVM: Introduce make_xfence_request_nodata for FENCE.I requests
2026-07-07 12:50 ` [PATCH v2 1/2] RISC-V: KVM: Introduce make_xfence_request_nodata for FENCE.I requests Wang Yechao
@ 2026-07-07 13:03 ` sashiko-bot
0 siblings, 0 replies; 4+ messages in thread
From: sashiko-bot @ 2026-07-07 13:03 UTC (permalink / raw)
To: Wang Yechao; +Cc: kvm
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Stranded `hfence_queue` entries cause permanent fallback to global TLB flushes.
--
--- Patch [1]: [PATCH v2 1/2] RISC-V: KVM: Introduce make_xfence_request_nodata for FENCE.I requests ---
commit c3b95cdce701530ec81cfa3b256ee7e3d2dd263d
Author: Wang Yechao <wang.yechao255@zte.com.cn>
RISC-V: KVM: Introduce make_xfence_request_nodata for FENCE.I requests
FENCE.I does not need hfence data, but it currently goes through the
generic make_xfence_request() path with NULL data, incurring unnecessary
per-VCPU checks. Split out a separate make_xfence_request_nodata() function
to handle FENCE.I directly, and move the data validity check to the top of
the generic function to avoid redundant checks.
> diff --git a/arch/riscv/kvm/tlb.c b/arch/riscv/kvm/tlb.c
> index 993b25ea94d67..5a9c75e458013 100644
> --- a/arch/riscv/kvm/tlb.c
> +++ b/arch/riscv/kvm/tlb.c
[ ... ]
> @@ -347,9 +373,6 @@ static void make_xfence_request(struct kvm *kvm,
>
> bitmap_set(vcpu_mask, i, 1);
>
> - if (!data || !data->type)
> - continue;
> -
> /*
> * Enqueue hfence data to VCPU hfence queue. If we don't
> * have space in the VCPU hfence queue then fallback to
[Severity: High]
This isn't a bug introduced by this patch, but can this loop in
make_xfence_request() cause a performance regression by stranding enqueued
items if a later enqueue fails?
If any vCPU's queue is full, vcpu_hfence_enqueue() fails, and the loop
overrides actual_req to fallback_req (e.g., KVM_REQ_TLB_FLUSH) for the entire
batch:
if (!vcpu_hfence_enqueue(vcpu, data))
actual_req = fallback_req;
}
kvm_make_vcpus_request_mask(kvm, actual_req, vcpu_mask);
The vCPUs that successfully enqueued the data earlier in the loop will receive
KVM_REQ_TLB_FLUSH instead of KVM_REQ_HFENCE. Since they process
KVM_REQ_TLB_FLUSH without dequeueing from their hfence_queue (which only
happens when processing KVM_REQ_HFENCE via kvm_riscv_hfence_process()), these
successfully enqueued items become permanently stranded.
As this repeats, the queues of healthy vCPUs will eventually fill up. Once a
queue is fully saturated with stranded items, it will permanently fail all
future enqueues, forcing all subsequent fine-grained requests to downgrade to
global TLB flushes for the lifetime of the VM.
> * a more conservative hfence request.
> */
> @@ -365,8 +388,7 @@ static void make_xfence_request(struct kvm *kvm,
> void kvm_riscv_fence_i(struct kvm *kvm,
> unsigned long hbase, unsigned long hmask)
> {
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260707125034.416521-1-wang.yechao255@zte.com.cn?part=1
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-07-07 13:03 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-07 12:50 [PATCH v2 0/2] RISC-V: KVM: Optimize hfence request handling for SMP guests Wang Yechao
2026-07-07 12:50 ` [PATCH v2 1/2] RISC-V: KVM: Introduce make_xfence_request_nodata for FENCE.I requests Wang Yechao
2026-07-07 13:03 ` sashiko-bot
2026-07-07 12:50 ` [PATCH v2 2/2] RISC-V: KVM: Separate req and fallback_req masks in make_xfence_request Wang Yechao
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox