Have arm64's pmap_fault() handle WnR faults on dirty PTEs.

If we take a WnR permission fault on a managed, writeable and dirty
PTE, simply return success without calling the main fault handler.  This
situation can occur if multiple threads simultaneously access a clean
writeable mapping and trigger WnR faults; losers of the race to mark the
PTE dirty would end up calling the main fault handler, which had no work
to do.

Reported by:	alc
Reviewed by:	alc
MFC with:	r350004
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D21097
This commit is contained in:
Mark Johnston 2019-07-29 21:21:53 +00:00
parent 0367bca479
commit 1587dc37fa
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=350427

View File

@ -5743,7 +5743,7 @@ pmap_sync_icache(pmap_t pmap, vm_offset_t va, vm_size_t sz)
int
pmap_fault(pmap_t pmap, uint64_t esr, uint64_t far)
{
pt_entry_t *pte;
pt_entry_t pte, *ptep;
register_t intr;
uint64_t ec, par;
int lvl, rv;
@ -5767,9 +5767,9 @@ pmap_fault(pmap_t pmap, uint64_t esr, uint64_t far)
case ISS_DATA_DFSC_AFF_L2:
case ISS_DATA_DFSC_AFF_L3:
PMAP_LOCK(pmap);
pte = pmap_pte(pmap, far, &lvl);
if (pte != NULL) {
pmap_set_bits(pte, ATTR_AF);
ptep = pmap_pte(pmap, far, &lvl);
if (ptep != NULL) {
pmap_set_bits(ptep, ATTR_AF);
rv = KERN_SUCCESS;
/*
* XXXMJ as an optimization we could mark the entry
@ -5785,12 +5785,13 @@ pmap_fault(pmap_t pmap, uint64_t esr, uint64_t far)
(esr & ISS_DATA_WnR) == 0)
return (rv);
PMAP_LOCK(pmap);
pte = pmap_pte(pmap, far, &lvl);
if (pte != NULL &&
(pmap_load(pte) & (ATTR_AP_RW_BIT | ATTR_SW_DBM)) ==
(ATTR_AP(ATTR_AP_RO) | ATTR_SW_DBM)) {
pmap_clear_bits(pte, ATTR_AP_RW_BIT);
pmap_invalidate_page(pmap, far);
ptep = pmap_pte(pmap, far, &lvl);
if (ptep != NULL &&
((pte = pmap_load(ptep)) & ATTR_SW_DBM) != 0) {
if ((pte & ATTR_AP_RW_BIT) == ATTR_AP(ATTR_AP_RO)) {
pmap_clear_bits(ptep, ATTR_AP_RW_BIT);
pmap_invalidate_page(pmap, far);
}
rv = KERN_SUCCESS;
}
PMAP_UNLOCK(pmap);