lkml.org 
[lkml]   [2022]   [Sep]   [4]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Subject[PATCH v2 2/3] mm, page_owner: Add page_owner_stacks file to print out only stacks and their counter
Date
We might be only interested in knowing about stacks <-> count
relationship, so instead of having to fiddle with page_owner
output and screen through pfns, let us add a new file called
'page_owner_stacks' that does just that.
By cating such file, we will get all the stacktraces followed by
its counter, so we can have a more global view.

Signed-off-by: Oscar Salvador <osalvador@suse.de>
---
include/linux/stackdepot.h | 1 +
lib/stackdepot.c | 40 ++++++++++++++++++++++++++++++++++++++
mm/page_owner.c | 25 ++++++++++++++++++++++++
3 files changed, 66 insertions(+)

diff --git a/include/linux/stackdepot.h b/include/linux/stackdepot.h
index 4e3a88f135ee..19d3f8295df8 100644
--- a/include/linux/stackdepot.h
+++ b/include/linux/stackdepot.h
@@ -25,6 +25,7 @@ depot_stack_handle_t __stack_depot_save(unsigned long *entries,
gfp_t gfp_flags, bool can_alloc,
enum stack_depot_action action);
void stack_depot_dec_count(depot_stack_handle_t handle);
+int stack_depot_print_stacks_threshold(char *buf, size_t size, loff_t *pos);

/*
* Every user of stack depot has to call stack_depot_init() during its own init
diff --git a/lib/stackdepot.c b/lib/stackdepot.c
index a806ef58a385..a198b2dbe3fb 100644
--- a/lib/stackdepot.c
+++ b/lib/stackdepot.c
@@ -565,3 +565,43 @@ depot_stack_handle_t stack_depot_save_action(unsigned long *entries,
return __stack_depot_save(entries, nr_entries, alloc_flags, true, action);
}
EXPORT_SYMBOL_GPL(stack_depot_save_action);
+
+int stack_depot_print_stacks_threshold(char *buf, size_t size, loff_t *pos)
+{
+ int i = *pos, ret = 0;
+ struct stack_record **stacks, *stack;
+ static struct stack_record *last = NULL;
+ unsigned long stack_table_entries = stack_hash_mask + 1;
+
+ /* Continue from the last stack if we have one */
+ if (last) {
+ stack = last->next;
+ } else {
+new_table:
+ stacks = &stack_table[i];
+ stack = (struct stack_record *)stacks;
+ }
+
+ for (; stack; stack = stack->next) {
+ if (!stack->size || stack->size < 0 ||
+ stack->size > size || stack->handle.valid != 1 ||
+ refcount_read(&stack->count) < 1)
+ continue;
+
+ ret += stack_trace_snprint(buf, size, stack->entries, stack->size, 0);
+ ret += scnprintf(buf + ret, size - ret, "stack count: %d\n\n",
+ refcount_read(&stack->count));
+ last = stack;
+ return ret;
+ }
+
+ i++;
+ *pos = i;
+ last = NULL;
+
+ /* Keep looking all tables for valid stacks */
+ if (i < stack_table_entries)
+ goto new_table;
+
+ return 0;
+}
diff --git a/mm/page_owner.c b/mm/page_owner.c
index 8730f377fa91..d88e6b4aefa0 100644
--- a/mm/page_owner.c
+++ b/mm/page_owner.c
@@ -664,6 +664,29 @@ static void init_early_allocated_pages(void)
init_zones_in_node(pgdat);
}

+static ssize_t read_page_owner_stacks(struct file *file, char __user *buf,
+ size_t count, loff_t *pos)
+{
+ char *kbuf;
+ int ret = 0;
+
+ count = min_t(size_t, count, PAGE_SIZE);
+ kbuf = kmalloc(count, GFP_KERNEL);
+ if (!kbuf)
+ return -ENOMEM;
+
+ ret += stack_depot_print_stacks_threshold(kbuf, count, pos);
+ if (copy_to_user(buf, kbuf, ret))
+ ret = -EFAULT;
+
+ kfree(kbuf);
+ return ret;
+}
+
+static const struct file_operations proc_page_owner_stacks = {
+ .read = read_page_owner_stacks,
+};
+
static const struct file_operations proc_page_owner_operations = {
.read = read_page_owner,
};
@@ -677,6 +700,8 @@ static int __init pageowner_init(void)

debugfs_create_file("page_owner", 0400, NULL, NULL,
&proc_page_owner_operations);
+ debugfs_create_file("page_owner_stacks", 0400, NULL, NULL,
+ &proc_page_owner_stacks);

return 0;
}
--
2.35.3
\
 
 \ /
  Last update: 2022-09-05 05:12    [W:0.515 / U:0.400 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site