[RFC PATCH v2 1/3] meminfo_extra: introduce meminfo extra
From: Jaewon Kim <hidden>
Date: 2020-03-23 08:05:19
Also in:
linux-mm, lkml
Subsystem:
filesystems (vfs and infrastructure), memory management, memory management - core, memory management - page allocator, proc filesystem, the rest · Maintainers:
Alexander Viro, Christian Brauner, Andrew Morton, David Hildenbrand, Vlastimil Babka, Linus Torvalds
Provide APIs to drivers so that they can show its memory usage on
/proc/meminfo_extra.
int register_meminfo_extra(atomic_long_t *val, int shift,
const char *name);
int unregister_meminfo_extra(atomic_long_t *val);
Signed-off-by: Jaewon Kim <redacted>
---
v2: move to /proc/meminfo_extra as a new file, meminfo_extra.c
use rcu to reduce lock overhead
v1: print info at /proc/meminfo
---
fs/proc/Makefile | 1 +
fs/proc/meminfo_extra.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/mm.h | 4 ++
mm/page_alloc.c | 1 +
4 files changed, 129 insertions(+)
create mode 100644 fs/proc/meminfo_extra.c
diff --git a/fs/proc/Makefile b/fs/proc/Makefile
index bd08616ed8ba..83d2f55591c6 100644
--- a/fs/proc/Makefile
+++ b/fs/proc/Makefile@@ -19,6 +19,7 @@ proc-y += devices.o proc-y += interrupts.o proc-y += loadavg.o proc-y += meminfo.o +proc-y += meminfo_extra.o proc-y += stat.o proc-y += uptime.o proc-y += util.o
diff --git a/fs/proc/meminfo_extra.c b/fs/proc/meminfo_extra.c
new file mode 100644
index 000000000000..bd3f0d2b7fb7
--- /dev/null
+++ b/fs/proc/meminfo_extra.c@@ -0,0 +1,123 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/mm.h> +#include <linux/proc_fs.h> +#include <linux/seq_file.h> +#include <linux/slab.h> + +static void show_val_kb(struct seq_file *m, const char *s, unsigned long num) +{ + seq_put_decimal_ull_width(m, s, num << (PAGE_SHIFT - 10), 8); + seq_write(m, " kB\n", 4); +} + +static LIST_HEAD(meminfo_head); +static DEFINE_SPINLOCK(meminfo_lock); + +#define NAME_SIZE 15 +#define NAME_BUF_SIZE (NAME_SIZE + 2) /* ':' and '\0' */ + +struct meminfo_extra { + struct list_head list; + atomic_long_t *val; + int shift_for_page; + char name[NAME_BUF_SIZE]; + char name_pad[NAME_BUF_SIZE]; +}; + +int register_meminfo_extra(atomic_long_t *val, int shift, const char *name) +{ + struct meminfo_extra *meminfo, *memtemp; + int len; + int error = 0; + + meminfo = kzalloc(sizeof(*meminfo), GFP_KERNEL); + if (!meminfo) { + error = -ENOMEM; + goto out; + } + + meminfo->val = val; + meminfo->shift_for_page = shift; + strncpy(meminfo->name, name, NAME_SIZE); + len = strlen(meminfo->name); + meminfo->name[len] = ':'; + strncpy(meminfo->name_pad, meminfo->name, NAME_BUF_SIZE); + while (++len < NAME_BUF_SIZE - 1) + meminfo->name_pad[len] = ' '; + + spin_lock(&meminfo_lock); + list_for_each_entry_rcu(memtemp, &meminfo_head, list) { + if (memtemp->val == val) { + error = -EINVAL; + break; + } + } + if (!error) + list_add_tail_rcu(&meminfo->list, &meminfo_head); + spin_unlock(&meminfo_lock); + if (error) + kfree(meminfo); +out: + + return error; +} +EXPORT_SYMBOL(register_meminfo_extra); + +int unregister_meminfo_extra(atomic_long_t *val) +{ + struct meminfo_extra *memtemp; + int error = -EINVAL; + + spin_lock(&meminfo_lock); + list_for_each_entry_rcu(memtemp, &meminfo_head, list) { + if (memtemp->val == val) { + list_del_rcu(&memtemp->list); + error = 0; + break; + } + } + spin_unlock(&meminfo_lock); + if (!error) { + synchronize_rcu(); + kfree(memtemp); + } + + return error; +} +EXPORT_SYMBOL(unregister_meminfo_extra); + +static void __meminfo_extra(struct seq_file *m) +{ + struct meminfo_extra *memtemp; + unsigned long nr_page; + + rcu_read_lock(); + list_for_each_entry_rcu(memtemp, &meminfo_head, list) { + nr_page = (unsigned long)atomic_long_read(memtemp->val); + nr_page = nr_page >> memtemp->shift_for_page; + if (m) + show_val_kb(m, memtemp->name_pad, nr_page); + else + pr_cont("%s%lukB ", memtemp->name, nr_page); + } + rcu_read_unlock(); +} + +void show_meminfo_extra(void) +{ + __meminfo_extra(NULL); +} + +static int meminfo_extra_proc_show(struct seq_file *m, void *v) +{ + __meminfo_extra(m); + + return 0; +} + +static int __init proc_meminfo_extra_init(void) +{ + proc_create_single("meminfo_extra", 0, NULL, meminfo_extra_proc_show); + return 0; +} +fs_initcall(proc_meminfo_extra_init);
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 52269e56c514..55317161ab57 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h@@ -2898,6 +2898,10 @@ void __init setup_nr_node_ids(void); static inline void setup_nr_node_ids(void) {} #endif +void show_meminfo_extra(void); +int register_meminfo_extra(atomic_long_t *val, int shift, const char *name); +int unregister_meminfo_extra(atomic_long_t *val); + extern int memcmp_pages(struct page *page1, struct page *page2); static inline int pages_identical(struct page *page1, struct page *page2)
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 3c4eb750a199..db1be9a39783 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c@@ -5229,6 +5229,7 @@ void show_free_areas(unsigned int filter, nodemask_t *nodemask) struct zone *zone; pg_data_t *pgdat; + show_meminfo_extra(); for_each_populated_zone(zone) { if (show_mem_node_skip(filter, zone_to_nid(zone), nodemask)) continue;
--
2.13.7