diff options
author | kib <kib@FreeBSD.org> | 2013-09-24 12:26:43 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2013-09-24 12:26:43 +0000 |
commit | 28393634c52c62351cee5193ebe7cb3b9a86117f (patch) | |
tree | 26310c8cce0bbee1499ed6cce7fb5947adb5efd4 /sys/amd64 | |
parent | 2346155b1e1ec03137ae64ce08cfe2d7803df47e (diff) | |
download | FreeBSD-src-28393634c52c62351cee5193ebe7cb3b9a86117f.zip FreeBSD-src-28393634c52c62351cee5193ebe7cb3b9a86117f.tar.gz |
Use the pv lists generation count to read-lock the pvh_global_lock in
pmap_clear_modify().
Noted and reviewed by: alc
Tested by: pho
Sponsored by: The FreeBSD Foundation
Approved by: re (marius)
Diffstat (limited to 'sys/amd64')
-rw-r--r-- | sys/amd64/amd64/pmap.c | 35 |
1 files changed, 30 insertions, 5 deletions
diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c index f4e8d67..e4a662a 100644 --- a/sys/amd64/amd64/pmap.c +++ b/sys/amd64/amd64/pmap.c @@ -5314,7 +5314,9 @@ pmap_clear_modify(vm_page_t m) pv_entry_t next_pv, pv; pd_entry_t oldpde, *pde; pt_entry_t oldpte, *pte; + struct rwlock *lock; vm_offset_t va; + int md_gen, pvh_gen; KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_clear_modify: page %p is not managed", m)); @@ -5329,18 +5331,30 @@ pmap_clear_modify(vm_page_t m) */ if ((m->aflags & PGA_WRITEABLE) == 0) return; - rw_wlock(&pvh_global_lock); + rw_rlock(&pvh_global_lock); + lock = VM_PAGE_TO_PV_LIST_LOCK(m); + rw_wlock(lock); +restart: if ((m->flags & PG_FICTITIOUS) != 0) goto small_mappings; pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m)); TAILQ_FOREACH_SAFE(pv, &pvh->pv_list, pv_next, next_pv) { pmap = PV_PMAP(pv); - PMAP_LOCK(pmap); + if (!PMAP_TRYLOCK(pmap)) { + pvh_gen = pvh->pv_gen; + rw_wunlock(lock); + PMAP_LOCK(pmap); + rw_wlock(lock); + if (pvh_gen != pvh->pv_gen) { + PMAP_UNLOCK(pmap); + goto restart; + } + } va = pv->pv_va; pde = pmap_pde(pmap, va); oldpde = *pde; if ((oldpde & PG_RW) != 0) { - if (pmap_demote_pde(pmap, pde, va)) { + if (pmap_demote_pde_locked(pmap, pde, va, &lock)) { if ((oldpde & PG_W) == 0) { /* * Write protect the mapping to a @@ -5367,7 +5381,17 @@ pmap_clear_modify(vm_page_t m) small_mappings: TAILQ_FOREACH(pv, &m->md.pv_list, pv_next) { pmap = PV_PMAP(pv); - PMAP_LOCK(pmap); + if (!PMAP_TRYLOCK(pmap)) { + md_gen = m->md.pv_gen; + pvh_gen = pvh->pv_gen; + rw_wunlock(lock); + PMAP_LOCK(pmap); + rw_wlock(lock); + if (pvh_gen != pvh->pv_gen || md_gen != m->md.pv_gen) { + PMAP_UNLOCK(pmap); + goto restart; + } + } pde = pmap_pde(pmap, pv->pv_va); KASSERT((*pde & PG_PS) == 0, ("pmap_clear_modify: found" " a 2mpage in page %p's pv list", m)); @@ -5378,7 +5402,8 @@ small_mappings: } PMAP_UNLOCK(pmap); } - rw_wunlock(&pvh_global_lock); + rw_wunlock(lock); + rw_runlock(&pvh_global_lock); } /* |