From 5fb91e2e84dc124d872d4e009f8d7751e6fc2f61 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 25 Jul 2021 02:27:43 +0200 Subject: [PATCH] Kernel: Don't COW volatile VM objects If a purgeable VM object is in the "volatile" state when we're asked to make a COW clone of it, make life simpler by simply "purging" the cloned object right away. This effectively means that a fork()'ed child process will discover its purgeable+volatile regions to be empty if/when it tries making them non-volatile. --- Kernel/VM/AnonymousVMObject.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/Kernel/VM/AnonymousVMObject.cpp b/Kernel/VM/AnonymousVMObject.cpp index a65e25a4a6..b65128e141 100644 --- a/Kernel/VM/AnonymousVMObject.cpp +++ b/Kernel/VM/AnonymousVMObject.cpp @@ -18,17 +18,21 @@ RefPtr AnonymousVMObject::try_clone() // We need to acquire our lock so we copy a sane state ScopedSpinLock lock(m_lock); + if (is_purgeable() && is_volatile()) { + // If this object is purgeable+volatile, create a new zero-filled purgeable+volatile + // object, effectively "pre-purging" it in the child process. + auto clone = try_create_purgeable_with_size(size(), AllocationStrategy::None); + if (!clone) + return {}; + clone->m_volatile = true; + return clone; + } + // We're the parent. Since we're about to become COW we need to // commit the number of pages that we need to potentially allocate // so that the parent is still guaranteed to be able to have all // non-volatile memory available. - size_t new_cow_pages_needed = 0; - - if (is_volatile()) { - // NOTE: If this object is currently volatile, we don't own any committed pages. - } else { - new_cow_pages_needed = page_count(); - } + size_t new_cow_pages_needed = page_count(); dbgln_if(COMMIT_DEBUG, "Cloning {:p}, need {} committed cow pages", this, new_cow_pages_needed); @@ -205,11 +209,14 @@ KResult AnonymousVMObject::set_volatile(bool is_volatile, bool& was_purged) page = MM.shared_zero_page(); } + if (m_unused_committed_pages) { MM.uncommit_user_physical_pages(m_unused_committed_pages); m_unused_committed_pages = 0; } + m_shared_committed_cow_pages = nullptr; + m_volatile = true; m_was_purged = false; return KSuccess;