Changeset View
Changeset View
Standalone View
Standalone View
sys/riscv/riscv/pmap.c
Show First 20 Lines • Show All 3,895 Lines • ▼ Show 20 Lines | if (!PMAP_TRYLOCK(pmap)) { | ||||
PMAP_LOCK(pmap); | PMAP_LOCK(pmap); | ||||
rw_wlock(lock); | rw_wlock(lock); | ||||
if (pvh_gen != pvh->pv_gen || md_gen != m->md.pv_gen) { | if (pvh_gen != pvh->pv_gen || md_gen != m->md.pv_gen) { | ||||
PMAP_UNLOCK(pmap); | PMAP_UNLOCK(pmap); | ||||
rw_wunlock(lock); | rw_wunlock(lock); | ||||
goto retry_pv_loop; | goto retry_pv_loop; | ||||
} | } | ||||
} | } | ||||
l3 = pmap_l3(pmap, pv->pv_va); | l2 = pmap_l2(pmap, pv->pv_va); | ||||
KASSERT((pmap_load(l2) & PTE_RWX) == 0, | |||||
("pmap_remove_write: found a 2mpage in page %p's pv list", | |||||
m)); | |||||
l3 = pmap_l2_to_l3(l2, pv->pv_va); | |||||
oldl3 = pmap_load(l3); | oldl3 = pmap_load(l3); | ||||
retry: | retry: | ||||
if ((oldl3 & PTE_W) != 0) { | if ((oldl3 & PTE_W) != 0) { | ||||
newl3 = oldl3 & ~(PTE_D | PTE_W); | newl3 = oldl3 & ~(PTE_D | PTE_W); | ||||
if (!atomic_fcmpset_long(l3, &oldl3, newl3)) | if (!atomic_fcmpset_long(l3, &oldl3, newl3)) | ||||
goto retry; | goto retry; | ||||
mhorne: Slightly unrelated, but do you know why the fcmpset/retry loop is required here? | |||||
mhorneAuthorUnsubmitted Done Inline ActionsForget the second question, I double checked the semantics of fcmpset. mhorne: Forget the second question, I double checked the semantics of fcmpset. | |||||
markjUnsubmitted Not Done Inline ActionsI believe it was done this way to handle races with the hardware setting PTE_D. We want to make sure we don't end up clearing PTE_D without observing that it was set. pmap_clear_modify() doesn't care so it can simply clear the bits. atomic_fcmpset_* updates the old value upon failure, in contrast with atomic_cmpset_*. markj: I believe it was done this way to handle races with the hardware setting PTE_D. We want to make… | |||||
if ((oldl3 & PTE_D) != 0) | if ((oldl3 & PTE_D) != 0) | ||||
vm_page_dirty(m); | vm_page_dirty(m); | ||||
pmap_invalidate_page(pmap, pv->pv_va); | pmap_invalidate_page(pmap, pv->pv_va); | ||||
} | } | ||||
PMAP_UNLOCK(pmap); | PMAP_UNLOCK(pmap); | ||||
} | } | ||||
rw_wunlock(lock); | rw_wunlock(lock); | ||||
vm_page_aflag_clear(m, PGA_WRITEABLE); | vm_page_aflag_clear(m, PGA_WRITEABLE); | ||||
▲ Show 20 Lines • Show All 725 Lines • Show Last 20 Lines |
Slightly unrelated, but do you know why the fcmpset/retry loop is required here? pmap_clear_modify is structured similarly but performs pmap_clear_bits on the PTE instead.
Also, can it ever advance without updating oldl3?