From eab69cfe9c0db96f4fdf8a918314401244395808 Mon Sep 17 00:00:00 2001 From: Jaewon Kim Date: Tue, 7 May 2024 17:26:27 +0900 Subject: [PATCH] ANDROID: memblock: introduce an early param for memsize So far there was only debugfs interface to see the memsize results. As debugfs is not allowed on the production binary, procfs would be preferred than debugfs. To work as same as possible like the upstream, provide an option to disable memsize. With this change, memsize will be disabled by default, and memsize would be enabled as procfs or debugfs through the option in the cmdline. i.e. memblock_memsize=none (default) memblock_memsize=procfs memblock_memsize=debugfs For your information, let me explain more about this memsize solution. Some of memory regions can be reserved for a specific purpose. They are usually defined through reserved-memory in device tree. If only size without address is specified in device tree, the address of the region will be determined at boot time. We may find the address of the memory regions through booting log, but it does not show all. And it could be hard to catch the very beginning log. The memblock_dump_all shows all memblock status but it does not show region name and its information is difficult to summarize. 1. How to use The memsize solution shows reserved memory status and boot time kernel memory size. To enable and see it, add one of this on the cmdline. memblock_memsize=procfs memblock_memsize=debugfs To see the address, do the following command. echo 1 > /proc/sys/kernel/kptr_restrict To see the results, do the following command. cat /proc/memsize or cat /DEBUGFS/memblock/memsize 2. How it works This is how the main internal logic works. The kernel size will be tracked by adding hooking code into memblock_[add_range|remove_range], and other reserved regions will be recored by calling memblock_memsize_record. A. tracking kernel size During the boot, memblock allocation and free are tracked by every call of memblock_[add_range|remove_range]. The total size will be saved at the memsize_kinit variable. B. tracking non kernel size The reserved memory regions defined in device tree and some special regions are recorded by calling memblock_memsize_record. B.1. reserved region in the device tree and elfcorehdr early_init_fdt_scan_reserved_mem memblock_memsize_detect_hole [memsize] memblock_memsize_record [memsize] memblock_memsize_disable_tracking [memsize] fdt_scan_reserved_mem fdt_reserve_elfcorehdr memblock_memsize_record [memsize] memblock_memsize_record for memreserve [memsize] fdt_init_reserved_mem memblock_memsize_record [memsize] memblock_memsize_enable_tracking [memsize] B2. add the default cma region dma_contiguous_reserve_area memblock_memsize_record [memsize] C. userspace interface The recorded information can be shown by userspace interface. procfs/debugfs memblock_memsize_show [memsize] memblock_memsize_check_size [memsize] memblock_memsize_free [memsize] memblock_memsize_record [memsize] Bug: 340432773 Signed-off-by: Jaewon Kim Change-Id: Ideefb9de0cbb9ebc91af7d3c79abf3571db27481 --- mm/memblock.c | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/mm/memblock.c b/mm/memblock.c index 35c438146233..74a3c26df52e 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "internal.h" @@ -2086,6 +2087,30 @@ static unsigned long memsize_ro __initdata_memblock; static unsigned long memsize_bss __initdata_memblock; static long memsize_reusable_size; +enum memblock_memsize_state { + MEMBLOCK_MEMSIZE_NONE = 0, + MEMBLOCK_MEMSIZE_DEBUGFS, + MEMBLOCK_MEMSIZE_PROCFS, +}; + +static enum memblock_memsize_state memsize_state __initdata_memblock = MEMBLOCK_MEMSIZE_NONE; + +static int __init early_memblock_memsize(char *str) +{ + if (!str) + return -EINVAL; + if (strcmp(str, "none") == 0) + memsize_state = MEMBLOCK_MEMSIZE_NONE; + else if (strcmp(str, "debugfs") == 0) + memsize_state = MEMBLOCK_MEMSIZE_DEBUGFS; + else if (strcmp(str, "procfs") == 0) + memsize_state = MEMBLOCK_MEMSIZE_PROCFS; + else + return -EINVAL; + return 0; +} +early_param("memblock_memsize", early_memblock_memsize); + void __init memblock_memsize_enable_tracking(void) { memblock_memsize_tracking = true; @@ -2246,6 +2271,9 @@ void __init_memblock memblock_memsize_record(const char *name, phys_addr_t base, struct memsize_rgn_struct *rgn; phys_addr_t end; + if (name && memsize_state == MEMBLOCK_MEMSIZE_NONE) + return; + if (memsize_rgn_count == CONFIG_MAX_MEMBLOCK_MEMSIZE) { pr_err("not enough space on memsize_rgn\n"); return; @@ -2882,8 +2910,12 @@ static int __init memblock_init_debugfs(void) &memblock_debug_fops); #endif #ifdef CONFIG_MEMBLOCK_MEMSIZE - debugfs_create_file("memsize", 0444, root, - NULL, &memblock_memsize_fops); + if (memsize_state == MEMBLOCK_MEMSIZE_DEBUGFS) + debugfs_create_file("memsize", 0444, root, NULL, + &memblock_memsize_fops); + else if (memsize_state == MEMBLOCK_MEMSIZE_PROCFS) + proc_create_single("memsize", 0, NULL, + memblock_memsize_show); #endif return 0;