Module Name: src
Committed By: skrll
Date: Thu Apr 16 09:51:57 UTC 2020
Modified Files:
src/sys/arch/hppa/hppa: pmap.c
src/sys/arch/hppa/include: types.h
Log Message:
To allow concurrent page faults on the same set of pages lock the PV
lists. From ad@ and fixed up by me.
Remove __HAVE_UNLOCKED_PMAP
To generate a diff of this commit:
cvs rdiff -u -r1.110 -r1.111 src/sys/arch/hppa/hppa/pmap.c
cvs rdiff -u -r1.27 -r1.28 src/sys/arch/hppa/include/types.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/hppa/hppa/pmap.c
diff -u src/sys/arch/hppa/hppa/pmap.c:1.110 src/sys/arch/hppa/hppa/pmap.c:1.111
--- src/sys/arch/hppa/hppa/pmap.c:1.110 Thu Apr 16 05:22:59 2020
+++ src/sys/arch/hppa/hppa/pmap.c Thu Apr 16 09:51:56 2020
@@ -1,7 +1,7 @@
-/* $NetBSD: pmap.c,v 1.110 2020/04/16 05:22:59 skrll Exp $ */
+/* $NetBSD: pmap.c,v 1.111 2020/04/16 09:51:56 skrll Exp $ */
/*-
- * Copyright (c) 2001, 2002 The NetBSD Foundation, Inc.
+ * Copyright (c) 2001, 2002, 2020 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -65,12 +65,14 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.110 2020/04/16 05:22:59 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.111 2020/04/16 09:51:56 skrll Exp $");
#include "opt_cputype.h"
#include <sys/param.h>
+#include <sys/atomic.h>
#include <sys/mutex.h>
+#include <sys/pool.h>
#include <sys/proc.h>
#include <sys/rwlock.h>
#include <sys/systm.h>
@@ -108,6 +110,14 @@ bool pmap_initialized = false;
static kmutex_t pmaps_lock;
+static union pmap_pv_locks {
+ kmutex_t lock;
+ char padding[COHERENCY_UNIT];
+} pmap_pv_locks[64] __aligned(COHERENCY_UNIT);
+
+#define PMAP_PV_LOCK(md) \
+ ((uintptr_t)(md) >> 7 & (__arraycount(pmap_pv_locks) - 1))
+
u_int hppa_prot[8];
u_int sid_counter;
@@ -140,6 +150,10 @@ static const struct uvm_pagerops pmap_pa
struct vm_page *pmap_pagealloc(struct uvm_object *, voff_t);
void pmap_pagefree(struct vm_page *);
+static inline void pmap_lock(struct pmap *);
+static inline void pmap_unlock(struct pmap *);
+static inline bool pmap_trylock(struct pmap *);
+
static inline void pmap_sdir_set(pa_space_t, volatile uint32_t *);
static inline uint32_t *pmap_sdir_get(pa_space_t);
@@ -165,6 +179,9 @@ static inline void pmap_pv_enter(struct
vaddr_t , struct vm_page *, u_int);
static inline struct pv_entry *pmap_pv_remove(struct vm_page *, pmap_t,
vaddr_t);
+static inline void pmap_pv_lock(const struct vm_page_md *md);
+static inline void pmap_pv_unlock(const struct vm_page_md *md);
+static inline bool pmap_pv_locked(const struct vm_page_md *md);
static inline void pmap_flush_page(struct vm_page *, bool);
static int pmap_check_alias(struct vm_page *, vaddr_t, pt_entry_t);
@@ -195,17 +212,47 @@ void pmap_dump_pv(paddr_t);
#define pmap_pvh_attrs(a) \
(((a) & (PVF_MOD|PVF_REF)) ^ PVF_REF)
-#define PMAP_LOCK(pm) \
- do { \
- if ((pm) != pmap_kernel()) \
- rw_enter((pm)->pm_lock, RW_WRITER); \
- } while (/*CONSTCOND*/0)
-
-#define PMAP_UNLOCK(pm) \
- do { \
- if ((pm) != pmap_kernel()) \
- rw_exit((pm)->pm_lock); \
- } while (/*CONSTCOND*/0)
+static inline void
+pmap_lock(struct pmap *pm)
+{
+
+ rw_enter(pm->pm_lock, RW_WRITER);
+}
+
+static inline void
+pmap_unlock(struct pmap *pm)
+{
+
+ rw_exit(pm->pm_lock);
+}
+
+static inline bool
+pmap_trylock(struct pmap *pm)
+{
+
+ return rw_tryenter(pm->pm_lock, RW_WRITER);
+}
+
+static inline void
+pmap_pv_lock(const struct vm_page_md *md)
+{
+
+ mutex_enter(&pmap_pv_locks[PMAP_PV_LOCK(md)].lock);
+}
+
+static inline void
+pmap_pv_unlock(const struct vm_page_md *md)
+{
+
+ mutex_exit(&pmap_pv_locks[PMAP_PV_LOCK(md)].lock);
+}
+
+static inline bool
+pmap_pv_locked(const struct vm_page_md *md)
+{
+
+ return mutex_owned(&pmap_pv_locks[PMAP_PV_LOCK(md)].lock);
+}
struct vm_page *
pmap_pagealloc(struct uvm_object *obj, voff_t off)
@@ -304,6 +351,7 @@ pmap_pde_alloc(pmap_t pm, vaddr_t va, st
UVMHIST_CALLARGS(maphist, "pm %#jx va %#jx pdep %#jx", (uintptr_t)pm,
va, (uintptr_t)pdep, 0);
+
KASSERT(pm != pmap_kernel());
KASSERT(rw_write_held(pm->pm_lock));
@@ -559,7 +607,7 @@ pmap_pv_enter(struct vm_page *pg, struct
UVMHIST_LOG(maphist, "...pdep %#jx flags %#jx",
(uintptr_t)pdep, flags, 0, 0);
- KASSERT(pm == pmap_kernel() || uvm_page_owner_locked_p(pg, true));
+ KASSERT(pmap_pv_locked(md));
pve->pv_pmap = pm;
pve->pv_va = va | flags;
@@ -578,7 +626,7 @@ pmap_pv_remove(struct vm_page *pg, pmap_
struct vm_page_md * const md = VM_PAGE_TO_MD(pg);
struct pv_entry **pve, *pv;
- KASSERT(pmap == pmap_kernel() || uvm_page_owner_locked_p(pg, true));
+ KASSERT(pmap_pv_locked(md));
for (pv = *(pve = &md->pvh_list);
pv; pv = *(pve = &(*pve)->pv_next)) {
@@ -967,6 +1015,7 @@ pmap_init(void)
{
extern void gateway_page(void);
volatile pt_entry_t *pde;
+ int i;
UVMHIST_FUNC(__func__)
UVMHIST_CALLED(maphist);
@@ -995,6 +1044,9 @@ pmap_init(void)
pmap_pte_set(pde, SYSCALLGATE, (paddr_t)&gateway_page |
PTE_PROT(TLB_GATE_PROT));
+ for (i = 0; i < __arraycount(pmap_pv_locks); i++)
+ mutex_init(&pmap_pv_locks[i].lock, MUTEX_DEFAULT, IPL_VM);
+
pmap_initialized = true;
UVMHIST_LOG(maphist, "<--- done", 0, 0, 0, 0);
@@ -1082,13 +1134,8 @@ pmap_destroy(pmap_t pmap)
struct vm_page *pg;
off_t off;
#endif
- int refs;
-
- rw_enter(pmap->pm_lock, RW_WRITER);
- refs = --pmap->pm_obj.uo_refs;
- rw_exit(pmap->pm_lock);
- if (refs > 0)
+ if (atomic_dec_uint_nv(&pmap->pm_obj.uo_refs) > 0)
return;
#ifdef DIAGNOSTIC
@@ -1101,6 +1148,7 @@ pmap_destroy(pmap_t pmap)
struct vm_page *spg;
struct pv_entry *pv, *npv;
paddr_t pa;
+ vaddr_t va;
off = pg->offset + PAGE_SIZE;
uvm_page_array_advance(&a);
@@ -1121,6 +1169,7 @@ pmap_destroy(pmap_t pmap)
continue;
struct vm_page_md * const md = VM_PAGE_TO_MD(spg);
+ pmap_pv_lock(md);
for (pv = md->pvh_list; pv != NULL; pv = npv) {
npv = pv->pv_next;
if (pv->pv_pmap != pmap)
@@ -1129,9 +1178,14 @@ pmap_destroy(pmap_t pmap)
UVMHIST_LOG(maphist, " %#jx", pv->pv_va, 0, 0,
0);
- pmap_remove(pmap, pv->pv_va & PV_VAMASK,
- (pv->pv_va & PV_VAMASK) + PAGE_SIZE);
+ va = pv->pv_va & PV_VAMASK;
+ pmap_pv_unlock(md);
+ pmap_remove(pmap, va, va + PAGE_SIZE);
+ pmap_pv_lock(md);
+ /* List may have changed: restart. */
+ npv = md->pvh_list;
}
+ pmap_pv_unlock(md);
}
}
rw_exit(pmap->pm_lock);
@@ -1156,9 +1210,7 @@ pmap_reference(pmap_t pmap)
UVMHIST_FUNC(__func__)
UVMHIST_CALLARGS(maphist, "pm %#jx", (uintptr_t)pmap, 0, 0, 0);
- rw_enter(pmap->pm_lock, RW_WRITER);
- pmap->pm_obj.uo_refs++;
- rw_exit(pmap->pm_lock);
+ atomic_inc_uint(&pmap->pm_obj.uo_refs);
}
@@ -1207,12 +1259,12 @@ pmap_enter(pmap_t pmap, vaddr_t va, padd
(uintptr_t)pmap, va, pa, prot);
UVMHIST_LOG(maphist, "...flags %#jx", flags, 0, 0, 0);
- PMAP_LOCK(pmap);
+ pmap_lock(pmap);
if (!(pde = pmap_pde_get(pmap->pm_pdir, va)) &&
!(pde = pmap_pde_alloc(pmap, va, &ptp))) {
if (flags & PMAP_CANFAIL) {
- PMAP_UNLOCK(pmap);
+ pmap_unlock(pmap);
return (ENOMEM);
}
@@ -1238,10 +1290,12 @@ pmap_enter(pmap_t pmap, vaddr_t va, padd
}
if (pg != NULL) {
- pve = pmap_pv_remove(pg, pmap, va);
-
struct vm_page_md * const md = VM_PAGE_TO_MD(pg);
+
+ pmap_pv_lock(md);
+ pve = pmap_pv_remove(pg, pmap, va);
md->pvh_attrs |= pmap_pvh_attrs(pte);
+ pmap_pv_unlock(md);
}
} else {
UVMHIST_LOG(maphist, "new mapping %#jx -> %#jx",
@@ -1255,9 +1309,11 @@ pmap_enter(pmap_t pmap, vaddr_t va, padd
}
if (pmap_initialized && (pg = PHYS_TO_VM_PAGE(pa))) {
+ struct vm_page_md * const md = VM_PAGE_TO_MD(pg);
+
if (!pve && !(pve = pmap_pv_alloc())) {
if (flags & PMAP_CANFAIL) {
- PMAP_UNLOCK(pmap);
+ pmap_unlock(pmap);
return (ENOMEM);
}
panic("%s: no pv entries available", __func__);
@@ -1265,7 +1321,9 @@ pmap_enter(pmap_t pmap, vaddr_t va, padd
pte |= PTE_PROT(pmap_prot(pmap, prot));
if (pmap_check_alias(pg, va, pte))
pmap_page_remove(pg);
+ pmap_pv_lock(md);
pmap_pv_enter(pg, pve, pmap, va, ptp, 0);
+ pmap_pv_unlock(md);
} else if (pve) {
pmap_pv_free(pve);
}
@@ -1291,7 +1349,7 @@ enter:
pte |= PTE_PROT(TLB_WIRED);
pmap_pte_set(pde, va, pte);
- PMAP_UNLOCK(pmap);
+ pmap_unlock(pmap);
UVMHIST_LOG(maphist, "<--- done (0)", 0, 0, 0, 0);
@@ -1308,7 +1366,6 @@ enter:
void
pmap_remove(pmap_t pmap, vaddr_t sva, vaddr_t eva)
{
-
UVMHIST_FUNC(__func__);
UVMHIST_CALLARGS(maphist, "sva %#jx eva %#jx", sva, eva, 0, 0);
@@ -1319,7 +1376,7 @@ pmap_remove(pmap_t pmap, vaddr_t sva, va
vaddr_t pdemask;
int batch;
- PMAP_LOCK(pmap);
+ pmap_lock(pmap);
for (batch = 0; sva < eva; sva += PAGE_SIZE) {
pdemask = sva & PDE_MASK;
@@ -1349,8 +1406,10 @@ pmap_remove(pmap_t pmap, vaddr_t sva, va
struct vm_page_md * const md =
VM_PAGE_TO_MD(pg);
+ pmap_pv_lock(md);
pve = pmap_pv_remove(pg, pmap, sva);
md->pvh_attrs |= pmap_pvh_attrs(pte);
+ pmap_pv_unlock(md);
if (pve != NULL)
pmap_pv_free(pve);
@@ -1365,7 +1424,7 @@ pmap_remove(pmap_t pmap, vaddr_t sva, va
}
}
- PMAP_UNLOCK(pmap);
+ pmap_unlock(pmap);
UVMHIST_LOG(maphist, "<--- done", 0, 0, 0, 0);
}
@@ -1385,7 +1444,7 @@ pmap_write_protect(pmap_t pmap, vaddr_t
sva = trunc_page(sva);
pteprot = PTE_PROT(pmap_prot(pmap, prot));
- PMAP_LOCK(pmap);
+ pmap_lock(pmap);
for (pdemask = 1; sva < eva; sva += PAGE_SIZE) {
if (pdemask != (sva & PDE_MASK)) {
@@ -1410,7 +1469,9 @@ pmap_write_protect(pmap_t pmap, vaddr_t
struct vm_page_md * const md =
VM_PAGE_TO_MD(pg);
+ pmap_pv_lock(md);
md->pvh_attrs |= pmap_pvh_attrs(pte);
+ pmap_pv_unlock(md);
}
/* Add TLB_EXECUTE if PVF_EXEC ??? */
@@ -1421,7 +1482,7 @@ pmap_write_protect(pmap_t pmap, vaddr_t
}
}
- PMAP_UNLOCK(pmap);
+ pmap_unlock(pmap);
}
void
@@ -1438,28 +1499,62 @@ pmap_page_remove(struct vm_page *pg)
return;
}
+ restart:
+ pmap_pv_lock(md);
pvp = &md->pvh_list;
for (pve = md->pvh_list; pve; pve = npve) {
pmap_t pmap = pve->pv_pmap;
vaddr_t va = pve->pv_va & PV_VAMASK;
volatile pt_entry_t *pde;
pt_entry_t pte;
+ bool locked;
- PMAP_LOCK(pmap);
-
- pde = pmap_pde_get(pmap->pm_pdir, va);
- pte = pmap_pte_get(pde, va);
+ UVMHIST_LOG(maphist, "... pm %#jx va %#jx", (uintptr_t)pmap,
+ va, 0, 0);
npve = pve->pv_next;
- /*
- * If this was an unmanaged mapping, it must be preserved. Move
- * it back on the list and advance the end-of-list pointer.
- */
if (pve->pv_va & PV_KENTER) {
+ /*
+ * This is an unmanaged mapping, it must be preserved.
+ * Move it back on the list and advance the end-of-list
+ * pointer.
+ */
*pvp = pve;
pvp = &pve->pv_next;
- } else
+
+ /* Get the pte for this mapping */
+ pde = pmap_pde_get(pmap->pm_pdir, va);
+ pte = pmap_pte_get(pde, va);
+ } else {
+ /*
+ * We have to seamlessly get a hold on the pmap's lock
+ * while holding the PV head lock, to know that the
+ * mapping is still in place and we can operate on it.
+ * If that can't be had, drop the PV head lock, wait
+ * for the pmap's lock to become available, and then
+ * try again.
+ */
+ UVMHIST_LOG(maphist, "... pm %#jx va %#jx... removing",
+ (uintptr_t)pmap, va, 0, 0);
+
+ pmap_reference(pmap);
+ locked = pmap_trylock(pmap);
+ if (!locked) {
+ pmap_pv_unlock(md);
+ pmap_lock(pmap);
+ /* nothing */
+ pmap_unlock(pmap);
+ pmap_destroy(pmap);
+
+ UVMHIST_LOG(maphist, "... failed lock", 0, 0, 0,
+ 0);
+ goto restart;
+ }
+ pde = pmap_pde_get(pmap->pm_pdir, va);
+ pte = pmap_pte_get(pde, va);
+
md->pvh_attrs |= pmap_pvh_attrs(pte);
+ }
pmap_pte_flush(pmap, va, pte);
if (pte & PTE_PROT(TLB_WIRED))
@@ -1468,13 +1563,21 @@ pmap_page_remove(struct vm_page *pg)
if (!(pve->pv_va & PV_KENTER)) {
pmap_pte_set(pde, va, 0);
+
+ pmap_pv_unlock(md);
pmap_pv_free(pve);
+ pmap_unlock(pmap);
+ pmap_destroy(pmap);
+ UVMHIST_LOG(maphist, "... removed", 0, 0, 0, 0);
+ *pvp = npve;
+ goto restart;
}
- PMAP_UNLOCK(pmap);
}
md->pvh_attrs &= ~PVF_EXEC;
*pvp = NULL;
+ pmap_pv_unlock(md);
+
UVMHIST_LOG(maphist, "<--- done", 0, 0, 0, 0);
}
@@ -1497,7 +1600,7 @@ pmap_unwire(pmap_t pmap, vaddr_t va)
volatile pt_entry_t *pde;
pt_entry_t pte = 0;
- PMAP_LOCK(pmap);
+ pmap_lock(pmap);
if ((pde = pmap_pde_get(pmap->pm_pdir, va))) {
pte = pmap_pte_get(pde, va);
@@ -1509,7 +1612,7 @@ pmap_unwire(pmap_t pmap, vaddr_t va)
pmap_pte_set(pde, va, pte);
}
}
- PMAP_UNLOCK(pmap);
+ pmap_unlock(pmap);
UVMHIST_LOG(maphist, "<--- done", 0, 0, 0, 0);
}
@@ -1530,6 +1633,7 @@ pmap_changebit(struct vm_page *pg, u_int
KASSERT((clear & ~(PVF_MOD|PVF_WRITE|PVF_UNCACHEABLE)) == 0);
/* preserve other bits */
+ pmap_pv_lock(md);
res = md->pvh_attrs & (set | clear);
md->pvh_attrs ^= res;
@@ -1562,6 +1666,7 @@ pmap_changebit(struct vm_page *pg, u_int
}
}
}
+ pmap_pv_unlock(md);
return ((res & (clear | set)) != 0);
}
@@ -1578,6 +1683,7 @@ pmap_testbit(struct vm_page *pg, u_int b
pt_entry_t pte;
int ret;
+ pmap_pv_lock(md);
for (pve = md->pvh_list; !(md->pvh_attrs & bit) && pve;
pve = pve->pv_next) {
pmap_t pm = pve->pv_pmap;
@@ -1589,6 +1695,7 @@ pmap_testbit(struct vm_page *pg, u_int b
md->pvh_attrs |= pmap_pvh_attrs(pte);
}
ret = ((md->pvh_attrs & bit) != 0);
+ pmap_pv_unlock(md);
return ret;
}
@@ -1608,9 +1715,14 @@ pmap_extract(pmap_t pmap, vaddr_t va, pa
pt_entry_t pte;
- PMAP_LOCK(pmap);
- pte = pmap_vp_find(pmap, va);
- PMAP_UNLOCK(pmap);
+
+ if (pmap != pmap_kernel()) {
+ pmap_lock(pmap);
+ pte = pmap_vp_find(pmap, va);
+ pmap_unlock(pmap);
+ } else {
+ pte = pmap_vp_find(pmap, va);
+ }
if (pte) {
if (pap)
@@ -1772,6 +1884,7 @@ pmap_kenter_pa(vaddr_t va, paddr_t pa, v
if (pg != NULL) {
KASSERT(pa < HPPA_IOBEGIN);
+ struct vm_page_md * const md = VM_PAGE_TO_MD(pg);
struct pv_entry *pve;
pve = pmap_pv_alloc();
@@ -1783,7 +1896,9 @@ pmap_kenter_pa(vaddr_t va, paddr_t pa, v
if (pmap_check_alias(pg, va, pte))
pmap_page_remove(pg);
+ pmap_pv_lock(md);
pmap_pv_enter(pg, pve, pmap_kernel(), va, NULL, PV_KENTER);
+ pmap_pv_unlock(md);
}
pmap_pte_set(pde, va, pte);
@@ -1844,7 +1959,11 @@ pmap_kremove(vaddr_t va, vsize_t size)
pg = pmap_initialized ? PHYS_TO_VM_PAGE(PTE_PAGE(pte)) : NULL;
if (pg != NULL) {
+ struct vm_page_md * const md = VM_PAGE_TO_MD(pg);
+
+ pmap_pv_lock(md);
pve = pmap_pv_remove(pg, pmap, va);
+ pmap_pv_unlock(md);
if (pve != NULL)
pmap_pv_free(pve);
Index: src/sys/arch/hppa/include/types.h
diff -u src/sys/arch/hppa/include/types.h:1.27 src/sys/arch/hppa/include/types.h:1.28
--- src/sys/arch/hppa/include/types.h:1.27 Sun Mar 22 17:33:58 2020
+++ src/sys/arch/hppa/include/types.h Thu Apr 16 09:51:57 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: types.h,v 1.27 2020/03/22 17:33:58 ad Exp $ */
+/* $NetBSD: types.h,v 1.28 2020/04/16 09:51:57 skrll Exp $ */
/* $OpenBSD: types.h,v 1.6 2001/08/11 01:58:34 art Exp $ */
@@ -103,7 +103,4 @@ extern const char __CONCAT(name,_ras_sta
#define __HAVE_MM_MD_DIRECT_MAPPED_PHYS
#define __HAVE_MM_MD_KERNACC
-/* XXX temporary */
-#define __HAVE_UNLOCKED_PMAP
-
#endif /* _HPPA_TYPES_H_ */