Kernel/Memory: Fix redundant page faults on anonymous mmaps after fork

After a fork(), page faults on anonymous mmaps can cause a redundant
page fault to occur.

This happens because VMObjects for anonymous mmaps are initially filled
with references to the lazy_committed_page or shared_zero_page. If there
is a fork, VMObject::try_clone() is called and all pages of the VMObject
are marked as cow (via the m_cow_map).

Page faults on a zero/lazy page are handled by handle_zero_fault().
handle_zero_fault() does not update m_cow_map, so if the page was marked
cow before the fault, it will still be marked cow after the fault. This
causes a second (redundant) page fault when the CPU retries the write.

This commit removes the redundant page fault by not marking zero/lazy
pages as cow in m_cow_map.
This commit is contained in:
brody-qq 2024-07-01 16:35:47 +01:00 committed by Nico Weber
parent 2278b17c42
commit 8812410617
2 changed files with 14 additions and 2 deletions

View file

@ -267,10 +267,21 @@ NonnullRefPtr<PhysicalRAMPage> AnonymousVMObject::allocate_committed_page(Badge<
return m_unused_committed_pages->take_one();
}
void AnonymousVMObject::reset_cow_map()
{
for (size_t i = 0; i < page_count(); ++i) {
auto& page = physical_pages()[i];
bool should_cow = !page->is_shared_zero_page() && !page->is_lazy_committed_page();
m_cow_map.set(i, should_cow);
}
}
ErrorOr<void> AnonymousVMObject::ensure_cow_map()
{
if (m_cow_map.is_null())
if (m_cow_map.is_null()) {
m_cow_map = TRY(Bitmap::create(page_count(), true));
reset_cow_map();
}
return {};
}
@ -279,7 +290,7 @@ ErrorOr<void> AnonymousVMObject::ensure_or_reset_cow_map()
if (m_cow_map.is_null())
TRY(ensure_cow_map());
else
m_cow_map.fill(true);
reset_cow_map();
return {};
}

View file

@ -58,6 +58,7 @@ private:
ErrorOr<void> ensure_cow_map();
ErrorOr<void> ensure_or_reset_cow_map();
void reset_cow_map();
Optional<CommittedPhysicalPageSet> m_unused_committed_pages;
Bitmap m_cow_map;