Kernel: Don't try to return a committed page that we don't have

When we get a COW fault and discover that whoever we were COW'ing
together with has either COW'ed that page on their end (or they have
unmapped/exited) we simplify life for ourselves by clearing the COW
bit and keeping the page we already have. (No need to COW if the page
is not shared!)

The act of doing this does not return a committed page to the pool.
In fact, that committed page we had reserved for this purpose was used
up (allocated) by our COW buddy when they COW'ed the page.

This fixes a kernel panic when running TestLibCMkTemp. :^)
This commit is contained in:
Andreas Kling 2021-07-26 00:31:26 +02:00
parent 101486279f
commit 50472fd69f
Notes: sideshowbarker 2024-07-18 08:20:39 +09:00
2 changed files with 12 additions and 20 deletions

View file

@ -319,20 +319,21 @@ PageFaultResponse AnonymousVMObject::handle_cow_fault(size_t page_index, Virtual
}
auto& page_slot = physical_pages()[page_index];
bool have_committed = m_shared_committed_cow_pages;
if (page_slot->ref_count() == 1) {
dbgln_if(PAGE_FAULT_DEBUG, " >> It's a COW page but nobody is sharing it anymore. Remap r/w");
set_should_cow(page_index, false);
if (have_committed) {
if (m_shared_committed_cow_pages->return_one())
m_shared_committed_cow_pages = nullptr;
}
// If we were sharing committed COW pages with another process, and the other process
// has exhausted the supply, we can stop counting the shared pages.
if (m_shared_committed_cow_pages && m_shared_committed_cow_pages->is_empty())
m_shared_committed_cow_pages = nullptr;
return PageFaultResponse::Continue;
}
RefPtr<PhysicalPage> page;
if (have_committed) {
if (m_shared_committed_cow_pages) {
dbgln_if(PAGE_FAULT_DEBUG, " >> It's a committed COW page and it's time to COW!");
page = m_shared_committed_cow_pages->allocate_one();
} else {
@ -386,13 +387,4 @@ NonnullRefPtr<PhysicalPage> CommittedCowPages::allocate_one()
return MM.allocate_committed_user_physical_page(MemoryManager::ShouldZeroFill::Yes);
}
bool CommittedCowPages::return_one()
{
VERIFY(m_committed_pages > 0);
m_committed_pages--;
MM.uncommit_user_physical_pages(1);
return m_committed_pages == 0;
}
}

View file

@ -20,14 +20,14 @@ class CommittedCowPages : public RefCounted<CommittedCowPages> {
public:
CommittedCowPages() = delete;
CommittedCowPages(size_t);
explicit CommittedCowPages(size_t);
~CommittedCowPages();
NonnullRefPtr<PhysicalPage> allocate_one();
bool return_one();
[[nodiscard]] NonnullRefPtr<PhysicalPage> allocate_one();
[[nodiscard]] size_t is_empty() const { return m_committed_pages == 0; }
private:
size_t m_committed_pages;
public:
size_t m_committed_pages { 0 };
};
class AnonymousVMObject final : public VMObject {