Linux 5.17-rc3
[linux-2.6-microblaze.git] / lib / stackdepot.c
index b437ae7..bf5ba9a 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/jhash.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/mutex.h>
 #include <linux/percpu.h>
 #include <linux/printk.h>
 #include <linux/slab.h>
@@ -161,18 +162,40 @@ static int __init is_stack_depot_disabled(char *str)
 }
 early_param("stack_depot_disable", is_stack_depot_disabled);
 
-int __init stack_depot_init(void)
+/*
+ * __ref because of memblock_alloc(), which will not be actually called after
+ * the __init code is gone, because at that point slab_is_available() is true
+ */
+__ref int stack_depot_init(void)
 {
-       if (!stack_depot_disable) {
+       static DEFINE_MUTEX(stack_depot_init_mutex);
+
+       mutex_lock(&stack_depot_init_mutex);
+       if (!stack_depot_disable && !stack_table) {
                size_t size = (STACK_HASH_SIZE * sizeof(struct stack_record *));
                int i;
 
-               stack_table = memblock_alloc(size, size);
-               for (i = 0; i < STACK_HASH_SIZE;  i++)
-                       stack_table[i] = NULL;
+               if (slab_is_available()) {
+                       pr_info("Stack Depot allocating hash table with kvmalloc\n");
+                       stack_table = kvmalloc(size, GFP_KERNEL);
+               } else {
+                       pr_info("Stack Depot allocating hash table with memblock_alloc\n");
+                       stack_table = memblock_alloc(size, SMP_CACHE_BYTES);
+               }
+               if (stack_table) {
+                       for (i = 0; i < STACK_HASH_SIZE;  i++)
+                               stack_table[i] = NULL;
+               } else {
+                       pr_err("Stack Depot hash table allocation failed, disabling\n");
+                       stack_depot_disable = true;
+                       mutex_unlock(&stack_depot_init_mutex);
+                       return -ENOMEM;
+               }
        }
+       mutex_unlock(&stack_depot_init_mutex);
        return 0;
 }
+EXPORT_SYMBOL_GPL(stack_depot_init);
 
 /* Calculate hash for a stack */
 static inline u32 hash_stack(unsigned long *entries, unsigned int size)
@@ -305,6 +328,9 @@ EXPORT_SYMBOL_GPL(stack_depot_fetch);
  * (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.
  *
+ * If the stack trace in @entries is from an interrupt, only the portion up to
+ * interrupt entry is saved.
+ *
  * 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
@@ -323,6 +349,16 @@ depot_stack_handle_t __stack_depot_save(unsigned long *entries,
        unsigned long flags;
        u32 hash;
 
+       /*
+        * If this stack trace is from an interrupt, including anything before
+        * interrupt entry usually leads to unbounded stackdepot growth.
+        *
+        * Because use of filter_irq_stacks() is a requirement to ensure
+        * stackdepot can efficiently deduplicate interrupt stacks, always
+        * filter_irq_stacks() to simplify all callers' use of stackdepot.
+        */
+       nr_entries = filter_irq_stacks(entries, nr_entries);
+
        if (unlikely(nr_entries == 0) || stack_depot_disable)
                goto fast_exit;