Correct a very old and very obscure bug: vmspace_fork() calls

pmap_copy() if the mapping is VM_INHERIT_SHARE.  Suppose the mapping
is also wired.  vmspace_fork() clears the wiring attributes in the vm
map entry but pmap_copy() copies the PG_W attribute in the PTE.  I
don't think this is catastrophic.  It blocks pmap_remove_pages() from
destroying the mapping and corrupts the pmap's wiring count.

This revision fixes the problem by changing pmap_copy() to clear the
PG_W attribute.

Reviewed by: tegge@
This commit is contained in:
alc 2006-06-27 04:28:23 +00:00
parent 2624aa9b6b
commit 49b81721c7
2 changed files with 9 additions and 6 deletions

View File

@ -2674,7 +2674,7 @@ pmap_copy(pmap_t dst_pmap, pmap_t src_pmap, vm_offset_t dst_addr, vm_size_t len,
PHYS_TO_DMAP(VM_PAGE_TO_PHYS(dstmpde));
pde = &pde[pmap_pde_index(addr)];
if (*pde == 0) {
*pde = srcptepaddr;
*pde = srcptepaddr & ~PG_W;
dst_pmap->pm_stats.resident_count +=
NBPDR / PAGE_SIZE;
} else
@ -2708,11 +2708,12 @@ pmap_copy(pmap_t dst_pmap, pmap_t src_pmap, vm_offset_t dst_addr, vm_size_t len,
pmap_try_insert_pv_entry(dst_pmap, addr,
PHYS_TO_VM_PAGE(ptetemp & PG_FRAME))) {
/*
* Clear the modified and
* Clear the wired, modified, and
* accessed (referenced) bits
* during the copy.
*/
*dst_pte = ptetemp & ~(PG_M | PG_A);
*dst_pte = ptetemp & ~(PG_W | PG_M |
PG_A);
dst_pmap->pm_stats.resident_count++;
} else
pmap_unwire_pte_hold(dst_pmap, addr,

View File

@ -2711,7 +2711,8 @@ pmap_copy(pmap_t dst_pmap, pmap_t src_pmap, vm_offset_t dst_addr, vm_size_t len,
if (srcptepaddr & PG_PS) {
if (dst_pmap->pm_pdir[ptepindex] == 0) {
dst_pmap->pm_pdir[ptepindex] = srcptepaddr;
dst_pmap->pm_pdir[ptepindex] = srcptepaddr &
~PG_W;
dst_pmap->pm_stats.resident_count +=
NBPDR / PAGE_SIZE;
}
@ -2742,11 +2743,12 @@ pmap_copy(pmap_t dst_pmap, pmap_t src_pmap, vm_offset_t dst_addr, vm_size_t len,
pmap_try_insert_pv_entry(dst_pmap, addr,
PHYS_TO_VM_PAGE(ptetemp & PG_FRAME))) {
/*
* Clear the modified and
* Clear the wired, modified, and
* accessed (referenced) bits
* during the copy.
*/
*dst_pte = ptetemp & ~(PG_M | PG_A);
*dst_pte = ptetemp & ~(PG_W | PG_M |
PG_A);
dst_pmap->pm_stats.resident_count++;
} else
pmap_unwire_pte_hold(dst_pmap, dstmpte);