Re: [PATCH 2/4] RISC-V: KVM: Split huge pages when dirty logging is enabled

Anup Patel anup at brainfault.org
Wed Jun 3 01:18:41 PDT 2026


On Wed, May 13, 2026 at 1:11 PM <wang.yechao255 at zte.com.cn> wrote:
>
> From: Wang Yechao <wang.yechao255 at zte.com.cn>
>
> Split huge pages eagerly when enabling dirty logging. The goal is to
> avoid doing it while faulting on write-protected pages, which
> negatively impacts guest performance.
>
> The benefits of eager page splitting are the same as in x86 and arm64,
> added with commit a3fe5dbda0a4 ("KVM: x86/mmu: Split huge pages mapped
> by the TDP MMU when dirty logging is enabled") and commit e7bf7a490c68
> ("KVM: arm64: Split huge pages when dirty logging is enabled")
>
> Signed-off-by: Wang Yechao <wang.yechao255 at zte.com.cn>
> ---
>  arch/riscv/kvm/mmu.c | 62 ++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 62 insertions(+)
>
> diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c
> index 85a3fb2622a4..14c558ee5f15 100644
> --- a/arch/riscv/kvm/mmu.c
> +++ b/arch/riscv/kvm/mmu.c
> @@ -90,6 +90,50 @@ void kvm_riscv_mmu_iounmap(struct kvm *kvm, gpa_t gpa, unsigned long size)
>         spin_unlock(&kvm->mmu_lock);
>  }
>
> +static bool need_topup_split_caches_or_resched(struct kvm_mmu_memory_cache *cache,
> +                                              int count)
> +{
> +       if (need_resched())
> +               return true;
> +
> +       return kvm_mmu_memory_cache_nr_free_objects(cache) < count;
> +}
> +
> +/* the caller must held mmu lock */
> +static void kvm_riscv_split_huge_pages(struct kvm_gstage *gstage,
> +                                      phys_addr_t start, phys_addr_t end,
> +                                      bool flush)

s/kvm_riscv_split_huge_pages/mmu_split_huge_pages/

> +{
> +       struct kvm *kvm = gstage->kvm;
> +       struct kvm_mmu_memory_cache *pcache = &kvm->arch.split_page_cache;
> +       int count = gstage->pgd_levels;
> +       phys_addr_t addr = start;
> +       int ret;
> +

lockdep_assert_held ??

> +       while (addr < end) {
> +               if (need_topup_split_caches_or_resched(pcache, count)) {
> +                       spin_unlock(&kvm->mmu_lock);
> +                       cond_resched();
> +
> +                       ret = kvm_mmu_topup_memory_cache(pcache, count);
> +                       if (ret) {
> +                               kvm_err("Failed to toup split page cache\n");
> +                               spin_lock(&kvm->mmu_lock);
> +                               return;
> +                       }
> +                       spin_lock(&kvm->mmu_lock);
> +               }
> +
> +               ret = kvm_riscv_gstage_split_huge(gstage, pcache, addr, 0, flush);
> +               if (ret != 0) {
> +                       kvm_err("split huge page for addr(0x%llx) failed %d\n", addr, ret);
> +                       break;
> +               }
> +
> +               addr += PMD_SIZE;
> +       }
> +}
> +
>  void kvm_arch_mmu_enable_log_dirty_pt_masked(struct kvm *kvm,
>                                              struct kvm_memory_slot *slot,
>                                              gfn_t gfn_offset,
> @@ -136,6 +180,23 @@ void kvm_arch_flush_shadow_memslot(struct kvm *kvm,
>         spin_unlock(&kvm->mmu_lock);
>  }
>
> +static void kvm_riscv_split_memory_region(struct kvm *kvm, int slot)

s/kvm_riscv_split_memory_region/mmu_split_memory_region/

> +{
> +       struct kvm_memslots *slots = kvm_memslots(kvm);
> +       struct kvm_memory_slot *memslot = id_to_memslot(slots, slot);
> +       phys_addr_t start = memslot->base_gfn << PAGE_SHIFT;
> +       phys_addr_t end = (memslot->base_gfn + memslot->npages) << PAGE_SHIFT;
> +       struct kvm_gstage gstage;
> +
> +       kvm_riscv_gstage_init(&gstage, kvm);
> +
> +       spin_lock(&kvm->mmu_lock);
> +       kvm_riscv_split_huge_pages(&gstage, start, end, false);
> +       spin_unlock(&kvm->mmu_lock);
> +
> +       kvm_flush_remote_tlbs_memslot(kvm, memslot);
> +}
> +
>  void kvm_arch_commit_memory_region(struct kvm *kvm,
>                                 struct kvm_memory_slot *old,
>                                 const struct kvm_memory_slot *new,
> @@ -150,6 +211,7 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
>                 if (kvm_dirty_log_manual_protect_and_init_set(kvm))
>                         return;
>                 mmu_wp_memory_region(kvm, new->id);
> +               kvm_riscv_split_memory_region(kvm, new->id);
>         }
>  }
>
> --
> 2.27.0

Regards,
Anup



More information about the kvm-riscv mailing list