From nobody Sun Oct 25 20:45:16 2026 X-Original-To: dev-commits-src-branches@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4jCTKS4xQsz6x6FB for ; Sun, 25 Oct 2026 20:45:16 +0000 (UTC) (envelope-from git@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) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 4jCTKS4CQ5z4L0F for ; Sun, 25 Oct 2026 20:45:16 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1792961116; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=nv/vR5JoH+KM4Pbz9j+YuTeuF0ScSrAejTx5oA1dD0E=; b=Ne3qm2zyVymVdqhy4O5Em/XhEXMFAVl2/Lu3U2DW+T5aoWpaTDDJyt1iRD//qhxT6MzcFd YvrzRguwVrAM4QFv/UWRBfBDIejDm/vMQeMbAqWtahn78gdGVelqYR3FANskJ6fqzMgjlM PFKkY+Y6vnupiV4Yw8K49Xnf8nt9VJK1bqcu1Q7cHney8PdCdAwmTxN86IWTAEPGi5c4+T oEhe4bAzibETLM+1g2xGrWY/iFsyxdgorJEP1x9C7tynDuITe5eHrTOFjF5BToDEaDYK8W Yy+oNx2ETyOz+xzA5dXjOI0hw+w7wNWOTgajgrDFEplV+W2oRAPvVFUNtquGBw== ARC-Seal: i=1; a=rsa-sha256; d=freebsd.org; s=dkim; cv=none; t=1792961116; b=tUgMVv9FQYawoDPN5DNU15Jvgq9YwWaHSg6s11VPP8aRQ8cTfFhcZfM0DAlWMXWs3qMkaj 4+E9QfciQT3dnr3RR+b4/dy9HQZ+tthnCZZ0X5NaC1+JbBL1289u6w4pN2hSWJjGbDjWhj GWZd8UKMAls+Ny20xosmtiR93nlu+0i3lut7YmoOUOUiofoTUFcO6rt+fp5Da2g9M4FXDo BOpdKV9+i7Fa/tQJug6k8zZLPfMkHJKqZ9xDxwQrBM9Ez6vjFc8S8wN0GJFVFuDxetfmYe op6QcDeO8yRfG4kADZ7AxTPOheep99liEu2FkmSfmaXci3P/IJkEQCHqSjTIoA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1792961116; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=nv/vR5JoH+KM4Pbz9j+YuTeuF0ScSrAejTx5oA1dD0E=; b=YCu71sJuJsroX3Zs4eN6L0asUOVKIaAfHZu4CIm10mSC0nDRL66vQyqaWAiEdQSvICyXyP wxigNXp5H4fhco9w9dDyCysNqrMvGPhLTX3oo6reLzmXOd0rNaIaRKHC4P0EK6Mhq9lArR niayWm+//2v8NeO6CQu4u/qNr8QZaU3/+/ROZtjozlbKRjNOUPbI18r26he3UUJ/5UQqx0 Oeq1vDkVoFBj1vlGgcSLaH/kiMXO9kYthN5Zg2uIWg+u+fvJcnaFXo0OhMdlErl4BMTHU7 YGdiDgOrhQhfNhrVDeGCGdcLpWXXIvP8u/vtQn7/lkSGVuVq5LFjCxSaeVVerQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4jCTKS3bHsz12nm for ; Sun, 25 Oct 2026 20:45:16 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 3d291 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Sun, 25 Oct 2026 20:45:16 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Alan Cox Subject: git: 6e8786bafd16 - stable/15 - amd64/arm64 pmap: consistently clear PGA_WRITEABLE List-Archive: https://lists.freebsd.org/archives/dev-commits-src-branches X-BeenThere: dev-commits-src-branches@freebsd.org Sender: owner-dev-commits-src-branches@FreeBSD.org List-Id: Commits to the stable branches of the FreeBSD src repository List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: alc X-Git-Repository: src X-Git-Refname: refs/heads/stable/15 X-Git-Reftype: branch X-Git-Commit: 6e8786bafd16e841dd5562c25a68a76dea6e3a8a Auto-Submitted: auto-generated Date: Sun, 25 Oct 2026 20:45:16 +0000 Message-Id: <6ade6a5c.3d291.54f668a2@gitrepo.freebsd.org> The branch stable/15 has been updated by alc: URL: https://cgit.FreeBSD.org/src/commit/?id=6e8786bafd16e841dd5562c25a68a76dea6e3a8a commit 6e8786bafd16e841dd5562c25a68a76dea6e3a8a Author: Alan Cox AuthorDate: 2026-09-07 07:31:45 +0000 Commit: Alan Cox CommitDate: 2026-10-25 19:48:56 +0000 amd64/arm64 pmap: consistently clear PGA_WRITEABLE We don't consistently clear PGA_WRITEABLE on fictitious, managed pages. Some functions do, e.g., pmap_remove_all(), but several do not. At worst, this is just a pessimization, but there is no good reason to be inconsistent. Clear PGA_WRITEABLE in those that previously did not by introducing (and using) the helper function pmap_page_is_mapped_locked() that implements the correct test. (cherry picked from commit 37321270b630d891e48851f81dd6d077ebd6b635) --- sys/amd64/amd64/pmap.c | 53 ++++++++++++++++++++--------------------- sys/arm64/arm64/pmap.c | 64 ++++++++++++++++++++++---------------------------- 2 files changed, 53 insertions(+), 64 deletions(-) diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c index 4d6eb3e2d152..64419f9b9007 100644 --- a/sys/amd64/amd64/pmap.c +++ b/sys/amd64/amd64/pmap.c @@ -1379,6 +1379,7 @@ static void pmap_invalidate_pde_page(pmap_t pmap, vm_offset_t va, static void pmap_kenter_attr(vm_offset_t va, vm_paddr_t pa, int mode); static vm_page_t pmap_large_map_getptp_unlocked(void); static vm_paddr_t pmap_large_map_kextract(vm_offset_t va); +static bool pmap_page_is_mapped_locked(vm_page_t m); #if VM_NRESERVLEVEL > 0 static bool pmap_promote_pde(pmap_t pmap, pd_entry_t *pde, vm_offset_t va, vm_page_t mpte, struct rwlock **lockp); @@ -5211,7 +5212,6 @@ reclaim_pv_chunk_domain(pmap_t locked_pmap, struct rwlock **lockp, int domain) struct pv_chunks_list *pvc; struct pv_chunk *pc, *pc_marker, *pc_marker_end; struct pv_chunk_header pc_marker_b, pc_marker_end_b; - struct md_page *pvh; pd_entry_t *pde; pmap_t next_pmap, pmap; pt_entry_t *pte, tpte; @@ -5331,14 +5331,8 @@ reclaim_pv_chunk_domain(pmap_t locked_pmap, struct rwlock **lockp, int domain) CHANGE_PV_LIST_LOCK_TO_VM_PAGE(lockp, m); TAILQ_REMOVE(&m->md.pv_list, pv, pv_next); m->md.pv_gen++; - if (TAILQ_EMPTY(&m->md.pv_list) && - (m->flags & PG_FICTITIOUS) == 0) { - pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m)); - if (TAILQ_EMPTY(&pvh->pv_list)) { - vm_page_aflag_clear(m, - PGA_WRITEABLE); - } - } + if (!pmap_page_is_mapped_locked(m)) + vm_page_aflag_clear(m, PGA_WRITEABLE); pmap_delayed_invl_page(m); pc->pc_map[field] |= 1UL << bit; pmap_unuse_pt(pmap, va, *pde, &free); @@ -6224,7 +6218,6 @@ static int pmap_remove_pte(pmap_t pmap, pt_entry_t *ptq, vm_offset_t va, pd_entry_t ptepde, struct spglist *free, struct rwlock **lockp) { - struct md_page *pvh; pt_entry_t oldpte, PG_A, PG_M, PG_RW; vm_page_t m; @@ -6245,12 +6238,8 @@ pmap_remove_pte(pmap_t pmap, pt_entry_t *ptq, vm_offset_t va, vm_page_aflag_set(m, PGA_REFERENCED); CHANGE_PV_LIST_LOCK_TO_VM_PAGE(lockp, m); pmap_pvh_free(&m->md, pmap, va); - if (TAILQ_EMPTY(&m->md.pv_list) && - (m->flags & PG_FICTITIOUS) == 0) { - pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m)); - if (TAILQ_EMPTY(&pvh->pv_list)) - vm_page_aflag_clear(m, PGA_WRITEABLE); - } + if (!pmap_page_is_mapped_locked(m)) + vm_page_aflag_clear(m, PGA_WRITEABLE); pmap_delayed_invl_page(m); } return (pmap_unuse_pt(pmap, va, ptepde, free)); @@ -7299,10 +7288,13 @@ retry: ("pmap_enter: no PV entry for %#lx", va)); if ((newpte & PG_MANAGED) == 0) free_pv_entry(pmap, pv); + + /* + * The old page is likely COW, so check "writeable" + * first. + */ if ((om->a.flags & PGA_WRITEABLE) != 0 && - TAILQ_EMPTY(&om->md.pv_list) && - ((om->flags & PG_FICTITIOUS) != 0 || - TAILQ_EMPTY(&pa_to_pvh(opa)->pv_list))) + !pmap_page_is_mapped_locked(om)) vm_page_aflag_clear(om, PGA_WRITEABLE); } else { /* @@ -8463,13 +8455,22 @@ pmap_page_is_mapped(vm_page_t m) return (false); lock = VM_PAGE_TO_PV_LIST_LOCK(m); rw_rlock(lock); - rv = !TAILQ_EMPTY(&m->md.pv_list) || - ((m->flags & PG_FICTITIOUS) == 0 && - !TAILQ_EMPTY(&pa_to_pvh(VM_PAGE_TO_PHYS(m))->pv_list)); + rv = pmap_page_is_mapped_locked(m); rw_runlock(lock); return (rv); } +/* + * The page's PV list lock must be held. + */ +static __always_inline bool +pmap_page_is_mapped_locked(vm_page_t m) +{ + return (!TAILQ_EMPTY(&m->md.pv_list) || + ((m->flags & PG_FICTITIOUS) == 0 && + !TAILQ_EMPTY(&pa_to_pvh(VM_PAGE_TO_PHYS(m))->pv_list))); +} + /* * Destroy all managed, non-wired mappings in the given user-space * pmap. This pmap cannot be active on any processor besides the @@ -8662,12 +8663,8 @@ pmap_remove_pages(pmap_t pmap) TAILQ_REMOVE(&m->md.pv_list, pv, pv_next); m->md.pv_gen++; if ((m->a.flags & PGA_WRITEABLE) != 0 && - TAILQ_EMPTY(&m->md.pv_list) && - (m->flags & PG_FICTITIOUS) == 0) { - pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m)); - if (TAILQ_EMPTY(&pvh->pv_list)) - vm_page_aflag_clear(m, PGA_WRITEABLE); - } + !pmap_page_is_mapped_locked(m)) + vm_page_aflag_clear(m, PGA_WRITEABLE); } pmap_unuse_pt(pmap, pv->pv_va, ptepde, &free); #ifdef PV_STATS diff --git a/sys/arm64/arm64/pmap.c b/sys/arm64/arm64/pmap.c index 657ed4c445fa..52afe723c354 100644 --- a/sys/arm64/arm64/pmap.c +++ b/sys/arm64/arm64/pmap.c @@ -497,6 +497,7 @@ static int pmap_insert_pt_page(pmap_t pmap, vm_page_t mpte, bool promoted, static pt_entry_t pmap_load_l3c(pt_entry_t *l3p); static void pmap_mask_set_l3c(pmap_t pmap, pt_entry_t *l3p, vm_offset_t va, vm_offset_t *vap, vm_offset_t va_next, pt_entry_t mask, pt_entry_t nbits); +static bool pmap_page_is_mapped_locked(vm_page_t m); static bool pmap_pv_insert_l3c(pmap_t pmap, vm_offset_t va, vm_page_t m, struct rwlock **lockp); static void pmap_remove_kernel_l2(pmap_t pmap, pt_entry_t *l2, vm_offset_t va); @@ -3351,7 +3352,6 @@ reclaim_pv_chunk_domain(pmap_t locked_pmap, struct rwlock **lockp, int domain) struct pv_chunks_list *pvc; struct pv_chunk *pc, *pc_marker, *pc_marker_end; struct pv_chunk_header pc_marker_b, pc_marker_end_b; - struct md_page *pvh; pd_entry_t *pde; pmap_t next_pmap, pmap; pt_entry_t *pte, tpte; @@ -3453,14 +3453,8 @@ reclaim_pv_chunk_domain(pmap_t locked_pmap, struct rwlock **lockp, int domain) CHANGE_PV_LIST_LOCK_TO_VM_PAGE(lockp, m); TAILQ_REMOVE(&m->md.pv_list, pv, pv_next); m->md.pv_gen++; - if (TAILQ_EMPTY(&m->md.pv_list) && - (m->flags & PG_FICTITIOUS) == 0) { - pvh = page_to_pvh(m); - if (TAILQ_EMPTY(&pvh->pv_list)) { - vm_page_aflag_clear(m, - PGA_WRITEABLE); - } - } + if (!pmap_page_is_mapped_locked(m)) + vm_page_aflag_clear(m, PGA_WRITEABLE); pc->pc_map[field] |= 1UL << bit; pmap_unuse_pt(pmap, va, pmap_load(pde), &free); freed++; @@ -4066,7 +4060,6 @@ static int pmap_remove_l3(pmap_t pmap, pt_entry_t *l3, vm_offset_t va, pd_entry_t l2e, struct spglist *free, struct rwlock **lockp) { - struct md_page *pvh; pt_entry_t old_l3; vm_page_t m; @@ -4087,12 +4080,8 @@ pmap_remove_l3(pmap_t pmap, pt_entry_t *l3, vm_offset_t va, vm_page_aflag_set(m, PGA_REFERENCED); CHANGE_PV_LIST_LOCK_TO_VM_PAGE(lockp, m); pmap_pvh_free(&m->md, pmap, va); - if (TAILQ_EMPTY(&m->md.pv_list) && - (m->flags & PG_FICTITIOUS) == 0) { - pvh = page_to_pvh(m); - if (TAILQ_EMPTY(&pvh->pv_list)) - vm_page_aflag_clear(m, PGA_WRITEABLE); - } + if (!pmap_page_is_mapped_locked(m)) + vm_page_aflag_clear(m, PGA_WRITEABLE); } return (pmap_unuse_pt(pmap, va, l2e, free)); } @@ -4194,7 +4183,6 @@ static void pmap_remove_l3_range(pmap_t pmap, pd_entry_t l2e, vm_offset_t sva, vm_offset_t eva, struct spglist *free, struct rwlock **lockp) { - struct md_page *pvh; struct rwlock *new_lock; pt_entry_t *l3, old_l3; vm_offset_t va; @@ -4272,12 +4260,8 @@ pmap_remove_l3_range(pmap_t pmap, pd_entry_t l2e, vm_offset_t sva, rw_wlock(*lockp); } pmap_pvh_free(&m->md, pmap, sva); - if (TAILQ_EMPTY(&m->md.pv_list) && - (m->flags & PG_FICTITIOUS) == 0) { - pvh = page_to_pvh(m); - if (TAILQ_EMPTY(&pvh->pv_list)) - vm_page_aflag_clear(m, PGA_WRITEABLE); - } + if (!pmap_page_is_mapped_locked(m)) + vm_page_aflag_clear(m, PGA_WRITEABLE); } if (l3pg != NULL && pmap_unwire_l3(pmap, sva, l3pg, free)) { /* @@ -5641,10 +5625,13 @@ havel3: pv = pmap_pvh_remove(&om->md, pmap, va); if ((m->oflags & VPO_UNMANAGED) != 0) free_pv_entry(pmap, pv); + + /* + * The old page is likely COW, so check "writeable" + * first. + */ if ((om->a.flags & PGA_WRITEABLE) != 0 && - TAILQ_EMPTY(&om->md.pv_list) && - ((om->flags & PG_FICTITIOUS) != 0 || - TAILQ_EMPTY(&page_to_pvh(om)->pv_list))) + !pmap_page_is_mapped_locked(om)) vm_page_aflag_clear(om, PGA_WRITEABLE); } else { KASSERT((orig_l3 & ATTR_AF) != 0, @@ -7116,13 +7103,22 @@ pmap_page_is_mapped(vm_page_t m) return (false); lock = VM_PAGE_TO_PV_LIST_LOCK(m); rw_rlock(lock); - rv = !TAILQ_EMPTY(&m->md.pv_list) || - ((m->flags & PG_FICTITIOUS) == 0 && - !TAILQ_EMPTY(&page_to_pvh(m)->pv_list)); + rv = pmap_page_is_mapped_locked(m); rw_runlock(lock); return (rv); } +/* + * The page's PV list lock must be held. + */ +static __always_inline bool +pmap_page_is_mapped_locked(vm_page_t m) +{ + return (!TAILQ_EMPTY(&m->md.pv_list) || + ((m->flags & PG_FICTITIOUS) == 0 && + !TAILQ_EMPTY(&page_to_pvh(m)->pv_list))); +} + /* * Destroy all managed, non-wired mappings in the given user-space * pmap. This pmap cannot be active on any processor besides the @@ -7291,13 +7287,9 @@ pmap_remove_pages(pmap_t pmap) pv_next); m->md.pv_gen++; if ((m->a.flags & PGA_WRITEABLE) != 0 && - TAILQ_EMPTY(&m->md.pv_list) && - (m->flags & PG_FICTITIOUS) == 0) { - pvh = page_to_pvh(m); - if (TAILQ_EMPTY(&pvh->pv_list)) - vm_page_aflag_clear(m, - PGA_WRITEABLE); - } + !pmap_page_is_mapped_locked(m)) + vm_page_aflag_clear(m, + PGA_WRITEABLE); break; } pmap_unuse_pt(pmap, pv->pv_va, pmap_load(pde),