Correct an error in pmap_promote_pde() that may result in an errant

promotion within the kernel's address space.  Specifically,
pmap_promote_pde() is only called when the page table page (PTP) that
is referenced by the given PDE has a full "use count", i.e., its
wire_count is 512.  Although this guarantees for a user address space
that all 512 PTEs in the PTP hold valid mappings, the same is not true
of the kernel's address space.  A kernel PTP always has a use count of
512 regardless of the state of the PTEs.  Therefore,
pmap_promote_pde() should not assume (or assert) that the first PTE in
the PTP is valid.
This commit is contained in:
Alan Cox 2008-06-01 07:36:59 +00:00
parent 4ca07625aa
commit 71e26e2c0e

View File

@ -2775,22 +2775,20 @@ pmap_promote_pde(pmap_t pmap, pd_entry_t *pde, vm_offset_t va)
PMAP_LOCK_ASSERT(pmap, MA_OWNED);
firstpte = (pt_entry_t *)PHYS_TO_DMAP(*pde & PG_FRAME);
KASSERT((*firstpte & PG_V) != 0,
("pmap_promote_pde: firstpte is missing PG_V"));
if ((*firstpte & PG_A) == 0) {
newpde = *firstpte;
if ((newpde & (PG_A | PG_V)) != (PG_A | PG_V)) {
pmap_pde_p_failures++;
CTR2(KTR_PMAP, "pmap_promote_pde: failure for va %#lx"
" in pmap %p", va, pmap);
return;
}
pa = *firstpte & PG_PS_FRAME;
newpde = *firstpte;
if ((newpde & (PG_M | PG_RW)) == PG_RW)
newpde &= ~PG_RW;
/*
* Check all the ptes before promotion
*/
pa = newpde & PG_PS_FRAME;
for (pte = firstpte; pte < firstpte + NPTEPG; pte++) {
retry:
oldpte = *pte;