DF-5289 / fix.diff
diff --git a/sys/vm/vm_fault.c b/sys/vm/vm_fault.c index e8b0bb5..f66966a 100644 --- a/sys/vm/vm_fault.c +++ b/sys/vm/vm_fault.c @@ -2676,9 +2676,27 @@ vm_fault_unwire(vm_map_t map, vm_map_entry_t entry) pmap = vm_map_pmap(map); start = entry->ba.start; end = entry->ba.end; - fictitious = entry->ba.object && + /* + * Mirror vm_fault_wire()'s classification (see ~line 2607): + * VM_MAPTYPE_UKSMAP entries have no VM object and are backed + * by a transient fictitious vm_page fabricated in vm_fault(); + * the pmap wiring takes no vm_page wire on the underlying + * real page, so the unwire path must not touch one either. + */ + switch (entry->maptype) { + case VM_MAPTYPE_NORMAL: + case VM_MAPTYPE_VPAGETABLE: + fictitious = entry->ba.object && ((entry->ba.object->type == OBJT_DEVICE) || (entry->ba.object->type == OBJT_MGTDEVICE)); + break; + case VM_MAPTYPE_UKSMAP: + fictitious = TRUE; + break; + default: + fictitious = FALSE; + break; + } if (entry->eflags & MAP_ENTRY_KSTACK) start += PAGE_SIZE; diff --git a/sys/platform/vkernel64/platform/pmap.c b/sys/platform/vkernel64/platform/pmap.c index 35f17b9..d404d5a 100644 --- a/sys/platform/vkernel64/platform/pmap.c +++ b/sys/platform/vkernel64/platform/pmap.c @@ -2652,8 +2652,19 @@ pmap_unwire(pmap_t pmap, vm_offset_t *pva) if (pmap_pte_w(pte)) { atomic_add_long(&pmap->pm_stats.wired_count, -1); atomic_clear_long(pte, VPTE_WIRED); - pa = *pte & VPTE_FRAME; - m = PHYS_TO_VM_PAGE(pa); /* held by wired count */ + + /* + * Only managed pages carry a wire count taken by + * pmap_enter(). Unmanaged (fictitious / UKSMAP) wired + * ptes must not yield a vm_page to the caller - the + * underlying page was never wired via the pmap. + */ + if (*pte & VPTE_MANAGED) { + pa = *pte & VPTE_FRAME; + m = PHYS_TO_VM_PAGE(pa);/* held by wired count */ + } else { + m = NULL; + } /* caller handles m->wire_count */ } else { m = NULL; |