@@ -392,50 +392,57 @@ PageFaultResponse Region::handle_fault(PageFault const& fault)
392
392
auto phys_page = physical_page (page_index_in_region);
393
393
if (phys_page->is_shared_zero_page () || phys_page->is_lazy_committed_page ()) {
394
394
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 );
396
396
}
397
397
return handle_cow_fault (page_index_in_region);
398
398
}
399
399
dbgln (" PV(error) fault in Region({})[{}] at {}" , this , page_index_in_region, fault.vaddr ());
400
400
return PageFaultResponse::ShouldCrash;
401
401
}
402
402
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 )
404
404
{
405
405
VERIFY (vmobject ().is_anonymous ());
406
406
407
- SpinlockLocker locker (vmobject ().m_lock );
408
-
409
- auto & page_slot = physical_page_slot (page_index_in_region);
410
407
auto page_index_in_vmobject = translate_to_vmobject_page (page_index_in_region);
411
408
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
-
419
409
auto current_thread = Thread::current ();
420
410
if (current_thread != nullptr )
421
411
current_thread->did_zero_fault ();
422
412
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 ()) {
424
416
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 ());
427
419
} else {
428
420
auto page_or_error = MM.allocate_physical_page (MemoryManager::ShouldZeroFill::Yes);
429
421
if (page_or_error.is_error ()) {
430
422
dmesgln (" MM: handle_zero_fault was unable to allocate a physical page" );
431
423
return PageFaultResponse::OutOfMemory;
432
424
}
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
+ }
435
442
}
436
443
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 );
439
446
return PageFaultResponse::OutOfMemory;
440
447
}
441
448
return PageFaultResponse::Continue;
0 commit comments