From b4efea53e09b98ec6c8dfabc7ee60adca34cef72 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Wed, 16 Oct 2019 15:50:12 +0000 Subject: [PATCH] Clear PGA_WRITEABLE in moea_pvo_remove(). moea_pvo_remove() might remove the last mapping of a page, in which case it is clearly no longer writeable. This can happen via pmap_remove(), or when a CoW fault removes the last mapping of the old page. Reported and tested by: bdragon Reviewed by: alc, bdragon, kib MFC after: 1 week Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D22044 --- sys/powerpc/aim/mmu_oea.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/sys/powerpc/aim/mmu_oea.c b/sys/powerpc/aim/mmu_oea.c index 1cc4520e126..96534d080d4 100644 --- a/sys/powerpc/aim/mmu_oea.c +++ b/sys/powerpc/aim/mmu_oea.c @@ -2107,25 +2107,28 @@ moea_pvo_remove(struct pvo_entry *pvo, int pteidx) if (pvo->pvo_vaddr & PVO_WIRED) pvo->pvo_pmap->pm_stats.wired_count--; + /* + * Remove this PVO from the PV and pmap lists. + */ + LIST_REMOVE(pvo, pvo_vlink); + RB_REMOVE(pvo_tree, &pvo->pvo_pmap->pmap_pvo, pvo); + /* * Save the REF/CHG bits into their cache if the page is managed. + * Clear PGA_WRITEABLE if all mappings of the page have been removed. */ if ((pvo->pvo_vaddr & PVO_MANAGED) == PVO_MANAGED) { - struct vm_page *pg; + struct vm_page *pg; pg = PHYS_TO_VM_PAGE(pvo->pvo_pte.pte.pte_lo & PTE_RPGN); if (pg != NULL) { moea_attr_save(pg, pvo->pvo_pte.pte.pte_lo & (PTE_REF | PTE_CHG)); + if (LIST_EMPTY(&pg->md.mdpg_pvoh)) + vm_page_aflag_clear(pg, PGA_WRITEABLE); } } - /* - * Remove this PVO from the PV and pmap lists. - */ - LIST_REMOVE(pvo, pvo_vlink); - RB_REMOVE(pvo_tree, &pvo->pvo_pmap->pmap_pvo, pvo); - /* * Remove this from the overflow list and return it to the pool * if we aren't going to reuse it.