pmap problem in FreeBSD current
Mark Tinguely
tinguely at casselton.net
Wed Jul 8 15:51:17 UTC 2009
I forgot to CC the rest. pmap_get_pv_entry() is called from pmap_enter_locked
and can have the same UMA call that can happen in pmap_kenter_internal.
move the kmap lock protection from pmap_enter_pv() to pmap_get_pv_entry()
static void
pmap_enter_pv(struct vm_page *pg, struct pv_entry *pve, pmap_t pm,
vm_offset_t va, u_int flags)
{
- int km;
mtx_assert(&vm_page_queue_mtx, MA_OWNED);
if (pg->md.pv_kva) {
/* PMAP_ASSERT_LOCKED(pmap_kernel()); */
pve->pv_pmap = pmap_kernel();
pve->pv_va = pg->md.pv_kva;
pve->pv_flags = PVF_WRITE | PVF_UNMAN;
pg->md.pv_kva = 0;
TAILQ_INSERT_HEAD(&pg->md.pv_list, pve, pv_list);
TAILQ_INSERT_HEAD(&pm->pm_pvlist, pve, pv_plist);
- if ((km = PMAP_OWNED(pmap_kernel())))
- PMAP_UNLOCK(pmap_kernel());
vm_page_unlock_queues();
if ((pve = pmap_get_pv_entry()) == NULL)
panic("pmap_kenter_internal: no pv entries");
vm_page_lock_queues();
- if (km)
- PMAP_LOCK(pmap_kernel());
}
PMAP_ASSERT_LOCKED(pm);
pve->pv_pmap = pm;
pve->pv_va = va;
pve->pv_flags = flags;
TAILQ_INSERT_HEAD(&pg->md.pv_list, pve, pv_list);
TAILQ_INSERT_HEAD(&pm->pm_pvlist, pve, pv_plist);
pg->md.pvh_attrs |= flags & (PVF_REF | PVF_MOD);
if (pve->pv_flags & PVF_WIRED)
++pm->pm_stats.wired_count;
vm_page_flag_set(pg, PG_REFERENCED);
}
static void
pmap_free_pv_entry(pv_entry_t pv)
{
+ int km;
pv_entry_count--;
+ if ((km = PMAP_OWNED(pmap_kernel())))
+ PMAP_UNLOCK(pmap_kernel());
uma_zfree(pvzone, pv);
+ if (km)
+ PMAP_LOCK(pmap_kernel());
}
/*
* get a new pv_entry, allocating a block from the system
* when needed.
* the memory allocation is performed bypassing the malloc code
* because of the possibility of allocations at interrupt time.
*/
static pv_entry_t
pmap_get_pv_entry(void)
{
pv_entry_t ret_value;
+ int km;
pv_entry_count++;
+ if ((km = PMAP_OWNED(pmap_kernel())))
+ PMAP_UNLOCK(pmap_kernel());
if (pv_entry_count > pv_entry_high_water)
pagedaemon_wakeup();
ret_value = uma_zalloc(pvzone, M_NOWAIT);
+ if (km)
+ PMAP_LOCK(pmap_kernel());
return ret_value;
}
More information about the freebsd-arm
mailing list