summaryrefslogtreecommitdiff
path: root/Kernel/Memory/AnonymousVMObject.cpp
diff options
context:
space:
mode:
authorIdan Horowitz <idan.horowitz@gmail.com>2022-07-10 16:40:48 +0300
committerIdan Horowitz <idan.horowitz@gmail.com>2022-07-10 22:17:21 +0300
commit1d96c30488a80602c1e773fe97c48f8711dd0361 (patch)
tree25cf6501102551b3890e85cf59feb307e423a9fb /Kernel/Memory/AnonymousVMObject.cpp
parentc1fe844da4df3061ac575567f662ad723cc2cccb (diff)
downloadserenity-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.cpp20
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()
{