Skip to content

Commit 108be8d

Browse files
xairyakpm00
authored andcommitted
lib/stackdepot: allow users to evict stack traces
Add stack_depot_put, a function that decrements the reference counter on a stack record and removes it from the stack depot once the counter reaches 0. Internally, when removing a stack record, the function unlinks it from the hash table bucket and returns to the freelist. With this change, the users of stack depot can call stack_depot_put when keeping a stack trace in the stack depot is not needed anymore. This allows avoiding polluting the stack depot with irrelevant stack traces and thus have more space to store the relevant ones before the stack depot reaches its capacity. Link: https://lkml.kernel.org/r/1d1ad5692ee43d4fc2b3fd9d221331d30b36123f.1700502145.git.andreyknvl@google.com Signed-off-by: Andrey Konovalov <[email protected]> Cc: Alexander Potapenko <[email protected]> Cc: Dmitry Vyukov <[email protected]> Cc: Evgenii Stepanov <[email protected]> Cc: Marco Elver <[email protected]> Cc: Oscar Salvador <[email protected]> Cc: Vlastimil Babka <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 410b764 commit 108be8d

File tree

2 files changed

+50
-1
lines changed

2 files changed

+50
-1
lines changed

include/linux/stackdepot.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ static inline int stack_depot_early_init(void) { return 0; }
9797
*
9898
* If STACK_DEPOT_FLAG_GET is set in @depot_flags, stack depot will increment
9999
* the refcount on the saved stack trace if it already exists in stack depot.
100+
* Users of this flag must also call stack_depot_put() when keeping the stack
101+
* trace is no longer required to avoid overflowing the refcount.
100102
*
101103
* If the provided stack trace comes from the interrupt context, only the part
102104
* up to the interrupt entry is saved.
@@ -162,6 +164,18 @@ void stack_depot_print(depot_stack_handle_t stack);
162164
int stack_depot_snprint(depot_stack_handle_t handle, char *buf, size_t size,
163165
int spaces);
164166

167+
/**
168+
* stack_depot_put - Drop a reference to a stack trace from stack depot
169+
*
170+
* @handle: Stack depot handle returned from stack_depot_save()
171+
*
172+
* The stack trace is evicted from stack depot once all references to it have
173+
* been dropped (once the number of stack_depot_evict() calls matches the
174+
* number of stack_depot_save_flags() calls with STACK_DEPOT_FLAG_GET set for
175+
* this stack trace).
176+
*/
177+
void stack_depot_put(depot_stack_handle_t handle);
178+
165179
/**
166180
* stack_depot_set_extra_bits - Set extra bits in a stack depot handle
167181
*

lib/stackdepot.c

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ static struct stack_record *depot_fetch_stack(depot_stack_handle_t handle)
394394
size_t offset = parts.offset << DEPOT_STACK_ALIGN;
395395
struct stack_record *stack;
396396

397-
lockdep_assert_held_read(&pool_rwlock);
397+
lockdep_assert_held(&pool_rwlock);
398398

399399
if (parts.pool_index > pools_num) {
400400
WARN(1, "pool index %d out of bounds (%d) for stack id %08x\n",
@@ -410,6 +410,14 @@ static struct stack_record *depot_fetch_stack(depot_stack_handle_t handle)
410410
return stack;
411411
}
412412

413+
/* Links stack into the freelist. */
414+
static void depot_free_stack(struct stack_record *stack)
415+
{
416+
lockdep_assert_held_write(&pool_rwlock);
417+
418+
list_add(&stack->list, &free_stacks);
419+
}
420+
413421
/* Calculates the hash for a stack. */
414422
static inline u32 hash_stack(unsigned long *entries, unsigned int size)
415423
{
@@ -592,6 +600,33 @@ unsigned int stack_depot_fetch(depot_stack_handle_t handle,
592600
}
593601
EXPORT_SYMBOL_GPL(stack_depot_fetch);
594602

603+
void stack_depot_put(depot_stack_handle_t handle)
604+
{
605+
struct stack_record *stack;
606+
unsigned long flags;
607+
608+
if (!handle || stack_depot_disabled)
609+
return;
610+
611+
write_lock_irqsave(&pool_rwlock, flags);
612+
613+
stack = depot_fetch_stack(handle);
614+
if (WARN_ON(!stack))
615+
goto out;
616+
617+
if (refcount_dec_and_test(&stack->count)) {
618+
/* Unlink stack from the hash table. */
619+
list_del(&stack->list);
620+
621+
/* Free stack. */
622+
depot_free_stack(stack);
623+
}
624+
625+
out:
626+
write_unlock_irqrestore(&pool_rwlock, flags);
627+
}
628+
EXPORT_SYMBOL_GPL(stack_depot_put);
629+
595630
void stack_depot_print(depot_stack_handle_t stack)
596631
{
597632
unsigned long *entries;

0 commit comments

Comments
 (0)