Kernel: Share committed COW pages between whole VMObject lineage
When cloning an AnonymousVMObject, committed COW pages are shared between the parent and child object. Whicever object COW's first will take the shared committed page, and if the other object ends up doing a COW as well, it will notice that the page is no longer shared by two objects and simple remap it as read/write. When a child is COW'ed again, while still having shared committed pages with its own parent, the grandchild object will now join in the sharing pool with its parent and grandparent. This means that the first 2 of 3 objects that COW will draw from the shared committed pages, and 3rd will remap read/write. Previously, we would "fork" the shared committed pages when cloning, which could lead to a situation where the grandparent held on to 1 of the 3 needed shared committed pages. If both the child and grandchild COW'ed, they wouldn't have enough pages, and since the grandparent maintained an extra +1 ref count on the page, it wasn't possible to to remap read/write.
This commit is contained in:
parent
bccdc08487
commit
2c0df5e7e7
Notes:
sideshowbarker
2024-07-18 07:45:01 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/2c0df5e7e7a
1 changed files with 10 additions and 11 deletions
|
@ -39,17 +39,16 @@ RefPtr<VMObject> AnonymousVMObject::try_clone()
|
|||
if (!MM.commit_user_physical_pages(new_cow_pages_needed))
|
||||
return {};
|
||||
|
||||
// Create or replace the committed cow pages. When cloning a previously
|
||||
// cloned vmobject, we want to essentially "fork", leaving us and the
|
||||
// new clone with one set of shared committed cow pages, and 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
|
||||
// to cow all pages as needed
|
||||
m_shared_committed_cow_pages = try_create<CommittedCowPages>(new_cow_pages_needed);
|
||||
|
||||
if (!m_shared_committed_cow_pages) {
|
||||
MM.uncommit_user_physical_pages(new_cow_pages_needed);
|
||||
return {};
|
||||
if (m_shared_committed_cow_pages) {
|
||||
// We already have shared committed COW pages with another object.
|
||||
// That sharing pool grows and the clone joins it.
|
||||
m_shared_committed_cow_pages->m_committed_pages += new_cow_pages_needed;
|
||||
} else {
|
||||
m_shared_committed_cow_pages = try_create<CommittedCowPages>(new_cow_pages_needed);
|
||||
if (!m_shared_committed_cow_pages) {
|
||||
MM.uncommit_user_physical_pages(new_cow_pages_needed);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
// Both original and clone become COW. So create a COW map for ourselves
|
||||
|
|
Loading…
Add table
Reference in a new issue