kernel/vm: Make use of VMTranslationMap::PageUnmapped in UnmapPages.

An extra argument is added to allow the VMAreaMappings objects to
be added to a queue instead of freed directly (and the lock unlocked,
and so on.)

All architectures adjusted.

This means there is now only one place in each TranslationMap that
the page state and other data is directly adjusted (in UnmapArea).

Change-Id: I3ed2d6d969d1b1e235144a1035c90c750779af27
Reviewed-on: https://review.haiku-os.org/c/haiku/+/8716
Tested-by: Commit checker robot <[email protected]>
Reviewed-by: X512 X512 <[email protected]>
Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
Augustin Cavalier
2024-12-27 22:07:34 +00:00
committed by waddlesplash
parent 6f786da5f7
commit c5874ee428
11 changed files with 70 additions and 416 deletions
+2 -1
View File
@@ -84,7 +84,8 @@ public:
protected: protected:
void PageUnmapped(VMArea* area, void PageUnmapped(VMArea* area,
page_num_t pageNumber, bool accessed, page_num_t pageNumber, bool accessed,
bool modified, bool updatePageQueue); bool modified, bool updatePageQueue,
VMAreaMappings* mappingsQueue = NULL);
void UnaccessedPageUnmapped(VMArea* area, void UnaccessedPageUnmapped(VMArea* area,
page_num_t pageNumber); page_num_t pageNumber);
@@ -452,52 +452,11 @@ ARMVMTranslationMap32Bit::UnmapPages(VMArea* area, addr_t base, size_t size,
} }
if (area->cache_type != CACHE_TYPE_DEVICE) { if (area->cache_type != CACHE_TYPE_DEVICE) {
// get the page page_num_t page = (oldEntry & ARM_PTE_ADDRESS_MASK) / B_PAGE_SIZE;
vm_page* page = vm_lookup_page( PageUnmapped(area, page,
(oldEntry & ARM_PTE_ADDRESS_MASK) / B_PAGE_SIZE); (oldEntry & ARM_MMU_L2_FLAG_AP0) != 0,
ASSERT(page != NULL); (oldEntry & ARM_MMU_L2_FLAG_AP2) != 0,
updatePageQueue, &queue);
DEBUG_PAGE_ACCESS_START(page);
// transfer the accessed/dirty flags to the page
if ((oldEntry & ARM_MMU_L2_FLAG_AP0) != 0)
page->accessed = true;
if ((oldEntry & ARM_MMU_L2_FLAG_AP2) == 0)
page->modified = true;
// remove the mapping object/decrement the wired_count of the
// page
if (area->wiring == B_NO_LOCK) {
vm_page_mapping* mapping = NULL;
vm_page_mappings::Iterator iterator
= page->mappings.GetIterator();
while ((mapping = iterator.Next()) != NULL) {
if (mapping->area == area)
break;
}
ASSERT(mapping != NULL);
area->mappings.Remove(mapping);
page->mappings.Remove(mapping);
queue.Add(mapping);
} else
page->DecrementWiredCount();
if (!page->IsMapped()) {
atomic_add(&gMappedPagesCount, -1);
if (updatePageQueue) {
if (page->Cache()->temporary)
vm_page_set_state(page, PAGE_STATE_INACTIVE);
else if (page->modified)
vm_page_set_state(page, PAGE_STATE_MODIFIED);
else
vm_page_set_state(page, PAGE_STATE_CACHED);
}
}
DEBUG_PAGE_ACCESS_END(page);
} }
} }
@@ -681,49 +681,10 @@ VMSAv8TranslationMap::UnmapPages(VMArea* area, addr_t address, size_t size, bool
if (area->cache_type == CACHE_TYPE_DEVICE) if (area->cache_type == CACHE_TYPE_DEVICE)
return; return;
// get the page page_num_t page = (oldPte & kPteAddrMask) >> fPageBits;
vm_page* page = vm_lookup_page((oldPte & kPteAddrMask) >> fPageBits); PageUnmapped(area, page,
ASSERT(page != NULL); is_pte_accessed(oldPte), is_pte_dirty(oldPte),
updatePageQueue, &queue);
DEBUG_PAGE_ACCESS_START(page);
// transfer the accessed/dirty flags to the page
page->accessed = is_pte_accessed(oldPte);
page->modified = is_pte_dirty(oldPte);
// remove the mapping object/decrement the wired_count of the
// page
if (area->wiring == B_NO_LOCK) {
vm_page_mapping* mapping = NULL;
vm_page_mappings::Iterator iterator
= page->mappings.GetIterator();
while ((mapping = iterator.Next()) != NULL) {
if (mapping->area == area)
break;
}
ASSERT(mapping != NULL);
area->mappings.Remove(mapping);
page->mappings.Remove(mapping);
queue.Add(mapping);
} else
page->DecrementWiredCount();
if (!page->IsMapped()) {
atomic_add(&gMappedPagesCount, -1);
if (updatePageQueue) {
if (page->Cache()->temporary)
vm_page_set_state(page, PAGE_STATE_INACTIVE);
else if (page->modified)
vm_page_set_state(page, PAGE_STATE_MODIFIED);
else
vm_page_set_state(page, PAGE_STATE_CACHED);
}
}
DEBUG_PAGE_ACCESS_END(page);
}); });
// TODO: As in UnmapPage() we can lose page dirty flags here. ATM it's not // TODO: As in UnmapPage() we can lose page dirty flags here. ATM it's not
@@ -573,52 +573,11 @@ M68KVMTranslationMap040::UnmapPages(VMArea* area, addr_t base, size_t size,
} }
if (area->cache_type != CACHE_TYPE_DEVICE) { if (area->cache_type != CACHE_TYPE_DEVICE) {
// get the page page_num_t page = (oldEntry & M68K_PTE_ADDRESS_MASK) / B_PAGE_SIZE;
vm_page* page = vm_lookup_page( PageUnmapped(area, page,
(oldEntry & M68K_PTE_ADDRESS_MASK) / B_PAGE_SIZE); (oldEntry & M68K_PTE_ACCESSED) != 0,
ASSERT(page != NULL); (oldEntry & M68K_PTE_DIRTY) != 0,
updatePageQueue, &queue);
DEBUG_PAGE_ACCESS_START(page);
// transfer the accessed/dirty flags to the page
if ((oldEntry & M68K_PTE_ACCESSED) != 0)
page->accessed = true;
if ((oldEntry & M68K_PTE_DIRTY) != 0)
page->modified = true;
// remove the mapping object/decrement the wired_count of the
// page
if (area->wiring == B_NO_LOCK) {
vm_page_mapping* mapping = NULL;
vm_page_mappings::Iterator iterator
= page->mappings.GetIterator();
while ((mapping = iterator.Next()) != NULL) {
if (mapping->area == area)
break;
}
ASSERT(mapping != NULL);
area->mappings.Remove(mapping);
page->mappings.Remove(mapping);
queue.Add(mapping);
} else
page->DecrementWiredCount();
if (!page->IsMapped()) {
atomic_add(&gMappedPagesCount, -1);
if (updatePageQueue) {
if (page->Cache()->temporary)
vm_page_set_state(page, PAGE_STATE_INACTIVE);
else if (page->modified)
vm_page_set_state(page, PAGE_STATE_MODIFIED);
else
vm_page_set_state(page, PAGE_STATE_CACHED);
}
}
DEBUG_PAGE_ACCESS_END(page);
} }
} }
@@ -798,52 +798,11 @@ PPCVMTranslationMap460::UnmapPages(VMArea* area, addr_t base, size_t size,
} }
if (area->cache_type != CACHE_TYPE_DEVICE) { if (area->cache_type != CACHE_TYPE_DEVICE) {
// get the page page_num_t page = (oldEntry & PPC_PTE_ADDRESS_MASK) / B_PAGE_SIZE;
vm_page* page = vm_lookup_page( PageUnmapped(area, page,
(oldEntry & PPC_PTE_ADDRESS_MASK) / B_PAGE_SIZE); (oldEntry & PPC_PTE_ACCESSED) != 0,
ASSERT(page != NULL); (oldEntry & PPC_PTE_DIRTY) != 0,
updatePageQueue, &queue);
DEBUG_PAGE_ACCESS_START(page);
// transfer the accessed/dirty flags to the page
if ((oldEntry & PPC_PTE_ACCESSED) != 0)
page->accessed = true;
if ((oldEntry & PPC_PTE_DIRTY) != 0)
page->modified = true;
// remove the mapping object/decrement the wired_count of the
// page
if (area->wiring == B_NO_LOCK) {
vm_page_mapping* mapping = NULL;
vm_page_mappings::Iterator iterator
= page->mappings.GetIterator();
while ((mapping = iterator.Next()) != NULL) {
if (mapping->area == area)
break;
}
ASSERT(mapping != NULL);
area->mappings.Remove(mapping);
page->mappings.Remove(mapping);
queue.Add(mapping);
} else
page->DecrementWiredCount();
if (!page->IsMapped()) {
atomic_add(&gMappedPagesCount, -1);
if (updatePageQueue) {
if (page->Cache()->temporary)
vm_page_set_state(page, PAGE_STATE_INACTIVE);
else if (page->modified)
vm_page_set_state(page, PAGE_STATE_MODIFIED);
else
vm_page_set_state(page, PAGE_STATE_CACHED);
}
}
DEBUG_PAGE_ACCESS_END(page);
} }
} }
@@ -798,52 +798,11 @@ PPCVMTranslationMapClassic::UnmapPages(VMArea* area, addr_t base, size_t size,
} }
if (area->cache_type != CACHE_TYPE_DEVICE) { if (area->cache_type != CACHE_TYPE_DEVICE) {
// get the page page_num_t page = (oldEntry & PPC_PTE_ADDRESS_MASK) / B_PAGE_SIZE;
vm_page* page = vm_lookup_page( PageUnmapped(area, page,
(oldEntry & PPC_PTE_ADDRESS_MASK) / B_PAGE_SIZE); (oldEntry & PPC_PTE_ACCESSED) != 0,
ASSERT(page != NULL); (oldEntry & PPC_PTE_DIRTY) != 0,
updatePageQueue, &queue);
DEBUG_PAGE_ACCESS_START(page);
// transfer the accessed/dirty flags to the page
if ((oldEntry & PPC_PTE_ACCESSED) != 0)
page->accessed = true;
if ((oldEntry & PPC_PTE_DIRTY) != 0)
page->modified = true;
// remove the mapping object/decrement the wired_count of the
// page
if (area->wiring == B_NO_LOCK) {
vm_page_mapping* mapping = NULL;
vm_page_mappings::Iterator iterator
= page->mappings.GetIterator();
while ((mapping = iterator.Next()) != NULL) {
if (mapping->area == area)
break;
}
ASSERT(mapping != NULL);
area->mappings.Remove(mapping);
page->mappings.Remove(mapping);
queue.Add(mapping);
} else
page->DecrementWiredCount();
if (!page->IsMapped()) {
atomic_add(&gMappedPagesCount, -1);
if (updatePageQueue) {
if (page->Cache()->temporary)
vm_page_set_state(page, PAGE_STATE_INACTIVE);
else if (page->modified)
vm_page_set_state(page, PAGE_STATE_MODIFIED);
else
vm_page_set_state(page, PAGE_STATE_CACHED);
}
}
DEBUG_PAGE_ACCESS_END(page);
} }
} }
@@ -393,49 +393,8 @@ RISCV64VMTranslationMap::UnmapPages(VMArea* area, addr_t base, size_t size,
InvalidatePage(start); InvalidatePage(start);
if (area->cache_type != CACHE_TYPE_DEVICE) { if (area->cache_type != CACHE_TYPE_DEVICE) {
// get the page PageUnmapped(area, oldPte.ppn, oldPte.isAccessed, oldPte.isDirty,
vm_page* page = vm_lookup_page(oldPte.ppn); updatePageQueue, &queue);
ASSERT(page != NULL);
DEBUG_PAGE_ACCESS_START(page);
// transfer the accessed/dirty flags to the page
page->accessed = oldPte.isAccessed;
page->modified = oldPte.isDirty;
// remove the mapping object/decrement the wired_count of the
// page
if (area->wiring == B_NO_LOCK) {
vm_page_mapping* mapping = NULL;
vm_page_mappings::Iterator iterator
= page->mappings.GetIterator();
while ((mapping = iterator.Next()) != NULL) {
if (mapping->area == area)
break;
}
ASSERT(mapping != NULL);
area->mappings.Remove(mapping);
page->mappings.Remove(mapping);
queue.Add(mapping);
} else
page->DecrementWiredCount();
if (!page->IsMapped()) {
atomic_add(&gMappedPagesCount, -1);
if (updatePageQueue) {
if (page->Cache()->temporary)
vm_page_set_state(page, PAGE_STATE_INACTIVE);
else if (page->modified)
vm_page_set_state(page, PAGE_STATE_MODIFIED);
else
vm_page_set_state(page, PAGE_STATE_CACHED);
}
}
DEBUG_PAGE_ACCESS_END(page);
} }
// flush explicitly, since we directly use the lock // flush explicitly, since we directly use the lock
@@ -435,52 +435,11 @@ X86VMTranslationMap32Bit::UnmapPages(VMArea* area, addr_t base, size_t size,
} }
if (area->cache_type != CACHE_TYPE_DEVICE) { if (area->cache_type != CACHE_TYPE_DEVICE) {
// get the page page_num_t page = (oldEntry & X86_PTE_ADDRESS_MASK) / B_PAGE_SIZE;
vm_page* page = vm_lookup_page( PageUnmapped(area, page,
(oldEntry & X86_PTE_ADDRESS_MASK) / B_PAGE_SIZE); (oldEntry & X86_PTE_ACCESSED) != 0,
ASSERT(page != NULL); (oldEntry & X86_PTE_DIRTY) != 0,
updatePageQueue, &queue);
DEBUG_PAGE_ACCESS_START(page);
// transfer the accessed/dirty flags to the page
if ((oldEntry & X86_PTE_ACCESSED) != 0)
page->accessed = true;
if ((oldEntry & X86_PTE_DIRTY) != 0)
page->modified = true;
// remove the mapping object/decrement the wired_count of the
// page
if (area->wiring == B_NO_LOCK) {
vm_page_mapping* mapping = NULL;
vm_page_mappings::Iterator iterator
= page->mappings.GetIterator();
while ((mapping = iterator.Next()) != NULL) {
if (mapping->area == area)
break;
}
ASSERT(mapping != NULL);
area->mappings.Remove(mapping);
page->mappings.Remove(mapping);
queue.Add(mapping);
} else
page->DecrementWiredCount();
if (!page->IsMapped()) {
atomic_add(&gMappedPagesCount, -1);
if (updatePageQueue) {
if (page->Cache()->temporary)
vm_page_set_state(page, PAGE_STATE_INACTIVE);
else if (page->modified)
vm_page_set_state(page, PAGE_STATE_MODIFIED);
else
vm_page_set_state(page, PAGE_STATE_CACHED);
}
}
DEBUG_PAGE_ACCESS_END(page);
} }
} }
@@ -437,52 +437,11 @@ X86VMTranslationMap64Bit::UnmapPages(VMArea* area, addr_t base, size_t size,
} }
if (area->cache_type != CACHE_TYPE_DEVICE) { if (area->cache_type != CACHE_TYPE_DEVICE) {
// get the page page_num_t page = (oldEntry & X86_64_PTE_ADDRESS_MASK) / B_PAGE_SIZE;
vm_page* page = vm_lookup_page( PageUnmapped(area, page,
(oldEntry & X86_64_PTE_ADDRESS_MASK) / B_PAGE_SIZE); (oldEntry & X86_64_PTE_ACCESSED) != 0,
ASSERT(page != NULL); (oldEntry & X86_64_PTE_DIRTY) != 0,
updatePageQueue, &queue);
DEBUG_PAGE_ACCESS_START(page);
// transfer the accessed/dirty flags to the page
if ((oldEntry & X86_64_PTE_ACCESSED) != 0)
page->accessed = true;
if ((oldEntry & X86_64_PTE_DIRTY) != 0)
page->modified = true;
// remove the mapping object/decrement the wired_count of the
// page
if (area->wiring == B_NO_LOCK) {
vm_page_mapping* mapping = NULL;
vm_page_mappings::Iterator iterator
= page->mappings.GetIterator();
while ((mapping = iterator.Next()) != NULL) {
if (mapping->area == area)
break;
}
ASSERT(mapping != NULL);
area->mappings.Remove(mapping);
page->mappings.Remove(mapping);
queue.Add(mapping);
} else
page->DecrementWiredCount();
if (!page->IsMapped()) {
atomic_add(&gMappedPagesCount, -1);
if (updatePageQueue) {
if (page->Cache()->temporary)
vm_page_set_state(page, PAGE_STATE_INACTIVE);
else if (page->modified)
vm_page_set_state(page, PAGE_STATE_MODIFIED);
else
vm_page_set_state(page, PAGE_STATE_CACHED);
}
}
DEBUG_PAGE_ACCESS_END(page);
} }
} }
@@ -682,52 +682,11 @@ X86VMTranslationMapPAE::UnmapPages(VMArea* area, addr_t base, size_t size,
} }
if (area->cache_type != CACHE_TYPE_DEVICE) { if (area->cache_type != CACHE_TYPE_DEVICE) {
// get the page page_num_t page = (oldEntry & X86_PAE_PTE_ADDRESS_MASK) / B_PAGE_SIZE;
vm_page* page = vm_lookup_page( PageUnmapped(area, page,
(oldEntry & X86_PAE_PTE_ADDRESS_MASK) / B_PAGE_SIZE); (oldEntry & X86_PAE_PTE_ACCESSED) != 0,
ASSERT(page != NULL); (oldEntry & X86_PAE_PTE_DIRTY) != 0,
updatePageQueue, &queue);
DEBUG_PAGE_ACCESS_START(page);
// transfer the accessed/dirty flags to the page
if ((oldEntry & X86_PAE_PTE_ACCESSED) != 0)
page->accessed = true;
if ((oldEntry & X86_PAE_PTE_DIRTY) != 0)
page->modified = true;
// remove the mapping object/decrement the wired_count of the
// page
if (area->wiring == B_NO_LOCK) {
vm_page_mapping* mapping = NULL;
vm_page_mappings::Iterator iterator
= page->mappings.GetIterator();
while ((mapping = iterator.Next()) != NULL) {
if (mapping->area == area)
break;
}
ASSERT(mapping != NULL);
area->mappings.Remove(mapping);
page->mappings.Remove(mapping);
queue.Add(mapping);
} else
page->DecrementWiredCount();
if (!page->IsMapped()) {
atomic_add(&gMappedPagesCount, -1);
if (updatePageQueue) {
if (page->Cache()->temporary)
vm_page_set_state(page, PAGE_STATE_INACTIVE);
else if (page->modified)
vm_page_set_state(page, PAGE_STATE_MODIFIED);
else
vm_page_set_state(page, PAGE_STATE_CACHED);
}
}
DEBUG_PAGE_ACCESS_END(page);
} }
} }
+21 -1
View File
@@ -158,12 +158,17 @@ VMTranslationMap::DebugGetReverseMappingInfo(phys_addr_t physicalAddress,
/*! Called by UnmapPage() after performing the architecture specific part. /*! Called by UnmapPage() after performing the architecture specific part.
Looks up the page, updates its flags, removes the page-area mapping, and Looks up the page, updates its flags, removes the page-area mapping, and
requeues the page, if necessary. requeues the page, if necessary.
If \c mappingsQueue is unspecified, then it unlocks the map and frees the
page-area mapping. If \c mappingsQueue is specified, then it adds the removed
mapping to the queue and does NOT unlock the map.
*/ */
void void
VMTranslationMap::PageUnmapped(VMArea* area, page_num_t pageNumber, VMTranslationMap::PageUnmapped(VMArea* area, page_num_t pageNumber,
bool accessed, bool modified, bool updatePageQueue) bool accessed, bool modified, bool updatePageQueue, VMAreaMappings* mappingsQueue)
{ {
if (area->cache_type == CACHE_TYPE_DEVICE) { if (area->cache_type == CACHE_TYPE_DEVICE) {
if (mappingsQueue == NULL)
recursive_lock_unlock(&fLock); recursive_lock_unlock(&fLock);
return; return;
} }
@@ -173,6 +178,12 @@ VMTranslationMap::PageUnmapped(VMArea* area, page_num_t pageNumber,
ASSERT_PRINT(page != NULL, "page number: %#" B_PRIxPHYSADDR ASSERT_PRINT(page != NULL, "page number: %#" B_PRIxPHYSADDR
", accessed: %d, modified: %d", pageNumber, accessed, modified); ", accessed: %d, modified: %d", pageNumber, accessed, modified);
if (mappingsQueue != NULL) {
DEBUG_PAGE_ACCESS_START(page);
} else {
DEBUG_PAGE_ACCESS_CHECK(page);
}
// transfer the accessed/dirty flags to the page // transfer the accessed/dirty flags to the page
page->accessed |= accessed; page->accessed |= accessed;
page->modified |= modified; page->modified |= modified;
@@ -195,6 +206,7 @@ VMTranslationMap::PageUnmapped(VMArea* area, page_num_t pageNumber,
} else } else
page->DecrementWiredCount(); page->DecrementWiredCount();
if (mappingsQueue == NULL)
recursive_lock_unlock(&fLock); recursive_lock_unlock(&fLock);
if (!page->IsMapped()) { if (!page->IsMapped()) {
@@ -210,11 +222,19 @@ VMTranslationMap::PageUnmapped(VMArea* area, page_num_t pageNumber,
} }
} }
if (mappingsQueue != NULL) {
DEBUG_PAGE_ACCESS_END(page);
}
if (mapping != NULL) { if (mapping != NULL) {
if (mappingsQueue == NULL) {
bool isKernelSpace = area->address_space == VMAddressSpace::Kernel(); bool isKernelSpace = area->address_space == VMAddressSpace::Kernel();
vm_free_page_mapping(pageNumber, mapping, vm_free_page_mapping(pageNumber, mapping,
CACHE_DONT_WAIT_FOR_MEMORY CACHE_DONT_WAIT_FOR_MEMORY
| (isKernelSpace ? CACHE_DONT_LOCK_KERNEL_SPACE : 0)); | (isKernelSpace ? CACHE_DONT_LOCK_KERNEL_SPACE : 0));
} else {
mappingsQueue->Add(mapping);
}
} }
} }