diff options
author | Idan Horowitz <idan.horowitz@gmail.com> | 2022-07-10 16:40:48 +0300 |
---|---|---|
committer | Idan Horowitz <idan.horowitz@gmail.com> | 2022-07-10 22:17:21 +0300 |
commit | 1d96c30488a80602c1e773fe97c48f8711dd0361 (patch) | |
tree | 25cf6501102551b3890e85cf59feb307e423a9fb /Kernel/Memory/AnonymousVMObject.cpp | |
parent | c1fe844da4df3061ac575567f662ad723cc2cccb (diff) | |
download | serenity-1d96c30488a80602c1e773fe97c48f8711dd0361.zip |
Kernel: Stop leaking leftover committed cow pages from forked processes
Since both the parent process and child process hold a reference to the
COW committed set, once the child process exits, the committed COW
pages are effectively leaked, only being slowly re-claimed each time
the parent process writes to one of them, realizing it's no longer
shared, and uncommitting it.
In order to mitigate this we now hold a weak reference the parent
VMObject from which the pages are cloned, and we use it on destruction
when available to drop the reference to the committed set from it as
well.
Diffstat (limited to 'Kernel/Memory/AnonymousVMObject.cpp')
-rw-r--r-- | Kernel/Memory/AnonymousVMObject.cpp | 20 |
1 files changed, 16 insertions, 4 deletions
diff --git a/Kernel/Memory/AnonymousVMObject.cpp b/Kernel/Memory/AnonymousVMObject.cpp index 2c94e67283..59a7ead9d3 100644 --- a/Kernel/Memory/AnonymousVMObject.cpp +++ b/Kernel/Memory/AnonymousVMObject.cpp @@ -124,7 +124,8 @@ ErrorOr<NonnullRefPtr<AnonymousVMObject>> AnonymousVMObject::try_create_for_phys 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)))); + auto weak_parent = TRY(other.try_make_weak_ptr<AnonymousVMObject>()); + auto vmobject = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) AnonymousVMObject(move(weak_parent), move(shared_committed_cow_pages), move(new_physical_pages)))); TRY(vmobject->ensure_cow_map()); @@ -159,14 +160,25 @@ AnonymousVMObject::AnonymousVMObject(FixedArray<RefPtr<PhysicalPage>>&& new_phys { } -AnonymousVMObject::AnonymousVMObject(AnonymousVMObject const& other, NonnullRefPtr<SharedCommittedCowPages> shared_committed_cow_pages, FixedArray<RefPtr<PhysicalPage>>&& new_physical_pages) +AnonymousVMObject::AnonymousVMObject(WeakPtr<AnonymousVMObject> other, NonnullRefPtr<SharedCommittedCowPages> shared_committed_cow_pages, FixedArray<RefPtr<PhysicalPage>>&& new_physical_pages) : VMObject(move(new_physical_pages)) + , m_cow_parent(move(other)) , m_shared_committed_cow_pages(move(shared_committed_cow_pages)) - , m_purgeable(other.m_purgeable) + , m_purgeable(m_cow_parent.strong_ref()->m_purgeable) { } -AnonymousVMObject::~AnonymousVMObject() = default; +AnonymousVMObject::~AnonymousVMObject() +{ + if (!m_shared_committed_cow_pages || m_shared_committed_cow_pages->is_empty()) + return; + auto cow_parent = m_cow_parent.strong_ref(); + if (!cow_parent) + return; + SpinlockLocker lock(cow_parent->m_lock); + if (cow_parent->m_shared_committed_cow_pages == m_shared_committed_cow_pages) + cow_parent->m_shared_committed_cow_pages.clear(); +} size_t AnonymousVMObject::purge() { |