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

Anup Patel <[email protected]>
Newsgroups org.infradead.lists.kvm-riscv,org.infradead.lists.linux-riscv,org.kernel.vger.kvm,org.kernel.vger.linux-kernel
Message-ID <CAAhSdy28AR=Gs90nofSWPkh9z_gmwmmTjsae_PCyyL_5qXcGhQ@mail.gmail.com>
On Wed, May 13, 2026 at 1:11 PM <[email protected]> wrote:
>
> From: Wang Yechao <[email protected]>
>
> 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 <[email protected]>
> ---
>  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

-- 
kvm-riscv mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kvm-riscv
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.