From owner-svn-src-all@freebsd.org Tue Jun 9 21:59:13 2020 Return-Path: Delivered-To: svn-src-all@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id CDBA133E7EE; Tue, 9 Jun 2020 21:59:13 +0000 (UTC) (envelope-from jhibbits@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 49hPCj57zLz3Yp7; Tue, 9 Jun 2020 21:59:13 +0000 (UTC) (envelope-from jhibbits@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id ABC311C5DA; Tue, 9 Jun 2020 21:59:13 +0000 (UTC) (envelope-from jhibbits@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id 059LxD9e002149; Tue, 9 Jun 2020 21:59:13 GMT (envelope-from jhibbits@FreeBSD.org) Received: (from jhibbits@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id 059LxDSx002148; Tue, 9 Jun 2020 21:59:13 GMT (envelope-from jhibbits@FreeBSD.org) Message-Id: <202006092159.059LxDSx002148@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: jhibbits set sender to jhibbits@FreeBSD.org using -f From: Justin Hibbits Date: Tue, 9 Jun 2020 21:59:13 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r361988 - head/sys/powerpc/booke X-SVN-Group: head X-SVN-Commit-Author: jhibbits X-SVN-Commit-Paths: head/sys/powerpc/booke X-SVN-Commit-Revision: 361988 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.33 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 09 Jun 2020 21:59:13 -0000 Author: jhibbits Date: Tue Jun 9 21:59:13 2020 New Revision: 361988 URL: https://svnweb.freebsd.org/changeset/base/361988 Log: powerpc/pmap: Fix wired memory leak in booke64 page directories Properly handle reference counts in the 64-bit pmap page directories. Otherwise all page table pages would leak due to over-referencing. This would cause a quick enter to swap on a desktop system (AmigaOne X5000) when quitting and rerunning applications, or just building world. Add an INVARIANTS check to validate no leakage at pmap release time. Modified: head/sys/powerpc/booke/pmap_64.c Modified: head/sys/powerpc/booke/pmap_64.c ============================================================================== --- head/sys/powerpc/booke/pmap_64.c Tue Jun 9 21:07:58 2020 (r361987) +++ head/sys/powerpc/booke/pmap_64.c Tue Jun 9 21:59:13 2020 (r361988) @@ -251,9 +251,7 @@ static bool unhold_free_page(pmap_t pmap, vm_page_t m) { - m->ref_count--; - if (m->ref_count == 0) { - vm_wire_sub(1); + if (vm_page_unwire_noq(m)) { vm_page_free_zero(m); return (true); } @@ -262,8 +260,8 @@ unhold_free_page(pmap_t pmap, vm_page_t m) } static vm_offset_t -alloc_or_hold_page(pmap_t pmap, vm_offset_t *ptr_tbl, uint32_t index, - bool nosleep, bool hold, bool *isnew) +get_pgtbl_page(pmap_t pmap, vm_offset_t *ptr_tbl, uint32_t index, + bool nosleep, bool hold_parent, bool *isnew) { vm_offset_t page; vm_page_t m; @@ -276,18 +274,18 @@ alloc_or_hold_page(pmap_t pmap, vm_offset_t *ptr_tbl, if (ptr_tbl[index] == 0) { *isnew = true; ptr_tbl[index] = page; + if (hold_parent) { + m = PHYS_TO_VM_PAGE(pmap_kextract((vm_offset_t)ptr_tbl)); + m->ref_count++; + } return (page); } m = PHYS_TO_VM_PAGE(DMAP_TO_PHYS(page)); page = ptr_tbl[index]; - vm_wire_sub(1); + vm_page_unwire_noq(m); vm_page_free_zero(m); } - if (hold) { - m = PHYS_TO_VM_PAGE(pmap_kextract(page)); - m->ref_count++; - } *isnew = false; return (page); @@ -301,19 +299,18 @@ ptbl_alloc(pmap_t pmap, vm_offset_t va, bool nosleep, unsigned int pdir_l1_idx = PDIR_L1_IDX(va); unsigned int pdir_idx = PDIR_IDX(va); vm_offset_t pdir_l1, pdir, ptbl; - bool hold_page; - hold_page = (pmap != kernel_pmap); - pdir_l1 = alloc_or_hold_page(pmap, (vm_offset_t *)pmap->pm_root, - pg_root_idx, nosleep, hold_page, is_new); + /* When holding a parent, no need to hold the root index pages. */ + pdir_l1 = get_pgtbl_page(pmap, (vm_offset_t *)pmap->pm_root, + pg_root_idx, nosleep, false, is_new); if (pdir_l1 == 0) return (NULL); - pdir = alloc_or_hold_page(pmap, (vm_offset_t *)pdir_l1, pdir_l1_idx, - nosleep, hold_page, is_new); + pdir = get_pgtbl_page(pmap, (vm_offset_t *)pdir_l1, pdir_l1_idx, + nosleep, !*is_new, is_new); if (pdir == 0) return (NULL); - ptbl = alloc_or_hold_page(pmap, (vm_offset_t *)pdir, pdir_idx, - nosleep, false, is_new); + ptbl = get_pgtbl_page(pmap, (vm_offset_t *)pdir, pdir_idx, + nosleep, !*is_new, is_new); return ((pte_t *)ptbl); } @@ -629,6 +626,15 @@ mmu_booke_release(pmap_t pmap) KASSERT(pmap->pm_stats.resident_count == 0, ("pmap_release: pmap resident count %ld != 0", pmap->pm_stats.resident_count)); +#ifdef INVARIANTS + /* + * Verify that all page directories are gone. + * Protects against reference count leakage. + */ + for (int i = 0; i < PG_ROOT_NENTRIES; i++) + KASSERT(pmap->pm_root[i] == 0, + ("Index %d on root page %p is non-zero!\n", i, pmap->pm_root)); +#endif uma_zfree(ptbl_root_zone, pmap->pm_root); }