[PATCH 2/3] KVM: riscv: Check hugetlb block mappings against memslot bounds
Anup Patel
anup at brainfault.org
Wed Jun 3 22:40:32 PDT 2026
On Wed, May 20, 2026 at 8:52 PM Jinyu Tang <tjytimi at 163.com> wrote:
>
> RISC-V KVM has used the hugetlb VMA size directly as the G-stage
> mapping size since stage-2 page table support was added. That is safe
> only if the block covered by the fault is fully contained in the
> memslot and the userspace address has the same offset as the GPA
> within that block.
>
> The THP path already checks those constraints before installing a PMD
> block mapping. The hugetlb path did not, so an unaligned memslot could
> make KVM install a PMD or PUD sized G-stage block that covers memory
> outside the slot or maps the wrong host pages.
>
> Select hugetlb mapping sizes through the same memslot-boundary check,
> falling back from PUD to PMD to PAGE_SIZE. When a smaller hugetlb
> mapping size is selected, fault the GFN aligned to that selected size
> instead of the original VMA size.
>
> Also keep hugetlb mappings out of transparent_hugepage_adjust(). Once
> the hugetlb path has chosen PAGE_SIZE, promoting it again through the
> THP helper would miss the hugetlb fallback decision.
>
> Fixes: 9d05c1fee837 ("RISC-V: KVM: Implement stage2 page table programming")
> Signed-off-by: Jinyu Tang <tjytimi at 163.com>
> ---
> arch/riscv/kvm/mmu.c | 40 ++++++++++++++++++++++++++++++++++++----
> 1 file changed, 36 insertions(+), 4 deletions(-)
>
> diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c
> index 10be8f683..d2378bb1f 100644
> --- a/arch/riscv/kvm/mmu.c
> +++ b/arch/riscv/kvm/mmu.c
> @@ -423,12 +423,33 @@ static unsigned long transparent_hugepage_adjust(struct kvm *kvm,
> return PAGE_SIZE;
> }
>
> +static unsigned long hugetlb_mapping_size(struct kvm_memory_slot *memslot,
> + unsigned long hva,
> + unsigned long map_size)
> +{
> + switch (map_size) {
> + case PUD_SIZE:
> + if (fault_supports_gstage_huge_mapping(memslot, hva, PUD_SIZE))
This patch is marked with a Fixes tag but does not include the changes
adding map_size parameter to fault_supports_gstage_huge_mapping().
I think it is better to sqash PATCH1 into this patch for completness of
this patch as Fix.
Regards,
Anup
> + return PUD_SIZE;
> + fallthrough;
> + case PMD_SIZE:
> + if (fault_supports_gstage_huge_mapping(memslot, hva, PMD_SIZE))
> + return PMD_SIZE;
> + fallthrough;
> + case PAGE_SIZE:
> + return PAGE_SIZE;
> + default:
> + return map_size;
> + }
> +}
> +
> int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
> gpa_t gpa, unsigned long hva, bool is_write,
> struct kvm_gstage_mapping *out_map)
> {
> int ret;
> kvm_pfn_t hfn;
> + bool is_hugetlb;
> bool writable;
> short vma_pageshift;
> gfn_t gfn = gpa >> PAGE_SHIFT;
> @@ -462,16 +483,23 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
> return -EFAULT;
> }
>
> - if (is_vm_hugetlb_page(vma))
> + is_hugetlb = is_vm_hugetlb_page(vma);
> + if (is_hugetlb)
> vma_pageshift = huge_page_shift(hstate_vma(vma));
> else
> vma_pageshift = PAGE_SHIFT;
> vma_pagesize = 1ULL << vma_pageshift;
> if (logging || (vma->vm_flags & VM_PFNMAP))
> vma_pagesize = PAGE_SIZE;
> + else if (is_hugetlb)
> + vma_pagesize = hugetlb_mapping_size(memslot, hva, vma_pagesize);
>
> + /*
> + * For hugetlb mappings, vma_pagesize might have been reduced from the
> + * VMA size to a smaller safe mapping size.
> + */
> if (vma_pagesize == PMD_SIZE || vma_pagesize == PUD_SIZE)
> - gfn = (gpa & huge_page_mask(hstate_vma(vma))) >> PAGE_SHIFT;
> + gfn = ALIGN_DOWN(gpa, vma_pagesize) >> PAGE_SHIFT;
>
> /*
> * Read mmu_invalidate_seq so that KVM can detect if the results of
> @@ -513,8 +541,12 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
> if (mmu_invalidate_retry(kvm, mmu_seq))
> goto out_unlock;
>
> - /* Check if we are backed by a THP and thus use block mapping if possible */
> - if (!logging && (vma_pagesize == PAGE_SIZE))
> + /*
> + * Check if we are backed by a THP and thus use block mapping if
> + * possible. Hugetlb mappings already selected their target size above,
> + * so do not promote them through the THP helper.
> + */
> + if (!logging && !is_hugetlb && vma_pagesize == PAGE_SIZE)
> vma_pagesize = transparent_hugepage_adjust(kvm, memslot, hva, &hfn, &gpa);
>
> if (writable) {
> --
> 2.43.0
>
More information about the kvm-riscv
mailing list