diff options
author | alc <alc@FreeBSD.org> | 2006-06-27 04:28:23 +0000 |
---|---|---|
committer | alc <alc@FreeBSD.org> | 2006-06-27 04:28:23 +0000 |
commit | 49b81721c75aa7d09b4439821e3d832e5f4cc900 (patch) | |
tree | 5f301ab478f99906131d417e3ced409158979b03 /sys/amd64 | |
parent | 2624aa9b6bf3b6e21b0e1c590665aaae07ea928d (diff) | |
download | FreeBSD-src-49b81721c75aa7d09b4439821e3d832e5f4cc900.zip FreeBSD-src-49b81721c75aa7d09b4439821e3d832e5f4cc900.tar.gz |
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@
Diffstat (limited to 'sys/amd64')
-rw-r--r-- | sys/amd64/amd64/pmap.c | 7 |
1 files changed, 4 insertions, 3 deletions
diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c index 2d82790..dd05e18 100644 --- a/sys/amd64/amd64/pmap.c +++ b/sys/amd64/amd64/pmap.c @@ -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, |