mirror of
https://github.com/SerenityOS/serenity
synced 2024-10-14 20:03:29 +00:00
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.
This commit is contained in:
parent
c1fe844da4
commit
1d96c30488
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -46,7 +46,7 @@ private:
|
|||
explicit AnonymousVMObject(FixedArray<RefPtr<PhysicalPage>>&&, AllocationStrategy, Optional<CommittedPhysicalPageSet>);
|
||||
explicit AnonymousVMObject(PhysicalAddress, FixedArray<RefPtr<PhysicalPage>>&&);
|
||||
explicit AnonymousVMObject(FixedArray<RefPtr<PhysicalPage>>&&);
|
||||
explicit AnonymousVMObject(AnonymousVMObject const&, NonnullRefPtr<SharedCommittedCowPages>, FixedArray<RefPtr<PhysicalPage>>&&);
|
||||
explicit AnonymousVMObject(WeakPtr<AnonymousVMObject>, NonnullRefPtr<SharedCommittedCowPages>, FixedArray<RefPtr<PhysicalPage>>&&);
|
||||
|
||||
virtual StringView class_name() const override { return "AnonymousVMObject"sv; }
|
||||
|
||||
|
@ -82,6 +82,7 @@ private:
|
|||
CommittedPhysicalPageSet m_committed_pages;
|
||||
};
|
||||
|
||||
WeakPtr<AnonymousVMObject> m_cow_parent;
|
||||
RefPtr<SharedCommittedCowPages> m_shared_committed_cow_pages;
|
||||
|
||||
bool m_purgeable { false };
|
||||
|
|
Loading…
Reference in a new issue