Subject: Re: Any clues?
To: John Klos <john@ziaspace.com>
From: Chuck Silvers <chuq@chuq.com>
List: port-macppc
Date: 08/15/2004 08:45:56
--liOOAslEiF7prFVr
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

hi,

this happens because the machine runs out of memory and the ppc pmap
doesn't know how to reclaim another active pvo entry.
try the attached patch.

-Chuck


On Tue, Aug 10, 2004 at 10:53:18PM -0400, John Klos wrote:
> Hi,
> 
> Just saw this today when I had 8179 processes running at the same time. 
> NetBSD 2.0 from a few days ago.
> 
> Aug 11 02:44:25 lain /netbsd: proc: table is full - increase kern.maxproc 
> or NP
> OC
> panic: pmap_pvo_enter: failed
> Begin traceback...
> 0xda0178b0: at pmap_pvo_enter+0x334
> 0xda017900: at pmap_enter+0x198
> 0xda017930: at ubc_fault+0x37c
> 0xda0179e0: at uvm_fault+0x1068
> 0xda017b10: at trap+0x2c0
> 0xda017b90: kernel DSI read trap @ 0xd57f4000 by memcpy+0x88: srr1=0x9032   
> 0
>             r1=0xda017c50 cr=0x40000024 xer=0x20000000 ctr=0xb6 
> dsisr=0x4000000
> 0xda017c50: at ddbstk+0x1fa4
> 0xda017c60: at pmap_pvo_remove+0x230
> 0xda017cf0: at uiomove+0x1b0
> 0xda017d20: at ffs_read+0x4ac
> 0xda017dc0: at vn_read+0x114
> 0xda017e40: at dofileread+0xb8
> 0xda017eb0: at sys_read+0x8c
> 0xda017ed0: at syscall_plain+0xe0
> 0xda017f40: user SC trap #3 by 0x41873498: srr1=0xd032
>             r1=0xffffd6b0 cr=0x20000044 xer=0 ctr=0x41901684
> End traceback...

--liOOAslEiF7prFVr
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="diff.pmap-ppc-pvoreclaim"

Index: src/sys/arch/powerpc/oea/pmap.c
===================================================================
RCS file: /cvsroot/src/sys/arch/powerpc/oea/pmap.c,v
retrieving revision 1.24
diff -u -p -r1.24 pmap.c
--- src/sys/arch/powerpc/oea/pmap.c	9 Jun 2004 19:30:57 -0000	1.24
+++ src/sys/arch/powerpc/oea/pmap.c	15 Aug 2004 15:44:14 -0000
@@ -243,10 +243,10 @@ STATIC void pmap_pvo_check(const struct 
 STATIC int pmap_pte_insert(int, struct pte *);
 STATIC int pmap_pvo_enter(pmap_t, struct pool *, struct pvo_head *,
 	vaddr_t, paddr_t, register_t, int);
-STATIC void pmap_pvo_remove(struct pvo_entry *, int);
+STATIC void pmap_pvo_remove(struct pvo_entry *, int, boolean_t);
 STATIC struct pvo_entry *pmap_pvo_find_va(pmap_t, vaddr_t, int *); 
 STATIC volatile struct pte *pmap_pvo_to_pte(const struct pvo_entry *, int);
-#define pmap_pvo_reclaim(pm)	NULL
+STATIC struct pvo_entry *pmap_pvo_reclaim(struct pmap *);
 STATIC void pvo_set_exec(struct pvo_entry *);
 STATIC void pvo_clear_exec(struct pvo_entry *);
 
@@ -255,6 +255,8 @@ STATIC void tlbia(void);
 STATIC void pmap_release(pmap_t);
 STATIC void *pmap_boot_find_memory(psize_t, psize_t, int);
 
+static uint32_t pmap_reclaim_nextidx;
+
 #define	VSID_NBPW	(sizeof(uint32_t) * 8)
 static uint32_t pmap_vsid_bitmap[NPMAPS / VSID_NBPW];
 
@@ -1489,6 +1491,33 @@ pmap_pvo_check(const struct pvo_entry *p
 #endif /* DEBUG || PMAPCHECK */
 
 /*
+ * Search the PVO table looking for a non-wired entry for the given pmap.
+ * If we find one, remove it and return it.
+ */
+
+struct pvo_entry *
+pmap_pvo_reclaim(struct pmap *pm)
+{
+	struct pvo_tqhead *pvoh;
+	struct pvo_entry *pvo;
+	uint32_t idx, endidx;
+
+	endidx = pmap_reclaim_nextidx++;
+	for (idx = (endidx + 1) & pmap_pteg_mask; idx != endidx;
+	     idx = (idx + 1) & pmap_pteg_mask) {
+		pvoh = &pmap_pvo_table[idx];
+		TAILQ_FOREACH(pvo, pvoh, pvo_olink) {
+			if (pvo->pvo_pmap == pm &&
+			    (pvo->pvo_vaddr & PVO_WIRED) == 0) {
+				pmap_pvo_remove(pvo, -1, FALSE);
+				return pvo;
+			}
+		}
+	}
+	return NULL;
+}
+
+/*
  * This returns whether this is the first mapping of a page.
  */
 int
@@ -1539,7 +1568,7 @@ pmap_pvo_enter(pmap_t pm, struct pool *p
 			}
 #endif
 			PMAPCOUNT(mappings_replaced);
-			pmap_pvo_remove(pvo, -1);
+			pmap_pvo_remove(pvo, -1, TRUE);
 			break;
 		}
 	}
@@ -1562,6 +1591,7 @@ pmap_pvo_enter(pmap_t pm, struct pool *p
 			return ENOMEM;
 		}
 	}
+
 	pvo->pvo_vaddr = va;
 	pvo->pvo_pmap = pm;
 	pvo->pvo_vaddr &= ~ADDR_POFF;
@@ -1626,7 +1656,7 @@ pmap_pvo_enter(pmap_t pm, struct pool *p
 }
 
 void
-pmap_pvo_remove(struct pvo_entry *pvo, int pteidx)
+pmap_pvo_remove(struct pvo_entry *pvo, int pteidx, boolean_t free)
 {
 	volatile struct pte *pt;
 	int ptegidx;
@@ -1697,8 +1727,10 @@ pmap_pvo_remove(struct pvo_entry *pvo, i
 	 */
 	LIST_REMOVE(pvo, pvo_vlink);
 	TAILQ_REMOVE(&pmap_pvo_table[ptegidx], pvo, pvo_olink);
-	pool_put(pvo->pvo_vaddr & PVO_MANAGED
-	    ? &pmap_mpvo_pool : &pmap_upvo_pool, pvo);
+	if (free) {
+		pool_put(pvo->pvo_vaddr & PVO_MANAGED ? &pmap_mpvo_pool :
+			 &pmap_upvo_pool, pvo);
+	}
 #if defined(DIAGNOSTIC) || defined(DEBUG) || defined(PMAPCHECK)
 	pmap_pvo_remove_depth--;
 #endif
@@ -1933,7 +1965,7 @@ pmap_remove(pmap_t pm, vaddr_t va, vaddr
 	for (; va < endva; va += PAGE_SIZE) {
 		pvo = pmap_pvo_find_va(pm, va, &pteidx);
 		if (pvo != NULL) {
-			pmap_pvo_remove(pvo, pteidx);
+			pmap_pvo_remove(pvo, pteidx, TRUE);
 		}
 	}
 	pmap_interrupts_restore(msr);
@@ -2125,7 +2157,7 @@ pmap_page_protect(struct vm_page *pg, vm
 		 * Downgrading to no mapping at all, we just remove the entry.
 		 */
 		if ((prot & VM_PROT_READ) == 0) {
-			pmap_pvo_remove(pvo, -1);
+			pmap_pvo_remove(pvo, -1, TRUE);
 			continue;
 		} 
 

--liOOAslEiF7prFVr--