diff options
Diffstat (limited to 'lib/stackdepot.c')
| -rw-r--r-- | lib/stackdepot.c | 72 | 
1 files changed, 39 insertions, 33 deletions
| diff --git a/lib/stackdepot.c b/lib/stackdepot.c index 0a2e417f83cb..09485dc5bd12 100644 --- a/lib/stackdepot.c +++ b/lib/stackdepot.c @@ -20,7 +20,6 @@   */  #include <linux/gfp.h> -#include <linux/interrupt.h>  #include <linux/jhash.h>  #include <linux/kernel.h>  #include <linux/mm.h> @@ -102,8 +101,8 @@ static bool init_stack_slab(void **prealloc)  }  /* Allocation of a new stack in raw storage */ -static struct stack_record *depot_alloc_stack(unsigned long *entries, int size, -		u32 hash, void **prealloc, gfp_t alloc_flags) +static struct stack_record * +depot_alloc_stack(unsigned long *entries, int size, u32 hash, void **prealloc)  {  	struct stack_record *stack;  	size_t required_size = struct_size(stack, entries, size); @@ -248,17 +247,28 @@ unsigned int stack_depot_fetch(depot_stack_handle_t handle,  EXPORT_SYMBOL_GPL(stack_depot_fetch);  /** - * stack_depot_save - Save a stack trace from an array + * __stack_depot_save - Save a stack trace from an array   *   * @entries:		Pointer to storage array   * @nr_entries:		Size of the storage array   * @alloc_flags:	Allocation gfp flags + * @can_alloc:		Allocate stack slabs (increased chance of failure if false) + * + * Saves a stack trace from @entries array of size @nr_entries. If @can_alloc is + * %true, is allowed to replenish the stack slab pool in case no space is left + * (allocates using GFP flags of @alloc_flags). If @can_alloc is %false, avoids + * any allocations and will fail if no space is left to store the stack trace.   * - * Return: The handle of the stack struct stored in depot + * Context: Any context, but setting @can_alloc to %false is required if + *          alloc_pages() cannot be used from the current context. Currently + *          this is the case from contexts where neither %GFP_ATOMIC nor + *          %GFP_NOWAIT can be used (NMI, raw_spin_lock). + * + * Return: The handle of the stack struct stored in depot, 0 on failure.   */ -depot_stack_handle_t stack_depot_save(unsigned long *entries, -				      unsigned int nr_entries, -				      gfp_t alloc_flags) +depot_stack_handle_t __stack_depot_save(unsigned long *entries, +					unsigned int nr_entries, +					gfp_t alloc_flags, bool can_alloc)  {  	struct stack_record *found = NULL, **bucket;  	depot_stack_handle_t retval = 0; @@ -291,7 +301,7 @@ depot_stack_handle_t stack_depot_save(unsigned long *entries,  	 * The smp_load_acquire() here pairs with smp_store_release() to  	 * |next_slab_inited| in depot_alloc_stack() and init_stack_slab().  	 */ -	if (unlikely(!smp_load_acquire(&next_slab_inited))) { +	if (unlikely(can_alloc && !smp_load_acquire(&next_slab_inited))) {  		/*  		 * Zero out zone modifiers, as we don't have specific zone  		 * requirements. Keep the flags related to allocation in atomic @@ -309,9 +319,8 @@ depot_stack_handle_t stack_depot_save(unsigned long *entries,  	found = find_stack(*bucket, entries, nr_entries, hash);  	if (!found) { -		struct stack_record *new = -			depot_alloc_stack(entries, nr_entries, -					  hash, &prealloc, alloc_flags); +		struct stack_record *new = depot_alloc_stack(entries, nr_entries, hash, &prealloc); +  		if (new) {  			new->next = *bucket;  			/* @@ -340,27 +349,24 @@ exit:  fast_exit:  	return retval;  } -EXPORT_SYMBOL_GPL(stack_depot_save); - -static inline int in_irqentry_text(unsigned long ptr) -{ -	return (ptr >= (unsigned long)&__irqentry_text_start && -		ptr < (unsigned long)&__irqentry_text_end) || -		(ptr >= (unsigned long)&__softirqentry_text_start && -		 ptr < (unsigned long)&__softirqentry_text_end); -} +EXPORT_SYMBOL_GPL(__stack_depot_save); -unsigned int filter_irq_stacks(unsigned long *entries, -					     unsigned int nr_entries) +/** + * stack_depot_save - Save a stack trace from an array + * + * @entries:		Pointer to storage array + * @nr_entries:		Size of the storage array + * @alloc_flags:	Allocation gfp flags + * + * Context: Contexts where allocations via alloc_pages() are allowed. + *          See __stack_depot_save() for more details. + * + * Return: The handle of the stack struct stored in depot, 0 on failure. + */ +depot_stack_handle_t stack_depot_save(unsigned long *entries, +				      unsigned int nr_entries, +				      gfp_t alloc_flags)  { -	unsigned int i; - -	for (i = 0; i < nr_entries; i++) { -		if (in_irqentry_text(entries[i])) { -			/* Include the irqentry function into the stack. */ -			return i + 1; -		} -	} -	return nr_entries; +	return __stack_depot_save(entries, nr_entries, alloc_flags, true);  } -EXPORT_SYMBOL_GPL(filter_irq_stacks); +EXPORT_SYMBOL_GPL(stack_depot_save); |