From owner-svn-src-projects@FreeBSD.ORG Tue Jun 15 21:46:07 2010 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 98B20106564A; Tue, 15 Jun 2010 21:46:07 +0000 (UTC) (envelope-from nwhitehorn@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 880E88FC0A; Tue, 15 Jun 2010 21:46:07 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o5FLk7Q3002715; Tue, 15 Jun 2010 21:46:07 GMT (envelope-from nwhitehorn@svn.freebsd.org) Received: (from nwhitehorn@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o5FLk79o002713; Tue, 15 Jun 2010 21:46:07 GMT (envelope-from nwhitehorn@svn.freebsd.org) Message-Id: <201006152146.o5FLk79o002713@svn.freebsd.org> From: Nathan Whitehorn Date: Tue, 15 Jun 2010 21:46:07 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r209220 - projects/ppc64/sys/powerpc/aim X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 15 Jun 2010 21:46:07 -0000 Author: nwhitehorn Date: Tue Jun 15 21:46:07 2010 New Revision: 209220 URL: http://svn.freebsd.org/changeset/base/209220 Log: Implement a page table spilling mechanism to allow the kernel to continue when user-space applications have filled all the slots in a PTEG. This relies on VM gracefully remapping pages when it gets faults on pages it thinks are mapped already, which it seems to do in limited forkbomb-based testing. Comments by alc appreciated before merging to HEAD. Modified: projects/ppc64/sys/powerpc/aim/mmu_oea64.c Modified: projects/ppc64/sys/powerpc/aim/mmu_oea64.c ============================================================================== --- projects/ppc64/sys/powerpc/aim/mmu_oea64.c Tue Jun 15 21:34:57 2010 (r209219) +++ projects/ppc64/sys/powerpc/aim/mmu_oea64.c Tue Jun 15 21:46:07 2010 (r209220) @@ -1024,6 +1024,8 @@ moea64_bootstrap(mmu_t mmup, vm_offset_t while (moea64_pteg_count < physmem) moea64_pteg_count <<= 1; + + moea64_pteg_count >>= 1; #endif /* PTEGCOUNT */ size = moea64_pteg_count * sizeof(struct lpteg); @@ -2625,6 +2627,8 @@ moea64_pvo_to_pte(const struct pvo_entry { struct lpte *pt; + ASSERT_TABLE_LOCK(); + /* * If we haven't been supplied the ptegidx, calculate it. */ @@ -2652,6 +2656,10 @@ moea64_pvo_to_pte(const struct pvo_entry "pvo but no valid pte", pvo); } + /* If the PTEG index is not set, then there is no page table entry */ + if (!PVO_PTEGIDX_ISSET(pvo)) + return (NULL); + if ((pt->pte_hi ^ (pvo->pvo_pte.lpte.pte_hi & ~LPTE_VALID)) == LPTE_VALID) { if ((pvo->pvo_pte.lpte.pte_hi & LPTE_VALID) == 0) { @@ -2679,10 +2687,47 @@ moea64_pvo_to_pte(const struct pvo_entry return (NULL); } +static __inline int +moea64_pte_spillable_ident(u_int ptegidx) +{ + struct lpte *pt; + int i, j, k; + + /* Start at a random slot */ + i = mftb() % 8; + k = -1; + for (j = 0; j < 8; j++) { + pt = &moea64_pteg_table[ptegidx].pt[(i + j) % 8]; + if (pt->pte_hi & LPTE_LOCKED) + continue; + + /* Don't spill kernel mappings */ + #ifdef __powerpc64__ + if ((pt->pte_hi >> LPTE_VSID_SHIFT) & KERNEL_VSID_BIT) + continue; + #else + if (((pt->pte_hi >> LPTE_VSID_SHIFT) & EMPTY_SEGMENT) == + EMPTY_SEGMENT) + continue; + #endif + + /* This is a candidate, so remember it */ + k = (i + j) % 8; + + /* Try to get a page that has not been used lately */ + if (!(pt->pte_lo & LPTE_REF)) + return (k); + } + + return (k); +} + static int moea64_pte_insert(u_int ptegidx, struct lpte *pvo_pt) { struct lpte *pt; + struct pvo_entry *pvo; + u_int pteg_bktidx; int i; ASSERT_TABLE_LOCK(); @@ -2690,6 +2735,7 @@ moea64_pte_insert(u_int ptegidx, struct /* * First try primary hash. */ + pteg_bktidx = ptegidx; for (pt = moea64_pteg_table[ptegidx].pt, i = 0; i < 8; i++, pt++) { if ((pt->pte_hi & LPTE_VALID) == 0 && (pt->pte_hi & LPTE_LOCKED) == 0) { @@ -2702,7 +2748,7 @@ moea64_pte_insert(u_int ptegidx, struct /* * Now try secondary hash. */ - ptegidx ^= moea64_pteg_mask; + pteg_bktidx ^= moea64_pteg_mask; for (pt = moea64_pteg_table[ptegidx].pt, i = 0; i < 8; i++, pt++) { if ((pt->pte_hi & LPTE_VALID) == 0 && @@ -2713,8 +2759,50 @@ moea64_pte_insert(u_int ptegidx, struct } } - panic("moea64_pte_insert: overflow"); - return (-1); + /* + * Out of luck. Find a PTE to sacrifice. + */ + pteg_bktidx = ptegidx; + i = moea64_pte_spillable_ident(pteg_bktidx); + if (i < 0) { + pteg_bktidx ^= moea64_pteg_mask; + i = moea64_pte_spillable_ident(pteg_bktidx); + } + + if (i < 0) { + /* No freeable slots in either PTEG? We're hosed. */ + panic("moea64_pte_insert: overflow"); + return (-1); + } + + /* + * Synchronize the sacrifice PTE with its PVO, then mark both + * invalid. The PVO will be reused when/if the VM system comes + * here after a fault. + */ + pt = &moea64_pteg_table[pteg_bktidx].pt[i]; + + if (pt->pte_hi & LPTE_HID) + pvo_pt->pte_hi |= LPTE_HID; + + LIST_FOREACH(pvo, &moea64_pvo_table[ptegidx], pvo_olink) { + if (pvo->pvo_pte.lpte.pte_hi == pt->pte_hi) { + moea64_pte_unset(pt, &pvo->pvo_pte.lpte, pvo->pvo_vpn); + PVO_PTEGIDX_CLR(pvo); + moea64_pte_overflow++; + break; + } + } + + KASSERT(pvo->pvo_pte.lpte.pte_hi == pt->pte_hi, + ("Unable to find PVO for spilled PTE")); + + /* + * Set the new PTE. + */ + moea64_pte_set(pt, pvo_pt); + + return (i); } static boolean_t