From dc00b6d99a468b5fc5e73985eefb3861cb3ef926 Mon Sep 17 00:00:00 2001 From: Sudarshan Rajagopalan Date: Tue, 25 Aug 2020 17:24:14 -0700 Subject: [PATCH] proc/meminfo: include offlined region for mem total MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When memory block is logically offlined, it is still part of System RAM but is inactive, and can be made active or Onlined anytime. Though from the perspective of kernel which is giving the “current usable memory in the system" info to userspace via MemTotal, when active-mode memory onlining is enabled, the offlined blocks can be onlined when there is memory pressure (on demand) and thus can be added as part of total available memory in the system. Change-Id: I3d6acbe5b05c33c60ac3f1346977f5a72e4d5897 Signed-off-by: Sudarshan Rajagopalan --- drivers/base/memory.c | 29 +++++++++++++++++++++++++++++ fs/proc/meminfo.c | 2 ++ include/linux/memory.h | 2 ++ 3 files changed, 33 insertions(+) diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 2f71f61efcad..d566d60abf54 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -982,3 +982,32 @@ int for_each_memory_block(void *arg, walk_memory_blocks_func_t func) return bus_for_each_dev(&memory_subsys, NULL, &cb_data, for_each_memory_block_cb); } + +static int check_memblock_offlined(struct memory_block *mem, void *arg) +{ + unsigned long *nr_pages_offlined = (unsigned long *)arg; + + if (is_memblock_offlined(mem)) + *nr_pages_offlined += memory_block_size_bytes() / PAGE_SIZE; + + return 0; +} + +/** + * get_offlined_pages_count - get total pages offlined in the system + * + * This function walks through all the memory blocks present and gives + * the total offlined pages count in the system. + * + */ +unsigned long get_offlined_pages_count(void) +{ + unsigned long nr_pages_offlined = 0; + + lock_device_hotplug_sysfs(); + for_each_memory_block(&nr_pages_offlined, check_memblock_offlined); + unlock_device_hotplug(); + + return nr_pages_offlined; + +} diff --git a/fs/proc/meminfo.c b/fs/proc/meminfo.c index 49768005a79e..a678d7ecc8ad 100644 --- a/fs/proc/meminfo.c +++ b/fs/proc/meminfo.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -53,6 +54,7 @@ static int meminfo_proc_show(struct seq_file *m, void *v) pages[lru] = global_node_page_state(NR_LRU_BASE + lru); available = si_mem_available(); + i.totalram += get_offlined_pages_count(); sreclaimable = global_node_page_state(NR_SLAB_RECLAIMABLE); sunreclaim = global_node_page_state(NR_SLAB_UNRECLAIMABLE); diff --git a/include/linux/memory.h b/include/linux/memory.h index 4c75dae8dd29..ebda8bf060a4 100644 --- a/include/linux/memory.h +++ b/include/linux/memory.h @@ -131,11 +131,13 @@ extern int for_each_memory_block(void *arg, walk_memory_blocks_func_t func); }) #define register_hotmemory_notifier(nb) register_memory_notifier(nb) #define unregister_hotmemory_notifier(nb) unregister_memory_notifier(nb) +extern unsigned long get_offlined_pages_count(void); #else #define hotplug_memory_notifier(fn, pri) ({ 0; }) /* These aren't inline functions due to a GCC bug. */ #define register_hotmemory_notifier(nb) ({ (void)(nb); 0; }) #define unregister_hotmemory_notifier(nb) ({ (void)(nb); }) +static inline unsigned long get_offlined_pages_count(void) { return 0; } #endif /*