Skip site navigation (1)Skip section navigation (2)
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>