[PATCH 1/4] lib/stackdepot: introduce __stack_depot_save()

From: Marco Elver
Date: Sun Sep 05 2021 - 10:51:26 EST


Add __stack_depot_save(), which provides more fine-grained control over
stackdepot's memory allocation behaviour, in case stackdepot runs out of
"stack slabs".

Normally stackdepot uses alloc_pages() in case it runs out of space;
passing can_alloc==false to __stack_depot_save() prohibits this, at the
cost of more likely failure to record a stack trace.

Signed-off-by: Marco Elver <elver@xxxxxxxxxx>
---
include/linux/stackdepot.h | 4 ++++
lib/stackdepot.c | 38 ++++++++++++++++++++++++++++++++------
2 files changed, 36 insertions(+), 6 deletions(-)

diff --git a/include/linux/stackdepot.h b/include/linux/stackdepot.h
index 6bb4bc1a5f54..3735b97f62be 100644
--- a/include/linux/stackdepot.h
+++ b/include/linux/stackdepot.h
@@ -13,6 +13,10 @@

typedef u32 depot_stack_handle_t;

+depot_stack_handle_t __stack_depot_save(unsigned long *entries,
+ unsigned int nr_entries,
+ gfp_t gfp_flags, bool can_alloc);
+
depot_stack_handle_t stack_depot_save(unsigned long *entries,
unsigned int nr_entries, gfp_t gfp_flags);

diff --git a/lib/stackdepot.c b/lib/stackdepot.c
index c80a9f734253..ec26845b4e29 100644
--- a/lib/stackdepot.c
+++ b/lib/stackdepot.c
@@ -248,17 +248,26 @@ 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
+ *
+ * Save a stack trace from an array. If |can_alloc| is false, avoids allocating
+ * new stack slabs if no space is left in the current stack slab.
+ *
+ * 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 not even
+ * %GFP_ATOMIC or %GFP_NOWAIT can be used (NMI, raw_spin_lock).
*
* @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)
*
- * Return: The handle of the stack struct stored in depot
+ * 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 +300,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
@@ -339,6 +348,23 @@ depot_stack_handle_t stack_depot_save(unsigned long *entries,
fast_exit:
return retval;
}
+EXPORT_SYMBOL_GPL(__stack_depot_save);
+
+/**
+ * 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
+ *
+ * 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)
+{
+ return __stack_depot_save(entries, nr_entries, alloc_flags, true);
+}
EXPORT_SYMBOL_GPL(stack_depot_save);

static inline int in_irqentry_text(unsigned long ptr)
--
2.33.0.153.gba50c8fa24-goog


--5wZe6NYc7WWhKinL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="0002-kasan-common-provide-can_alloc-in-kasan_save_stack.patch"