Repository navigation
Report pages shared copy-on-write as Shared in /proc/[pid]/smaps. - #15430
Open
copybara-service[bot] wants to merge 1 commit into
Open
copybara-service[bot] wants to merge 1 commit into
copybara-service[bot] wants to merge 1 commit into
Conversation
copybara-service
Bot
force-pushed
the
test/cl994851982
branch
2 times, most recently
from
October 7, 2026 16:23
d937d65 to
2fc6e6f
Compare
copybara-service
Bot
requested review from
EtiennePerot and
fvoznika
as code owners
October 7, 2026 16:23
copybara-service
Bot
force-pushed
the
test/cl994851982
branch
3 times, most recently
from
October 7, 2026 21:59
6936ff5 to
42fde64
Compare
copybara-service
Bot
force-pushed
the
test/cl994851982
branch
from
October 7, 2026 22:22
42fde64 to
cc0d9dc
Compare
smaps reported every resident page of a writable vma as Private_Dirty and never reported Shared_Clean or Shared_Dirty. On Linux, a private anonymous page that a fork()ed child still shares with its parent has mapcount 2 and is Shared_Dirty in both (fs/proc/task_mmu.c:smaps_account()); it becomes Private_Dirty in each once one of them writes it and breaks copy-on-write. Programs measure copy-on-write this way: Valkey's and Redis's fork()ed RDB/AOF child sums Private_Dirty from its own smaps (zmalloc_get_private_dirty) and reports it as current_cow_size and rdb_last_cow_size. Under gVisor the child's COW size starts at the whole heap and never grows as the parent writes, so Valkey's "Test child sending info" fails with "COW info wasn't reported". For private copy-on-write pmas, smaps now reports pages on which the MemoryFile holds more than one reference as shared (dirty if the vma is writable, clean otherwise), and divides each such page among its references in Pss, as Linux divides by mapcount. A copy-on-write page's references are the pmas mapping it. Other private pmas are skipped because their extra references are pins, which Linux reports as private. Reading smaps now walks the MemoryFile's reference counts for copy-on-write pmas. In the worst layouts measured (1 GiB forked, then every other page written by the parent, so that each page is its own pma or reference-count segment) a read takes 4-32 ms instead of 0.2-12 ms; Linux, which walks every page table entry, takes 11-57 ms for the same layouts on the same hosts. Tests: proc_pid_smaps_test ForkCopyOnWrite fails before this change on runsc (Shared_Dirty 0, Private_Dirty 64 kB and Pss 64 kB right after fork) and passes after it and on native. FUTURE_COPYBARA_INTEGRATE_REVIEW=#15437 from tamird:tuntap-leak-check 3b35968 PiperOrigin-RevId: 994851982
copybara-service
Bot
force-pushed
the
test/cl994851982
branch
from
October 7, 2026 23:37
cc0d9dc to
1922621
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Report pages shared copy-on-write as Shared in /proc/[pid]/smaps.
smaps reported every resident page of a writable vma as Private_Dirty and
never reported Shared_Clean or Shared_Dirty. On Linux, a private anonymous page
that a fork()ed child still shares with its parent has mapcount 2 and is
Shared_Dirty in both (fs/proc/task_mmu.c:smaps_account()); it becomes
Private_Dirty in each once one of them writes it and breaks copy-on-write.
Programs measure copy-on-write this way: Valkey's and Redis's fork()ed RDB/AOF
child sums Private_Dirty from its own smaps (zmalloc_get_private_dirty) and
reports it as current_cow_size and rdb_last_cow_size. Under gVisor the child's
COW size starts at the whole heap and never grows as the parent writes, so
Valkey's "Test child sending info" fails with "COW info wasn't reported".
For private copy-on-write pmas, smaps now reports pages on which the
MemoryFile holds more than one reference as shared (dirty if the vma is
writable, clean otherwise), and divides each such page among its references in
Pss, as Linux divides by mapcount. A copy-on-write page's references are the
pmas mapping it. Other private pmas are skipped because their extra references
are pins, which Linux reports as private.
Reading smaps now walks the MemoryFile's reference counts for copy-on-write
pmas. In the worst layouts measured (1 GiB forked, then every other page
written by the parent, so that each page is its own pma or reference-count
segment) a read takes 4-32 ms instead of 0.2-12 ms; Linux, which walks every
page table entry, takes 11-57 ms for the same layouts on the same hosts.
Tests: proc_pid_smaps_test ForkCopyOnWrite fails before this change on runsc
(Shared_Dirty 0, Private_Dirty 64 kB and Pss 64 kB right after fork) and
passes after it and on native.
FUTURE_COPYBARA_INTEGRATE_REVIEW=#15437 from tamird:tuntap-leak-check 3b35968