diff options
author | Idan Horowitz <idan.horowitz@gmail.com> | 2022-02-10 19:17:27 +0200 |
---|---|---|
committer | Idan Horowitz <idan.horowitz@gmail.com> | 2022-02-11 17:49:46 +0200 |
commit | 8030e2a88f8b6c9a78ac9734fb2c08071f8d3d70 (patch) | |
tree | 1594298791eda6cd9f8bda44843b2bce91049f40 /Kernel/Memory/AnonymousVMObject.cpp | |
parent | 871a53db760a975a6aa3510b1a5b355152eaa2ef (diff) | |
download | serenity-8030e2a88f8b6c9a78ac9734fb2c08071f8d3d70.zip |
Kernel: Make AnonymousVMObject COW-Bitmap allocation OOM-fallible
Diffstat (limited to 'Kernel/Memory/AnonymousVMObject.cpp')
-rw-r--r-- | Kernel/Memory/AnonymousVMObject.cpp | 39 |
1 files changed, 25 insertions, 14 deletions
diff --git a/Kernel/Memory/AnonymousVMObject.cpp b/Kernel/Memory/AnonymousVMObject.cpp index a55d0225c3..1625c677e8 100644 --- a/Kernel/Memory/AnonymousVMObject.cpp +++ b/Kernel/Memory/AnonymousVMObject.cpp @@ -45,13 +45,13 @@ ErrorOr<NonnullRefPtr<VMObject>> AnonymousVMObject::try_clone() // to cow all pages as needed auto new_shared_committed_cow_pages = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) SharedCommittedCowPages(move(committed_pages)))); auto new_physical_pages = TRY(this->try_clone_physical_pages()); - auto clone = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) AnonymousVMObject(*this, *new_shared_committed_cow_pages, move(new_physical_pages)))); - - m_shared_committed_cow_pages = move(new_shared_committed_cow_pages); + auto clone = TRY(try_create_with_shared_cow(*this, *new_shared_committed_cow_pages, move(new_physical_pages))); // Both original and clone become COW. So create a COW map for ourselves // or reset all pages to be copied again if we were previously cloned - ensure_or_reset_cow_map(); + TRY(ensure_or_reset_cow_map()); + + m_shared_committed_cow_pages = move(new_shared_committed_cow_pages); if (m_unused_committed_pages.has_value() && !m_unused_committed_pages->is_empty()) { // The parent vmobject didn't use up all committed pages. When @@ -122,6 +122,15 @@ ErrorOr<NonnullRefPtr<AnonymousVMObject>> AnonymousVMObject::try_create_for_phys return adopt_nonnull_ref_or_enomem(new (nothrow) AnonymousVMObject(paddr, move(new_physical_pages))); } +ErrorOr<NonnullRefPtr<AnonymousVMObject>> AnonymousVMObject::try_create_with_shared_cow(AnonymousVMObject const& other, NonnullRefPtr<SharedCommittedCowPages> shared_committed_cow_pages, FixedArray<RefPtr<PhysicalPage>>&& new_physical_pages) +{ + auto vmobject = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) AnonymousVMObject(other, move(shared_committed_cow_pages), move(new_physical_pages)))); + + TRY(vmobject->ensure_cow_map()); + + return vmobject; +} + AnonymousVMObject::AnonymousVMObject(FixedArray<RefPtr<PhysicalPage>>&& new_physical_pages, AllocationStrategy strategy, Optional<CommittedPhysicalPageSet> committed_pages) : VMObject(move(new_physical_pages)) , m_unused_committed_pages(move(committed_pages)) @@ -155,7 +164,6 @@ AnonymousVMObject::AnonymousVMObject(AnonymousVMObject const& other, NonnullRefP , m_shared_committed_cow_pages(move(shared_committed_cow_pages)) , m_purgeable(other.m_purgeable) { - ensure_cow_map(); } AnonymousVMObject::~AnonymousVMObject() @@ -250,19 +258,20 @@ NonnullRefPtr<PhysicalPage> AnonymousVMObject::allocate_committed_page(Badge<Reg return m_unused_committed_pages->take_one(); } -Bitmap& AnonymousVMObject::ensure_cow_map() +ErrorOr<void> AnonymousVMObject::ensure_cow_map() { if (m_cow_map.is_null()) - m_cow_map = Bitmap::try_create(page_count(), true).release_value_but_fixme_should_propagate_errors(); - return m_cow_map; + m_cow_map = TRY(Bitmap::try_create(page_count(), true)); + return {}; } -void AnonymousVMObject::ensure_or_reset_cow_map() +ErrorOr<void> AnonymousVMObject::ensure_or_reset_cow_map() { if (m_cow_map.is_null()) - ensure_cow_map(); + TRY(ensure_cow_map()); else m_cow_map.fill(true); + return {}; } bool AnonymousVMObject::should_cow(size_t page_index, bool is_shared) const @@ -275,9 +284,11 @@ bool AnonymousVMObject::should_cow(size_t page_index, bool is_shared) const return !m_cow_map.is_null() && m_cow_map.get(page_index); } -void AnonymousVMObject::set_should_cow(size_t page_index, bool cow) +ErrorOr<void> AnonymousVMObject::set_should_cow(size_t page_index, bool cow) { - ensure_cow_map().set(page_index, cow); + TRY(ensure_cow_map()); + m_cow_map.set(page_index, cow); + return {}; } size_t AnonymousVMObject::cow_pages() const @@ -307,7 +318,7 @@ PageFaultResponse AnonymousVMObject::handle_cow_fault(size_t page_index, Virtual 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); + MUST(set_should_cow(page_index, false)); // If we received a COW fault, we already have a cow map allocated, so this is infallible if (m_shared_committed_cow_pages) { m_shared_committed_cow_pages->uncommit_one(); @@ -350,7 +361,7 @@ PageFaultResponse AnonymousVMObject::handle_cow_fault(size_t page_index, Virtual MM.unquickmap_page(); } page_slot = move(page); - set_should_cow(page_index, false); + MUST(set_should_cow(page_index, false)); // If we received a COW fault, we already have a cow map allocated, so this is infallible return PageFaultResponse::Continue; } |