Date: Wed, 8 Jul 2009 10:51:16 -0500 (CDT) From: Mark Tinguely <tinguely@casselton.net> To: mih@semihalf.com, tinguely@casselton.net Cc: freebsd-arm@freebsd.org Subject: Re: pmap problem in FreeBSD current Message-ID: <200907081551.n68FpFeM073177@casselton.net> In-Reply-To: <200907081507.n68F7Vsu070524@casselton.net>
next in thread | previous in thread | raw e-mail | index | archive | help
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; }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200907081551.n68FpFeM073177>