diff options
Diffstat (limited to 'lib/stackdepot.c')
| -rw-r--r-- | lib/stackdepot.c | 65 | 
1 files changed, 16 insertions, 49 deletions
diff --git a/lib/stackdepot.c b/lib/stackdepot.c index 4a7055a63d9f..af6cc19a2003 100644 --- a/lib/stackdepot.c +++ b/lib/stackdepot.c @@ -36,53 +36,11 @@  #include <linux/memblock.h>  #include <linux/kasan-enabled.h> -#define DEPOT_HANDLE_BITS (sizeof(depot_stack_handle_t) * 8) - -#define DEPOT_POOL_ORDER 2 /* Pool size order, 4 pages */ -#define DEPOT_POOL_SIZE (1LL << (PAGE_SHIFT + DEPOT_POOL_ORDER)) -#define DEPOT_STACK_ALIGN 4 -#define DEPOT_OFFSET_BITS (DEPOT_POOL_ORDER + PAGE_SHIFT - DEPOT_STACK_ALIGN) -#define DEPOT_POOL_INDEX_BITS (DEPOT_HANDLE_BITS - DEPOT_OFFSET_BITS - \ -			       STACK_DEPOT_EXTRA_BITS)  #define DEPOT_POOLS_CAP 8192 +/* The pool_index is offset by 1 so the first record does not have a 0 handle. */  #define DEPOT_MAX_POOLS \ -	(((1LL << (DEPOT_POOL_INDEX_BITS)) < DEPOT_POOLS_CAP) ? \ -	 (1LL << (DEPOT_POOL_INDEX_BITS)) : DEPOT_POOLS_CAP) - -/* Compact structure that stores a reference to a stack. */ -union handle_parts { -	depot_stack_handle_t handle; -	struct { -		u32 pool_index	: DEPOT_POOL_INDEX_BITS; -		u32 offset	: DEPOT_OFFSET_BITS; -		u32 extra	: STACK_DEPOT_EXTRA_BITS; -	}; -}; - -struct stack_record { -	struct list_head hash_list;	/* Links in the hash table */ -	u32 hash;			/* Hash in hash table */ -	u32 size;			/* Number of stored frames */ -	union handle_parts handle;	/* Constant after initialization */ -	refcount_t count; -	union { -		unsigned long entries[CONFIG_STACKDEPOT_MAX_FRAMES];	/* Frames */ -		struct { -			/* -			 * An important invariant of the implementation is to -			 * only place a stack record onto the freelist iff its -			 * refcount is zero. Because stack records with a zero -			 * refcount are never considered as valid, it is safe to -			 * union @entries and freelist management state below. -			 * Conversely, as soon as an entry is off the freelist -			 * and its refcount becomes non-zero, the below must not -			 * be accessed until being placed back on the freelist. -			 */ -			struct list_head free_list;	/* Links in the freelist */ -			unsigned long rcu_state;	/* RCU cookie */ -		}; -	}; -}; +	(((1LL << (DEPOT_POOL_INDEX_BITS)) - 1 < DEPOT_POOLS_CAP) ? \ +	 (1LL << (DEPOT_POOL_INDEX_BITS)) - 1 : DEPOT_POOLS_CAP)  static bool stack_depot_disabled;  static bool __stack_depot_early_init_requested __initdata = IS_ENABLED(CONFIG_STACKDEPOT_ALWAYS_INIT); @@ -372,7 +330,7 @@ static struct stack_record *depot_pop_free_pool(void **prealloc, size_t size)  	stack = current_pool + pool_offset;  	/* Pre-initialize handle once. */ -	stack->handle.pool_index = pool_index; +	stack->handle.pool_index = pool_index + 1;  	stack->handle.offset = pool_offset >> DEPOT_STACK_ALIGN;  	stack->handle.extra = 0;  	INIT_LIST_HEAD(&stack->hash_list); @@ -483,18 +441,19 @@ static struct stack_record *depot_fetch_stack(depot_stack_handle_t handle)  	const int pools_num_cached = READ_ONCE(pools_num);  	union handle_parts parts = { .handle = handle };  	void *pool; +	u32 pool_index = parts.pool_index - 1;  	size_t offset = parts.offset << DEPOT_STACK_ALIGN;  	struct stack_record *stack;  	lockdep_assert_not_held(&pool_lock); -	if (parts.pool_index > pools_num_cached) { +	if (pool_index >= pools_num_cached) {  		WARN(1, "pool index %d out of bounds (%d) for stack id %08x\n", -		     parts.pool_index, pools_num_cached, handle); +		     pool_index, pools_num_cached, handle);  		return NULL;  	} -	pool = stack_pools[parts.pool_index]; +	pool = stack_pools[pool_index];  	if (WARN_ON(!pool))  		return NULL; @@ -728,6 +687,14 @@ depot_stack_handle_t stack_depot_save(unsigned long *entries,  }  EXPORT_SYMBOL_GPL(stack_depot_save); +struct stack_record *__stack_depot_get_stack_record(depot_stack_handle_t handle) +{ +	if (!handle) +		return NULL; + +	return depot_fetch_stack(handle); +} +  unsigned int stack_depot_fetch(depot_stack_handle_t handle,  			       unsigned long **entries)  {  | 
