Skip to content

Commit 5ada38f

Browse files
committed
Kernel: Reduce time under VMObject lock while handling zero faults
We only need to hold the VMObject lock while inspecting and/or updating the physical page array in the VMObject.
1 parent a84d893 commit 5ada38f

File tree

2 files changed

+27
-20
lines changed

2 files changed

+27
-20
lines changed

Kernel/Memory/Region.cpp

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -392,50 +392,57 @@ PageFaultResponse Region::handle_fault(PageFault const& fault)
392392
auto phys_page = physical_page(page_index_in_region);
393393
if (phys_page->is_shared_zero_page() || phys_page->is_lazy_committed_page()) {
394394
dbgln_if(PAGE_FAULT_DEBUG, "NP(zero) fault in Region({})[{}] at {}", this, page_index_in_region, fault.vaddr());
395-
return handle_zero_fault(page_index_in_region);
395+
return handle_zero_fault(page_index_in_region, *phys_page);
396396
}
397397
return handle_cow_fault(page_index_in_region);
398398
}
399399
dbgln("PV(error) fault in Region({})[{}] at {}", this, page_index_in_region, fault.vaddr());
400400
return PageFaultResponse::ShouldCrash;
401401
}
402402

403-
PageFaultResponse Region::handle_zero_fault(size_t page_index_in_region)
403+
PageFaultResponse Region::handle_zero_fault(size_t page_index_in_region, PhysicalPage& page_in_slot_at_time_of_fault)
404404
{
405405
VERIFY(vmobject().is_anonymous());
406406

407-
SpinlockLocker locker(vmobject().m_lock);
408-
409-
auto& page_slot = physical_page_slot(page_index_in_region);
410407
auto page_index_in_vmobject = translate_to_vmobject_page(page_index_in_region);
411408

412-
if (!page_slot.is_null() && !page_slot->is_shared_zero_page() && !page_slot->is_lazy_committed_page()) {
413-
dbgln_if(PAGE_FAULT_DEBUG, "MM: zero_page() but page already present. Fine with me!");
414-
if (!remap_vmobject_page(page_index_in_vmobject, *page_slot))
415-
return PageFaultResponse::OutOfMemory;
416-
return PageFaultResponse::Continue;
417-
}
418-
419409
auto current_thread = Thread::current();
420410
if (current_thread != nullptr)
421411
current_thread->did_zero_fault();
422412

423-
if (page_slot->is_lazy_committed_page()) {
413+
RefPtr<PhysicalPage> new_physical_page;
414+
415+
if (page_in_slot_at_time_of_fault.is_lazy_committed_page()) {
424416
VERIFY(m_vmobject->is_anonymous());
425-
page_slot = static_cast<AnonymousVMObject&>(*m_vmobject).allocate_committed_page({});
426-
dbgln_if(PAGE_FAULT_DEBUG, " >> ALLOCATED COMMITTED {}", page_slot->paddr());
417+
new_physical_page = static_cast<AnonymousVMObject&>(*m_vmobject).allocate_committed_page({});
418+
dbgln_if(PAGE_FAULT_DEBUG, " >> ALLOCATED COMMITTED {}", new_physical_page->paddr());
427419
} else {
428420
auto page_or_error = MM.allocate_physical_page(MemoryManager::ShouldZeroFill::Yes);
429421
if (page_or_error.is_error()) {
430422
dmesgln("MM: handle_zero_fault was unable to allocate a physical page");
431423
return PageFaultResponse::OutOfMemory;
432424
}
433-
page_slot = page_or_error.release_value();
434-
dbgln_if(PAGE_FAULT_DEBUG, " >> ALLOCATED {}", page_slot->paddr());
425+
new_physical_page = page_or_error.release_value();
426+
dbgln_if(PAGE_FAULT_DEBUG, " >> ALLOCATED {}", new_physical_page->paddr());
427+
}
428+
429+
bool already_handled = false;
430+
431+
{
432+
SpinlockLocker locker(vmobject().m_lock);
433+
auto& page_slot = physical_page_slot(page_index_in_region);
434+
already_handled = !page_slot.is_null() && !page_slot->is_shared_zero_page() && !page_slot->is_lazy_committed_page();
435+
if (already_handled) {
436+
// Someone else already faulted in a new page in this slot. That's fine, we'll just remap with their page.
437+
new_physical_page = page_slot;
438+
} else {
439+
// Install the newly allocated page into the VMObject.
440+
page_slot = new_physical_page;
441+
}
435442
}
436443

437-
if (!remap_vmobject_page(page_index_in_vmobject, *page_slot)) {
438-
dmesgln("MM: handle_zero_fault was unable to allocate a page table to map {}", page_slot);
444+
if (!remap_vmobject_page(page_index_in_vmobject, *new_physical_page)) {
445+
dmesgln("MM: handle_zero_fault was unable to allocate a page table to map {}", new_physical_page);
439446
return PageFaultResponse::OutOfMemory;
440447
}
441448
return PageFaultResponse::Continue;

Kernel/Memory/Region.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ class Region final
211211

212212
[[nodiscard]] PageFaultResponse handle_cow_fault(size_t page_index);
213213
[[nodiscard]] PageFaultResponse handle_inode_fault(size_t page_index);
214-
[[nodiscard]] PageFaultResponse handle_zero_fault(size_t page_index);
214+
[[nodiscard]] PageFaultResponse handle_zero_fault(size_t page_index, PhysicalPage& page_in_slot_at_time_of_fault);
215215

216216
[[nodiscard]] bool map_individual_page_impl(size_t page_index);
217217
[[nodiscard]] bool map_individual_page_impl(size_t page_index, RefPtr<PhysicalPage>);

0 commit comments

Comments
 (0)