summaryrefslogtreecommitdiff
path: root/Kernel/Memory/AnonymousVMObject.cpp
diff options
context:
space:
mode:
authorIdan Horowitz <idan.horowitz@gmail.com>2022-02-10 19:17:27 +0200
committerIdan Horowitz <idan.horowitz@gmail.com>2022-02-11 17:49:46 +0200
commit8030e2a88f8b6c9a78ac9734fb2c08071f8d3d70 (patch)
tree1594298791eda6cd9f8bda44843b2bce91049f40 /Kernel/Memory/AnonymousVMObject.cpp
parent871a53db760a975a6aa3510b1a5b355152eaa2ef (diff)
downloadserenity-8030e2a88f8b6c9a78ac9734fb2c08071f8d3d70.zip
Kernel: Make AnonymousVMObject COW-Bitmap allocation OOM-fallible
Diffstat (limited to 'Kernel/Memory/AnonymousVMObject.cpp')
-rw-r--r--Kernel/Memory/AnonymousVMObject.cpp39
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;
}