[PATCH 1/1] stackdepot: interface to check entries and size of stackdepot.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch provides interface to check all the stack enteries
saved in stackdepot so far as well as memory consumed by stackdepot.

1) Take current depot_index and offset to calculate end address for one
	iteration of (/sys/kernel/debug/depot_stack/depot_entries).

2) Fill end marker in every slab to point its end, and then use it while
	traversing all the slabs of stackdepot.

"debugfs code inspired from page_onwer's way of printing BT"

checked on ARM and x86_64.
$cat /sys/kernel/debug/depot_stack/depot_size
Memory consumed by Stackdepot:208 KB

$ cat /sys/kernel/debug/depot_stack/depot_entries
stack count 1 backtrace
 init_page_owner+0x1e/0x210
 start_kernel+0x310/0x3cd
 secondary_startup_64+0xa5/0xb0
 0xffffffffffffffff

Signed-off-by: Vaneet Narang <v.narang@xxxxxxxxxxx>
Signed-off-by: Maninder Singh <maninder1.s@xxxxxxxxxxx>
---
 include/linux/stackdepot.h |   13 +++
 include/linux/stacktrace.h |    6 ++
 lib/stackdepot.c           |  183 ++++++++++++++++++++++++++++++++++++++++++++
 mm/page_owner.c            |    6 --
 4 files changed, 202 insertions(+), 6 deletions(-)

diff --git a/include/linux/stackdepot.h b/include/linux/stackdepot.h
index 7978b3e..dd95b11 100644
--- a/include/linux/stackdepot.h
+++ b/include/linux/stackdepot.h
@@ -23,6 +23,19 @@
 
 typedef u32 depot_stack_handle_t;
 
+/*
+ * structure to store markers which
+ * will be used while printing entries
+ * stored in stackdepot.
+ */
+struct depot_stack_data {
+	int print_offset;
+	int print_counter;
+	int print_index;
+	unsigned long end_marker;
+	void *end_address;
+};
+
 struct stack_trace;
 
 depot_stack_handle_t depot_save_stack(struct stack_trace *trace, gfp_t flags);
diff --git a/include/linux/stacktrace.h b/include/linux/stacktrace.h
index ba29a06..1cfd27d 100644
--- a/include/linux/stacktrace.h
+++ b/include/linux/stacktrace.h
@@ -4,6 +4,12 @@
 
 #include <linux/types.h>
 
+/*
+ * TODO: teach PAGE_OWNER_STACK_DEPTH (__dump_page_owner and save_stack)
+ * to use off stack temporal storage
+ */
+#define PAGE_OWNER_STACK_DEPTH (16)
+
 struct task_struct;
 struct pt_regs;
 
diff --git a/lib/stackdepot.c b/lib/stackdepot.c
index f87d138..3067fcb 100644
--- a/lib/stackdepot.c
+++ b/lib/stackdepot.c
@@ -39,6 +39,8 @@
 #include <linux/stackdepot.h>
 #include <linux/string.h>
 #include <linux/types.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
 
 #define DEPOT_STACK_BITS (sizeof(depot_stack_handle_t) * 8)
 
@@ -111,6 +113,7 @@ static bool init_stack_slab(void **prealloc)
 	int required_size = offsetof(struct stack_record, entries) +
 		sizeof(unsigned long) * size;
 	struct stack_record *stack;
+	void *address;
 
 	required_size = ALIGN(required_size, 1 << STACK_ALLOC_ALIGN);
 
@@ -119,6 +122,17 @@ static bool init_stack_slab(void **prealloc)
 			WARN_ONCE(1, "Stack depot reached limit capacity");
 			return NULL;
 		}
+
+		/*
+		 * write POSION_END if any space left in
+		 * current slab to represent its end.
+		 * later used while printing all the stacks.
+		 */
+		if (depot_offset < STACK_ALLOC_SIZE) {
+			address = stack_slabs[depot_index] + depot_offset;
+			memset(address, POISON_END, sizeof(unsigned long));
+		}
+
 		depot_index++;
 		depot_offset = 0;
 		/*
@@ -285,3 +299,172 @@ depot_stack_handle_t depot_save_stack(struct stack_trace *trace,
 	return retval;
 }
 EXPORT_SYMBOL_GPL(depot_save_stack);
+
+#define DEPOT_SIZE 64
+
+static ssize_t read_depot_stack_size(struct file *file, char __user *buf, size_t count, loff_t *ppos)
+{
+	char kbuf[DEPOT_SIZE];
+	ssize_t ret = 0;
+	unsigned long size = depot_index * (1 << STACK_ALLOC_ORDER) * PAGE_SIZE;
+
+	ret = snprintf(kbuf, count, "Memory consumed by Stackdepot:%lu KB\n", size >> 10);
+	if (ret >= count)
+		return -ENOMEM;
+
+	return simple_read_from_buffer(buf, count, ppos, kbuf, ret);
+}
+
+static ssize_t print_depot_stack(char __user *buf, size_t count, struct stack_trace *trace, loff_t *ppos)
+{
+	char *kbuf;
+	int ret = 0;
+
+	kbuf = kvmalloc(count, GFP_KERNEL);
+	if (!kbuf)
+		return -ENOMEM;
+
+	ret = snprintf(kbuf, count, "stack count %d backtrace\n", (int)*ppos);
+	ret += snprint_stack_trace(kbuf + ret, count - ret, trace, 0);
+	ret += snprintf(kbuf + ret, count - ret, "\n");
+
+	if (ret >= count) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	if (copy_to_user(buf, kbuf, ret))
+		ret = -EFAULT;
+
+err:
+	kvfree(kbuf);
+	return ret;
+}
+
+/*
+ * read_depot_stack()
+ *
+ * function to print all the entries present
+ * in depot_stack database currently in system.
+ */
+static ssize_t read_depot_stack(struct file *file, char __user *buf, size_t count, loff_t *ppos)
+{
+	struct stack_record *stack;
+	void *address;
+	struct depot_stack_data *debugfs_data;
+
+	debugfs_data  = (struct depot_stack_data *)file->private_data;
+
+	if (!debugfs_data)
+		return -EINVAL;
+
+	while (debugfs_data->print_counter <= debugfs_data->print_index) {
+		unsigned long entries[PAGE_OWNER_STACK_DEPTH];
+		struct stack_trace trace = {
+			.nr_entries = 0,
+			.entries = entries,
+			.max_entries = PAGE_OWNER_STACK_DEPTH,
+			.skip = 0
+		};
+
+		address = stack_slabs[debugfs_data->print_counter] + debugfs_data->print_offset;
+		if (address == debugfs_data->end_address)
+			break;
+
+		if (*((unsigned long *)address) == debugfs_data->end_marker) {
+			debugfs_data->print_counter++;
+			debugfs_data->print_offset = 0;
+			continue;
+		}
+
+		stack = address;
+		trace.nr_entries = trace.max_entries = stack->size;
+		trace.entries = stack->entries;
+
+		debugfs_data->print_offset += offsetof(struct stack_record, entries) +
+				(stack->size * sizeof(unsigned long));
+		debugfs_data->print_offset = ALIGN(debugfs_data->print_offset, 1 << STACK_ALLOC_ALIGN);
+		if (debugfs_data->print_offset >= STACK_ALLOC_SIZE) {
+			debugfs_data->print_counter++;
+			debugfs_data->print_offset = 0;
+		}
+
+		*ppos = *ppos + 1; /* one stack found, print it */
+		return print_depot_stack(buf, count, &trace, ppos);
+	}
+
+	return 0;
+}
+
+int read_depot_open(struct inode *inode, struct file *file)
+{
+	struct depot_stack_data *debugfs_data;
+	unsigned long flags;
+
+	debugfs_data  = kzalloc(sizeof(struct depot_stack_data), GFP_KERNEL);
+	if (!debugfs_data)
+		return -ENOMEM;
+	/*
+	 * First time depot_stack/depot_entries is called.
+	 * (/sys/kernel/debug/depot_stack/depot_entries)
+	 * initialise print depot_index and stopping address.
+	 */
+	memset(&(debugfs_data->end_marker), POISON_END, sizeof(unsigned long));
+
+	spin_lock_irqsave(&depot_lock, flags);
+	debugfs_data->print_index = depot_index;
+	debugfs_data->end_address = stack_slabs[depot_index] + depot_offset;
+	spin_unlock_irqrestore(&depot_lock, flags);
+
+	file->private_data = debugfs_data;
+	return 0;
+}
+
+int read_depot_release(struct inode *inode, struct file *file)
+{
+	void *debugfs_data = file->private_data;
+
+	kfree(debugfs_data);
+	return 0;
+}
+
+static const struct file_operations proc_depot_stack_operations = {
+	.open       = read_depot_open,
+	.read		= read_depot_stack,
+	.release    = read_depot_release,
+};
+
+static const struct file_operations proc_depot_stack_size_operations = {
+	.read		= read_depot_stack_size,
+};
+
+static int __init depot_stack_init(void)
+{
+	struct dentry *dentry, *dentry_root;
+
+	dentry_root = debugfs_create_dir("depot_stack", NULL);
+
+	if (!dentry_root) {
+		pr_warn("debugfs 'depot_stack' dir creation failed\n");
+		return -ENOMEM;
+	}
+
+	dentry = debugfs_create_file("depot_entries", 0400, dentry_root,
+			NULL, &proc_depot_stack_operations);
+
+	if (IS_ERR(dentry))
+		goto err;
+
+	dentry = debugfs_create_file("depot_size", 0400, dentry_root,
+			NULL, &proc_depot_stack_size_operations);
+
+	if (IS_ERR(dentry))
+		goto err;
+
+	return 0;
+
+err:
+	debugfs_remove_recursive(dentry_root);
+	return PTR_ERR(dentry);
+}
+late_initcall(depot_stack_init)
diff --git a/mm/page_owner.c b/mm/page_owner.c
index 4f44b95..341b326 100644
--- a/mm/page_owner.c
+++ b/mm/page_owner.c
@@ -13,12 +13,6 @@
 
 #include "internal.h"
 
-/*
- * TODO: teach PAGE_OWNER_STACK_DEPTH (__dump_page_owner and save_stack)
- * to use off stack temporal storage
- */
-#define PAGE_OWNER_STACK_DEPTH (16)
-
 struct page_owner {
 	unsigned int order;
 	gfp_t gfp_mask;
-- 
1.7.1

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@xxxxxxxxx.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@xxxxxxxxx";> email@xxxxxxxxx </a>



[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Bugtraq]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]
  Powered by Linux