riscv: handle kernel PTE edge-case in pmap_enter_l2()
Page table pages are never freed from the kernel pmap, instead they are zeroed when a range is unmapped. This allows future mappings to be constructed more quickly. Detect this scenario in pmap_enter_l2(), so we don't fail to create a superpage mapping when the 2MB range is actually available. Reviewed by: markj MFC after: 1 week Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D36885
This commit is contained in:
parent
99fe523778
commit
1f9cc5ffc5
@ -3146,6 +3146,24 @@ pmap_enter_2mpage(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot,
|
||||
PMAP_ENTER_NOREPLACE | PMAP_ENTER_NORECLAIM, NULL, lockp));
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if every page table entry in the specified page table is
|
||||
* zero.
|
||||
*/
|
||||
static bool
|
||||
pmap_every_pte_zero(vm_paddr_t pa)
|
||||
{
|
||||
pt_entry_t *pt_end, *pte;
|
||||
|
||||
KASSERT((pa & PAGE_MASK) == 0, ("pa is misaligned"));
|
||||
pte = (pt_entry_t *)PHYS_TO_DMAP(pa);
|
||||
for (pt_end = pte + Ln_ENTRIES; pte < pt_end; pte++) {
|
||||
if (*pte != 0)
|
||||
return (false);
|
||||
}
|
||||
return (true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tries to create the specified 2MB page mapping. Returns KERN_SUCCESS if
|
||||
* the mapping was created, and one of KERN_FAILURE, KERN_NO_SPACE, or
|
||||
@ -3190,7 +3208,8 @@ pmap_enter_l2(pmap_t pmap, vm_offset_t va, pd_entry_t new_l2, u_int flags,
|
||||
"pmap_enter_l2: no space for va %#lx"
|
||||
" in pmap %p", va, pmap);
|
||||
return (KERN_NO_SPACE);
|
||||
} else {
|
||||
} else if (va < VM_MAXUSER_ADDRESS ||
|
||||
!pmap_every_pte_zero(L2PTE_TO_PHYS(oldl2))) {
|
||||
l2pg->ref_count--;
|
||||
CTR2(KTR_PMAP, "pmap_enter_l2:"
|
||||
" failed to replace existing mapping"
|
||||
|
Loading…
Reference in New Issue
Block a user