lib/stackdepot: put functions in logical order
Patch series "lib/stackdepot: fixes and clean-ups", v2. A set of fixes, comments, and clean-ups I came up with while reading the stack depot code. This patch (of 18): Put stack depot functions' declarations and definitions in a more logical order: 1. Functions that save stack traces into stack depot. 2. Functions that fetch and print stack traces. 3. stack_depot_get_extra_bits that operates on stack depot handles and does not interact with the stack depot storage. No functional changes. Link: https://lkml.kernel.org/r/cover.1676063693.git.andreyknvl@google.com Link: https://lkml.kernel.org/r/daca1319b665d826b94c596b992a8d8117846147.1676063693.git.andreyknvl@google.com Signed-off-by: Andrey Konovalov <andreyknvl@google.com> Reviewed-by: Alexander Potapenko <glider@google.com> Cc: Evgenii Stepanov <eugenis@google.com> Cc: Marco Elver <elver@google.com> Cc: Vlastimil Babka <vbabka@suse.cz> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
parent
6bdfc60cf0
commit
15ef6a982f
@ -14,17 +14,13 @@
|
|||||||
#include <linux/gfp.h>
|
#include <linux/gfp.h>
|
||||||
|
|
||||||
typedef u32 depot_stack_handle_t;
|
typedef u32 depot_stack_handle_t;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Number of bits in the handle that stack depot doesn't use. Users may store
|
* Number of bits in the handle that stack depot doesn't use. Users may store
|
||||||
* information in them.
|
* information in them.
|
||||||
*/
|
*/
|
||||||
#define STACK_DEPOT_EXTRA_BITS 5
|
#define STACK_DEPOT_EXTRA_BITS 5
|
||||||
|
|
||||||
depot_stack_handle_t __stack_depot_save(unsigned long *entries,
|
|
||||||
unsigned int nr_entries,
|
|
||||||
unsigned int extra_bits,
|
|
||||||
gfp_t gfp_flags, bool can_alloc);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Every user of stack depot has to call stack_depot_init() during its own init
|
* Every user of stack depot has to call stack_depot_init() during its own init
|
||||||
* when it's decided that it will be calling stack_depot_save() later. This is
|
* when it's decided that it will be calling stack_depot_save() later. This is
|
||||||
@ -59,17 +55,22 @@ static inline void stack_depot_want_early_init(void) { }
|
|||||||
static inline int stack_depot_early_init(void) { return 0; }
|
static inline int stack_depot_early_init(void) { return 0; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
depot_stack_handle_t __stack_depot_save(unsigned long *entries,
|
||||||
|
unsigned int nr_entries,
|
||||||
|
unsigned int extra_bits,
|
||||||
|
gfp_t gfp_flags, bool can_alloc);
|
||||||
|
|
||||||
depot_stack_handle_t stack_depot_save(unsigned long *entries,
|
depot_stack_handle_t stack_depot_save(unsigned long *entries,
|
||||||
unsigned int nr_entries, gfp_t gfp_flags);
|
unsigned int nr_entries, gfp_t gfp_flags);
|
||||||
|
|
||||||
unsigned int stack_depot_fetch(depot_stack_handle_t handle,
|
unsigned int stack_depot_fetch(depot_stack_handle_t handle,
|
||||||
unsigned long **entries);
|
unsigned long **entries);
|
||||||
|
|
||||||
unsigned int stack_depot_get_extra_bits(depot_stack_handle_t handle);
|
void stack_depot_print(depot_stack_handle_t stack);
|
||||||
|
|
||||||
int stack_depot_snprint(depot_stack_handle_t handle, char *buf, size_t size,
|
int stack_depot_snprint(depot_stack_handle_t handle, char *buf, size_t size,
|
||||||
int spaces);
|
int spaces);
|
||||||
|
|
||||||
void stack_depot_print(depot_stack_handle_t stack);
|
unsigned int stack_depot_get_extra_bits(depot_stack_handle_t handle);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
314
lib/stackdepot.c
314
lib/stackdepot.c
@ -79,84 +79,6 @@ static int next_slab_inited;
|
|||||||
static size_t depot_offset;
|
static size_t depot_offset;
|
||||||
static DEFINE_RAW_SPINLOCK(depot_lock);
|
static DEFINE_RAW_SPINLOCK(depot_lock);
|
||||||
|
|
||||||
unsigned int stack_depot_get_extra_bits(depot_stack_handle_t handle)
|
|
||||||
{
|
|
||||||
union handle_parts parts = { .handle = handle };
|
|
||||||
|
|
||||||
return parts.extra;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(stack_depot_get_extra_bits);
|
|
||||||
|
|
||||||
static bool init_stack_slab(void **prealloc)
|
|
||||||
{
|
|
||||||
if (!*prealloc)
|
|
||||||
return false;
|
|
||||||
/*
|
|
||||||
* This smp_load_acquire() pairs with smp_store_release() to
|
|
||||||
* |next_slab_inited| below and in depot_alloc_stack().
|
|
||||||
*/
|
|
||||||
if (smp_load_acquire(&next_slab_inited))
|
|
||||||
return true;
|
|
||||||
if (stack_slabs[depot_index] == NULL) {
|
|
||||||
stack_slabs[depot_index] = *prealloc;
|
|
||||||
*prealloc = NULL;
|
|
||||||
} else {
|
|
||||||
/* If this is the last depot slab, do not touch the next one. */
|
|
||||||
if (depot_index + 1 < STACK_ALLOC_MAX_SLABS) {
|
|
||||||
stack_slabs[depot_index + 1] = *prealloc;
|
|
||||||
*prealloc = NULL;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* This smp_store_release pairs with smp_load_acquire() from
|
|
||||||
* |next_slab_inited| above and in stack_depot_save().
|
|
||||||
*/
|
|
||||||
smp_store_release(&next_slab_inited, 1);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Allocation of a new stack in raw storage */
|
|
||||||
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);
|
|
||||||
|
|
||||||
required_size = ALIGN(required_size, 1 << STACK_ALLOC_ALIGN);
|
|
||||||
|
|
||||||
if (unlikely(depot_offset + required_size > STACK_ALLOC_SIZE)) {
|
|
||||||
if (unlikely(depot_index + 1 >= STACK_ALLOC_MAX_SLABS)) {
|
|
||||||
WARN_ONCE(1, "Stack depot reached limit capacity");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
depot_index++;
|
|
||||||
depot_offset = 0;
|
|
||||||
/*
|
|
||||||
* smp_store_release() here pairs with smp_load_acquire() from
|
|
||||||
* |next_slab_inited| in stack_depot_save() and
|
|
||||||
* init_stack_slab().
|
|
||||||
*/
|
|
||||||
if (depot_index + 1 < STACK_ALLOC_MAX_SLABS)
|
|
||||||
smp_store_release(&next_slab_inited, 0);
|
|
||||||
}
|
|
||||||
init_stack_slab(prealloc);
|
|
||||||
if (stack_slabs[depot_index] == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
stack = stack_slabs[depot_index] + depot_offset;
|
|
||||||
|
|
||||||
stack->hash = hash;
|
|
||||||
stack->size = size;
|
|
||||||
stack->handle.slabindex = depot_index;
|
|
||||||
stack->handle.offset = depot_offset >> STACK_ALLOC_ALIGN;
|
|
||||||
stack->handle.valid = 1;
|
|
||||||
stack->handle.extra = 0;
|
|
||||||
memcpy(stack->entries, entries, flex_array_size(stack, entries, size));
|
|
||||||
depot_offset += required_size;
|
|
||||||
|
|
||||||
return stack;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* one hash table bucket entry per 16kB of memory */
|
/* one hash table bucket entry per 16kB of memory */
|
||||||
#define STACK_HASH_SCALE 14
|
#define STACK_HASH_SCALE 14
|
||||||
/* limited between 4k and 1M buckets */
|
/* limited between 4k and 1M buckets */
|
||||||
@ -270,6 +192,76 @@ int stack_depot_init(void)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(stack_depot_init);
|
EXPORT_SYMBOL_GPL(stack_depot_init);
|
||||||
|
|
||||||
|
static bool init_stack_slab(void **prealloc)
|
||||||
|
{
|
||||||
|
if (!*prealloc)
|
||||||
|
return false;
|
||||||
|
/*
|
||||||
|
* This smp_load_acquire() pairs with smp_store_release() to
|
||||||
|
* |next_slab_inited| below and in depot_alloc_stack().
|
||||||
|
*/
|
||||||
|
if (smp_load_acquire(&next_slab_inited))
|
||||||
|
return true;
|
||||||
|
if (stack_slabs[depot_index] == NULL) {
|
||||||
|
stack_slabs[depot_index] = *prealloc;
|
||||||
|
*prealloc = NULL;
|
||||||
|
} else {
|
||||||
|
/* If this is the last depot slab, do not touch the next one. */
|
||||||
|
if (depot_index + 1 < STACK_ALLOC_MAX_SLABS) {
|
||||||
|
stack_slabs[depot_index + 1] = *prealloc;
|
||||||
|
*prealloc = NULL;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* This smp_store_release pairs with smp_load_acquire() from
|
||||||
|
* |next_slab_inited| above and in stack_depot_save().
|
||||||
|
*/
|
||||||
|
smp_store_release(&next_slab_inited, 1);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocation of a new stack in raw storage */
|
||||||
|
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);
|
||||||
|
|
||||||
|
required_size = ALIGN(required_size, 1 << STACK_ALLOC_ALIGN);
|
||||||
|
|
||||||
|
if (unlikely(depot_offset + required_size > STACK_ALLOC_SIZE)) {
|
||||||
|
if (unlikely(depot_index + 1 >= STACK_ALLOC_MAX_SLABS)) {
|
||||||
|
WARN_ONCE(1, "Stack depot reached limit capacity");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
depot_index++;
|
||||||
|
depot_offset = 0;
|
||||||
|
/*
|
||||||
|
* smp_store_release() here pairs with smp_load_acquire() from
|
||||||
|
* |next_slab_inited| in stack_depot_save() and
|
||||||
|
* init_stack_slab().
|
||||||
|
*/
|
||||||
|
if (depot_index + 1 < STACK_ALLOC_MAX_SLABS)
|
||||||
|
smp_store_release(&next_slab_inited, 0);
|
||||||
|
}
|
||||||
|
init_stack_slab(prealloc);
|
||||||
|
if (stack_slabs[depot_index] == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
stack = stack_slabs[depot_index] + depot_offset;
|
||||||
|
|
||||||
|
stack->hash = hash;
|
||||||
|
stack->size = size;
|
||||||
|
stack->handle.slabindex = depot_index;
|
||||||
|
stack->handle.offset = depot_offset >> STACK_ALLOC_ALIGN;
|
||||||
|
stack->handle.valid = 1;
|
||||||
|
stack->handle.extra = 0;
|
||||||
|
memcpy(stack->entries, entries, flex_array_size(stack, entries, size));
|
||||||
|
depot_offset += required_size;
|
||||||
|
|
||||||
|
return stack;
|
||||||
|
}
|
||||||
|
|
||||||
/* Calculate hash for a stack */
|
/* Calculate hash for a stack */
|
||||||
static inline u32 hash_stack(unsigned long *entries, unsigned int size)
|
static inline u32 hash_stack(unsigned long *entries, unsigned int size)
|
||||||
{
|
{
|
||||||
@ -309,85 +301,6 @@ static inline struct stack_record *find_stack(struct stack_record *bucket,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* stack_depot_snprint - print stack entries from a depot into a buffer
|
|
||||||
*
|
|
||||||
* @handle: Stack depot handle which was returned from
|
|
||||||
* stack_depot_save().
|
|
||||||
* @buf: Pointer to the print buffer
|
|
||||||
*
|
|
||||||
* @size: Size of the print buffer
|
|
||||||
*
|
|
||||||
* @spaces: Number of leading spaces to print
|
|
||||||
*
|
|
||||||
* Return: Number of bytes printed.
|
|
||||||
*/
|
|
||||||
int stack_depot_snprint(depot_stack_handle_t handle, char *buf, size_t size,
|
|
||||||
int spaces)
|
|
||||||
{
|
|
||||||
unsigned long *entries;
|
|
||||||
unsigned int nr_entries;
|
|
||||||
|
|
||||||
nr_entries = stack_depot_fetch(handle, &entries);
|
|
||||||
return nr_entries ? stack_trace_snprint(buf, size, entries, nr_entries,
|
|
||||||
spaces) : 0;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(stack_depot_snprint);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* stack_depot_print - print stack entries from a depot
|
|
||||||
*
|
|
||||||
* @stack: Stack depot handle which was returned from
|
|
||||||
* stack_depot_save().
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void stack_depot_print(depot_stack_handle_t stack)
|
|
||||||
{
|
|
||||||
unsigned long *entries;
|
|
||||||
unsigned int nr_entries;
|
|
||||||
|
|
||||||
nr_entries = stack_depot_fetch(stack, &entries);
|
|
||||||
if (nr_entries > 0)
|
|
||||||
stack_trace_print(entries, nr_entries, 0);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(stack_depot_print);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* stack_depot_fetch - Fetch stack entries from a depot
|
|
||||||
*
|
|
||||||
* @handle: Stack depot handle which was returned from
|
|
||||||
* stack_depot_save().
|
|
||||||
* @entries: Pointer to store the entries address
|
|
||||||
*
|
|
||||||
* Return: The number of trace entries for this depot.
|
|
||||||
*/
|
|
||||||
unsigned int stack_depot_fetch(depot_stack_handle_t handle,
|
|
||||||
unsigned long **entries)
|
|
||||||
{
|
|
||||||
union handle_parts parts = { .handle = handle };
|
|
||||||
void *slab;
|
|
||||||
size_t offset = parts.offset << STACK_ALLOC_ALIGN;
|
|
||||||
struct stack_record *stack;
|
|
||||||
|
|
||||||
*entries = NULL;
|
|
||||||
if (!handle)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (parts.slabindex > depot_index) {
|
|
||||||
WARN(1, "slab index %d out of bounds (%d) for stack id %08x\n",
|
|
||||||
parts.slabindex, depot_index, handle);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
slab = stack_slabs[parts.slabindex];
|
|
||||||
if (!slab)
|
|
||||||
return 0;
|
|
||||||
stack = slab + offset;
|
|
||||||
|
|
||||||
*entries = stack->entries;
|
|
||||||
return stack->size;
|
|
||||||
}
|
|
||||||
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
|
||||||
*
|
*
|
||||||
@ -533,3 +446,90 @@ depot_stack_handle_t stack_depot_save(unsigned long *entries,
|
|||||||
return __stack_depot_save(entries, nr_entries, 0, alloc_flags, true);
|
return __stack_depot_save(entries, nr_entries, 0, alloc_flags, true);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(stack_depot_save);
|
EXPORT_SYMBOL_GPL(stack_depot_save);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* stack_depot_fetch - Fetch stack entries from a depot
|
||||||
|
*
|
||||||
|
* @handle: Stack depot handle which was returned from
|
||||||
|
* stack_depot_save().
|
||||||
|
* @entries: Pointer to store the entries address
|
||||||
|
*
|
||||||
|
* Return: The number of trace entries for this depot.
|
||||||
|
*/
|
||||||
|
unsigned int stack_depot_fetch(depot_stack_handle_t handle,
|
||||||
|
unsigned long **entries)
|
||||||
|
{
|
||||||
|
union handle_parts parts = { .handle = handle };
|
||||||
|
void *slab;
|
||||||
|
size_t offset = parts.offset << STACK_ALLOC_ALIGN;
|
||||||
|
struct stack_record *stack;
|
||||||
|
|
||||||
|
*entries = NULL;
|
||||||
|
if (!handle)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (parts.slabindex > depot_index) {
|
||||||
|
WARN(1, "slab index %d out of bounds (%d) for stack id %08x\n",
|
||||||
|
parts.slabindex, depot_index, handle);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
slab = stack_slabs[parts.slabindex];
|
||||||
|
if (!slab)
|
||||||
|
return 0;
|
||||||
|
stack = slab + offset;
|
||||||
|
|
||||||
|
*entries = stack->entries;
|
||||||
|
return stack->size;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(stack_depot_fetch);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* stack_depot_print - print stack entries from a depot
|
||||||
|
*
|
||||||
|
* @stack: Stack depot handle which was returned from
|
||||||
|
* stack_depot_save().
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void stack_depot_print(depot_stack_handle_t stack)
|
||||||
|
{
|
||||||
|
unsigned long *entries;
|
||||||
|
unsigned int nr_entries;
|
||||||
|
|
||||||
|
nr_entries = stack_depot_fetch(stack, &entries);
|
||||||
|
if (nr_entries > 0)
|
||||||
|
stack_trace_print(entries, nr_entries, 0);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(stack_depot_print);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* stack_depot_snprint - print stack entries from a depot into a buffer
|
||||||
|
*
|
||||||
|
* @handle: Stack depot handle which was returned from
|
||||||
|
* stack_depot_save().
|
||||||
|
* @buf: Pointer to the print buffer
|
||||||
|
*
|
||||||
|
* @size: Size of the print buffer
|
||||||
|
*
|
||||||
|
* @spaces: Number of leading spaces to print
|
||||||
|
*
|
||||||
|
* Return: Number of bytes printed.
|
||||||
|
*/
|
||||||
|
int stack_depot_snprint(depot_stack_handle_t handle, char *buf, size_t size,
|
||||||
|
int spaces)
|
||||||
|
{
|
||||||
|
unsigned long *entries;
|
||||||
|
unsigned int nr_entries;
|
||||||
|
|
||||||
|
nr_entries = stack_depot_fetch(handle, &entries);
|
||||||
|
return nr_entries ? stack_trace_snprint(buf, size, entries, nr_entries,
|
||||||
|
spaces) : 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(stack_depot_snprint);
|
||||||
|
|
||||||
|
unsigned int stack_depot_get_extra_bits(depot_stack_handle_t handle)
|
||||||
|
{
|
||||||
|
union handle_parts parts = { .handle = handle };
|
||||||
|
|
||||||
|
return parts.extra;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(stack_depot_get_extra_bits);
|
||||||
|
Loading…
Reference in New Issue
Block a user