mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-10-28 11:25:21 +01:00
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 37321270b6)
This commit is contained in:
1 parent
f581891cd1
commit
6e8786bafd
2 files changed
+53
-64
No files matched your search
+25
-28
@@ -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
|
||||
|
||||
+28
-36
@@ -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),
|
||||
|
||||
Reference in new issue
Block a user