Messages in this thread |  | | From | Anup Patel <> | | Date | Sun, 4 Oct 2026 03:00:50 +0530 | | Subject | Re: [PATCH v4 RESEND 1/5] KVM: riscv: Avoid overwriting G-stage tables with huge leaves |
| |
On Sat, Aug 15, 2026 at 4:01 PM Jinyu Tang <jinyu.tang@linux.dev> wrote: > > RISC-V KVM can overwrite an existing G-stage table entry when > installing a huge leaf mapping. If the target huge range already has a > lower-level page table, kvm_riscv_gstage_set_pte() can replace the > non-leaf entry with a leaf PTE and disconnect the lower-level page > table. > > Reject replacing a valid table entry with a leaf PTE. If huge-page > installation hits such a conflict, fall back to a 4K mapping for the > original faulting GPA in the MMU fault path, where the original GPA and > HFN are still available. > > Suggested-by: Sashiko <sashiko-bot@kernel.org> > Fixes: 9d05c1fee837 ("RISC-V: KVM: Implement stage2 page table programming") > Signed-off-by: Jinyu Tang <jinyu.tang@linux.dev> > --- > arch/riscv/kvm/gstage.c | 6 ++++++ > arch/riscv/kvm/mmu.c | 24 +++++++++++++++++++++++- > 2 files changed, 29 insertions(+), 1 deletion(-) > > diff --git a/arch/riscv/kvm/gstage.c b/arch/riscv/kvm/gstage.c > index e5002cb9cbef..54d45addf18f 100644 > --- a/arch/riscv/kvm/gstage.c > +++ b/arch/riscv/kvm/gstage.c > @@ -174,6 +174,12 @@ int kvm_riscv_gstage_set_pte(struct kvm_gstage *gstage, > > if (pte_val(*ptep) != pte_val(map->pte)) { > bool was_invalid = !pte_val(*ptep); > + > + /* Avoid replacing an existing lower-level table with a leaf mapping. */ > + if (!gstage_pte_leaf(ptep) && !was_invalid && > + gstage_pte_leaf(&map->pte)) > + return -EEXIST; > + > set_pte(ptep, map->pte); > if (gstage_pte_leaf(ptep) && > !(was_invalid && riscv_has_extension_unlikely(RISCV_ISA_EXT_SVVPTC))) > diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c > index 6035b5ec9503..bfd6168ebe30 100644 > --- a/arch/riscv/kvm/mmu.c > +++ b/arch/riscv/kvm/mmu.c > @@ -625,10 +625,11 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot, > struct kvm_gstage_mapping *out_map) > { > int ret; > - kvm_pfn_t hfn; > + kvm_pfn_t fault_hfn, hfn; > bool is_hugetlb; > bool writable; > unsigned int vma_pageshift; > + gpa_t fault_gpa = gpa; > gfn_t gfn = gpa >> PAGE_SHIFT; > struct vm_area_struct *vma; > struct kvm *kvm = vcpu->kvm; > @@ -709,6 +710,7 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot, > } > if (is_error_noslot_pfn(hfn)) > return -EFAULT; > + fault_hfn = hfn + ((fault_gpa >> PAGE_SHIFT) - gfn); > > /* > * If logging is active then we allow writable pages only > @@ -734,9 +736,29 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot, > mark_page_dirty_in_slot(kvm, memslot, gfn); > ret = kvm_riscv_gstage_map_page(&gstage, pcache, gpa, hfn << PAGE_SHIFT, > vma_pagesize, false, true, out_map); > + if (ret == -EEXIST) { > + /* > + * Retry at 4K granularity for the original faulting GPA > + * when a huge leaf cannot replace an existing table. > + */ > + ret = kvm_riscv_gstage_map_page(&gstage, pcache, fault_gpa, > + fault_hfn << PAGE_SHIFT, > + PAGE_SIZE, false, true, > + out_map); > + }
If you were attempting to map 1G hugepage then you should first try 2M and not 4K. This patch needs more work.
> } else { > ret = kvm_riscv_gstage_map_page(&gstage, pcache, gpa, hfn << PAGE_SHIFT, > vma_pagesize, true, true, out_map); > + if (ret == -EEXIST) { > + /* > + * Retry at 4K granularity for the original faulting GPA > + * when a huge leaf cannot replace an existing table. > + */ > + ret = kvm_riscv_gstage_map_page(&gstage, pcache, fault_gpa, > + fault_hfn << PAGE_SHIFT, > + PAGE_SIZE, true, true, > + out_map); > + } > } > > if (ret) > -- > 2.43.0 >
Regards, Anup
|  |