aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKalesh Singh <kaleshsingh@google.com>2024-03-18 17:27:59 -0700
committerKalesh Singh <kaleshsingh@google.com>2024-05-02 11:06:53 -0700
commit5134762efa7be5d9d4006dba0d91039237bb7b2c (patch)
treef83a66a7e5f9ce53e6d33eb048ed38048b3a086b
parentc5c1d19ebb6d675f3028906be34d447c14ffbce5 (diff)
downloadbionic-5134762efa7be5d9d4006dba0d91039237bb7b2c.tar.gz
bionic: loader: Drop readahead padding pages
These are padding pages are only needed to layout the ELF to be compatible with max-page-size. They are zero-filled (holes) and can be dropped from the page cache. The madvise() here is a special case that also serves to hint to the kernel what part of the segment is padding. For example the kernel then shows these padding regions as PROT_NONE VMAs (labeled [page size compat]) in /proc/*/maps. Note: This doesn't use backing vm_area_structs, so doesn't consume additional slab memory. Before: ❯ cf-adb shell cat /proc/1/maps | grep -A1 'libbase.so$' 7f8d13600000-7f8d13614000 r--p 00000000 fe:09 21909460 /system/lib64/libbase.so 7f8d13614000-7f8d13638000 r-xp 00014000 fe:09 21909460 /system/lib64/libbase.so 7f8d13638000-7f8d1363c000 r--p 00038000 fe:09 21909460 /system/lib64/libbase.so 7f8d1363c000-7f8d1363d000 rw-p 0003c000 fe:09 21909460 /system/lib64/libbase.so Segments appear extended in /proc/<pid>/maps After: ❯ cf-adb shell cat /proc/1/maps | grep -A1 'libbase.so$' 7f3650043000-7f3650054000 r--p 00000000 fe:09 21906900 /system/lib64/libbase.so 7f3650054000-7f3650057000 ---p 00000000 00:00 0 [page size compat] 7f3650057000-7f3650079000 r-xp 00014000 fe:09 21906900 /system/lib64/libbase.so 7f3650079000-7f365007b000 ---p 00000000 00:00 0 [page size compat] 7f365007b000-7f365007c000 r--p 00038000 fe:09 21906900 /system/lib64/libbase.so 7f365007c000-7f365007f000 ---p 00000000 00:00 0 [page size compat] 7f365007f000-7f3650080000 rw-p 0003c000 fe:09 21906900 /system/lib64/libbase.so Segments maintain PROT_NONE gaps ("[page size compat]") for app compatiblity but these are not backed by actual slab VMA memory. Bug: 330117029 Bug: 327600007 Bug: 330767927 Bug: 328266487 Bug: 329803029 Test: Manual - Launch Free Fire Chaos app Change-Id: Ic50540e247b4294eb08f8cf70e74bd2bf6606684 Signed-off-by: Kalesh Singh <kaleshsingh@google.com>
-rw-r--r--linker/linker_phdr.cpp26
1 files changed, 22 insertions, 4 deletions
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index 80f1ad9d4..fa712a10a 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -918,10 +918,28 @@ bool ElfReader::LoadSegments() {
// 2) Break the COW backing, faulting in new anon pages for a region
// that will not be used.
- // _seg_file_end = unextended seg_file_end
- uint64_t _seg_file_end = seg_start + phdr->p_filesz;
- if ((phdr->p_flags & PF_W) != 0 && page_offset(_seg_file_end) > 0) {
- memset(reinterpret_cast<void*>(_seg_file_end), 0, kPageSize - page_offset(_seg_file_end));
+ uint64_t unextended_seg_file_end = seg_start + phdr->p_filesz;
+ if ((phdr->p_flags & PF_W) != 0 && page_offset(unextended_seg_file_end) > 0) {
+ memset(reinterpret_cast<void*>(unextended_seg_file_end), 0,
+ kPageSize - page_offset(unextended_seg_file_end));
+ }
+
+ // Pages may be brought in due to readahead.
+ // Drop the padding (zero) pages, to avoid reclaim work later.
+ //
+ // NOTE: The madvise() here is special, as it also serves to hint to the
+ // kernel the portion of the LOAD segment that is padding.
+ //
+ // See: [1] https://android-review.googlesource.com/c/kernel/common/+/3032411
+ // [2] https://android-review.googlesource.com/c/kernel/common/+/3048835
+ uint64_t pad_start = page_end(unextended_seg_file_end);
+ uint64_t pad_end = page_end(seg_file_end);
+ CHECK(pad_start <= pad_end);
+ uint64_t pad_len = pad_end - pad_start;
+ if (page_size_migration_supported() && pad_len > 0 &&
+ madvise(reinterpret_cast<void*>(pad_start), pad_len, MADV_DONTNEED)) {
+ DL_WARN("\"%s\": madvise(0x%" PRIx64 ", 0x%" PRIx64 ", MADV_DONTNEED) failed: %m",
+ name_.c_str(), pad_start, pad_len);
}
seg_file_end = page_end(seg_file_end);