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

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

 



On Wed 22-11-17 16:17:41, Maninder Singh wrote:
> 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

Why do we need this? Who is goging to use this information and what for?
I haven't looked at the code but just the diffstat looks like this
should better have a _very_ good justification to be considered for
merging. To be honest with you I have hard time imagine how this can be
useful other than debugging stack depot...

> 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
> 

-- 
Michal Hocko
SUSE Labs

--
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