1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 16:37:35 +00:00

Kernel: Handle AnonymousVMObject allocation failure when forking

Thanks to all the RAII, AnonymousVMObject::try_clone() can now
gracefully handle allocation failure.
This commit is contained in:
Andreas Kling 2021-08-04 22:58:58 +02:00
parent 0672163840
commit 89a9ae7d0c
2 changed files with 13 additions and 9 deletions

View file

@ -46,19 +46,21 @@ RefPtr<VMObject> AnonymousVMObject::try_clone()
// one would keep the one it still has. This ensures that the original // one would keep the one it still has. This ensures that the original
// one and this one, as well as the clone have sufficient resources // one and this one, as well as the clone have sufficient resources
// to cow all pages as needed // to cow all pages as needed
m_shared_committed_cow_pages = try_create<SharedCommittedCowPages>(committed_pages.release_value()); auto new_shared_committed_cow_pages = try_create<SharedCommittedCowPages>(committed_pages.release_value());
if (!m_shared_committed_cow_pages) if (!new_shared_committed_cow_pages)
return {}; return {};
auto clone = adopt_ref_if_nonnull(new (nothrow) AnonymousVMObject(*this, *new_shared_committed_cow_pages));
if (!clone)
return {};
m_shared_committed_cow_pages = move(new_shared_committed_cow_pages);
// Both original and clone become COW. So create a COW map for ourselves // 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 // or reset all pages to be copied again if we were previously cloned
ensure_or_reset_cow_map(); ensure_or_reset_cow_map();
// FIXME: If this allocation fails, we need to rollback all changes.
auto clone = adopt_ref_if_nonnull(new (nothrow) AnonymousVMObject(*this));
VERIFY(clone);
if (m_unused_committed_pages.has_value() && !m_unused_committed_pages->is_empty()) { if (m_unused_committed_pages.has_value() && !m_unused_committed_pages->is_empty()) {
// The parent vmobject didn't use up all committed pages. When // The parent vmobject didn't use up all committed pages. When
// cloning (fork) we will overcommit. For this purpose we drop all // cloning (fork) we will overcommit. For this purpose we drop all
@ -153,9 +155,9 @@ AnonymousVMObject::AnonymousVMObject(Span<NonnullRefPtr<PhysicalPage>> physical_
} }
} }
AnonymousVMObject::AnonymousVMObject(AnonymousVMObject const& other) AnonymousVMObject::AnonymousVMObject(AnonymousVMObject const& other, NonnullRefPtr<SharedCommittedCowPages> shared_committed_cow_pages)
: VMObject(other) : VMObject(other)
, m_shared_committed_cow_pages(other.m_shared_committed_cow_pages) , m_shared_committed_cow_pages(move(shared_committed_cow_pages))
, m_purgeable(other.m_purgeable) , m_purgeable(other.m_purgeable)
{ {
ensure_cow_map(); ensure_cow_map();

View file

@ -39,10 +39,12 @@ public:
size_t purge(); size_t purge();
private: private:
class SharedCommittedCowPages;
explicit AnonymousVMObject(size_t, AllocationStrategy, Optional<CommittedPhysicalPageSet>); explicit AnonymousVMObject(size_t, AllocationStrategy, Optional<CommittedPhysicalPageSet>);
explicit AnonymousVMObject(PhysicalAddress, size_t); explicit AnonymousVMObject(PhysicalAddress, size_t);
explicit AnonymousVMObject(Span<NonnullRefPtr<PhysicalPage>>); explicit AnonymousVMObject(Span<NonnullRefPtr<PhysicalPage>>);
explicit AnonymousVMObject(AnonymousVMObject const&); explicit AnonymousVMObject(AnonymousVMObject const&, NonnullRefPtr<SharedCommittedCowPages>);
virtual StringView class_name() const override { return "AnonymousVMObject"sv; } virtual StringView class_name() const override { return "AnonymousVMObject"sv; }