linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] stackdepot: fix stack_depot_save_flags() in NMI context
@ 2024-11-22 15:39 Marco Elver
  2024-11-22 17:38 ` Sebastian Andrzej Siewior
  2024-11-28  1:25 ` Andrew Morton
  0 siblings, 2 replies; 4+ messages in thread
From: Marco Elver @ 2024-11-22 15:39 UTC (permalink / raw)
  To: elver, Andrew Morton
  Cc: Andrey Konovalov, Alexander Potapenko, Dmitry Vyukov,
	Vlastimil Babka, Oscar Salvador, linux-kernel, linux-mm,
	kasan-dev, Sebastian Andrzej Siewior

Per documentation, stack_depot_save_flags() was meant to be usable from
NMI context if STACK_DEPOT_FLAG_CAN_ALLOC is unset. However, it still
would try to take the pool_lock in an attempt to save a stack trace in
the current pool (if space is available).

This could result in deadlock if an NMI is handled while pool_lock is
already held. To avoid deadlock, only try to take the lock in NMI
context and give up if unsuccessful.

The documentation is fixed to clearly convey this.

Link: https://lkml.kernel.org/r/Z0CcyfbPqmxJ9uJH@elver.google.com
Fixes: 4434a56ec209 ("stackdepot: make fast paths lock-less again")
Reported-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Marco Elver <elver@google.com>
---
 include/linux/stackdepot.h |  6 +++---
 lib/stackdepot.c           | 10 +++++++++-
 2 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/include/linux/stackdepot.h b/include/linux/stackdepot.h
index e9ec32fb97d4..2cc21ffcdaf9 100644
--- a/include/linux/stackdepot.h
+++ b/include/linux/stackdepot.h
@@ -147,7 +147,7 @@ static inline int stack_depot_early_init(void)	{ return 0; }
  * If the provided stack trace comes from the interrupt context, only the part
  * up to the interrupt entry is saved.
  *
- * Context: Any context, but setting STACK_DEPOT_FLAG_CAN_ALLOC is required if
+ * Context: Any context, but unsetting STACK_DEPOT_FLAG_CAN_ALLOC is required if
  *          alloc_pages() cannot be used from the current context. Currently
  *          this is the case for contexts where neither %GFP_ATOMIC nor
  *          %GFP_NOWAIT can be used (NMI, raw_spin_lock).
@@ -156,7 +156,7 @@ static inline int stack_depot_early_init(void)	{ return 0; }
  */
 depot_stack_handle_t stack_depot_save_flags(unsigned long *entries,
 					    unsigned int nr_entries,
-					    gfp_t gfp_flags,
+					    gfp_t alloc_flags,
 					    depot_flags_t depot_flags);
 
 /**
@@ -175,7 +175,7 @@ depot_stack_handle_t stack_depot_save_flags(unsigned long *entries,
  * Return: Handle of the stack trace stored in depot, 0 on failure
  */
 depot_stack_handle_t stack_depot_save(unsigned long *entries,
-				      unsigned int nr_entries, gfp_t gfp_flags);
+				      unsigned int nr_entries, gfp_t alloc_flags);
 
 /**
  * __stack_depot_get_stack_record - Get a pointer to a stack_record struct
diff --git a/lib/stackdepot.c b/lib/stackdepot.c
index 5ed34cc963fc..245d5b416699 100644
--- a/lib/stackdepot.c
+++ b/lib/stackdepot.c
@@ -630,7 +630,15 @@ depot_stack_handle_t stack_depot_save_flags(unsigned long *entries,
 			prealloc = page_address(page);
 	}
 
-	raw_spin_lock_irqsave(&pool_lock, flags);
+	if (in_nmi()) {
+		/* We can never allocate in NMI context. */
+		WARN_ON_ONCE(can_alloc);
+		/* Best effort; bail if we fail to take the lock. */
+		if (!raw_spin_trylock_irqsave(&pool_lock, flags))
+			goto exit;
+	} else {
+		raw_spin_lock_irqsave(&pool_lock, flags);
+	}
 	printk_deferred_enter();
 
 	/* Try to find again, to avoid concurrently inserting duplicates. */
-- 
2.47.0.371.ga323438b13-goog



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] stackdepot: fix stack_depot_save_flags() in NMI context
  2024-11-22 15:39 [PATCH] stackdepot: fix stack_depot_save_flags() in NMI context Marco Elver
@ 2024-11-22 17:38 ` Sebastian Andrzej Siewior
  2024-11-28  1:25 ` Andrew Morton
  1 sibling, 0 replies; 4+ messages in thread
From: Sebastian Andrzej Siewior @ 2024-11-22 17:38 UTC (permalink / raw)
  To: Marco Elver
  Cc: Andrew Morton, Andrey Konovalov, Alexander Potapenko,
	Dmitry Vyukov, Vlastimil Babka, Oscar Salvador, linux-kernel,
	linux-mm, kasan-dev

On 2024-11-22 16:39:47 [+0100], Marco Elver wrote:
> Per documentation, stack_depot_save_flags() was meant to be usable from
> NMI context if STACK_DEPOT_FLAG_CAN_ALLOC is unset. However, it still
> would try to take the pool_lock in an attempt to save a stack trace in
> the current pool (if space is available).
> 
> This could result in deadlock if an NMI is handled while pool_lock is
> already held. To avoid deadlock, only try to take the lock in NMI
> context and give up if unsuccessful.
> 
> The documentation is fixed to clearly convey this.
> 
> Link: https://lkml.kernel.org/r/Z0CcyfbPqmxJ9uJH@elver.google.com
> Fixes: 4434a56ec209 ("stackdepot: make fast paths lock-less again")
> Reported-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> Signed-off-by: Marco Elver <elver@google.com>

Reviewed-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>

Sebastian


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] stackdepot: fix stack_depot_save_flags() in NMI context
  2024-11-22 15:39 [PATCH] stackdepot: fix stack_depot_save_flags() in NMI context Marco Elver
  2024-11-22 17:38 ` Sebastian Andrzej Siewior
@ 2024-11-28  1:25 ` Andrew Morton
  2024-11-28  9:13   ` Marco Elver
  1 sibling, 1 reply; 4+ messages in thread
From: Andrew Morton @ 2024-11-28  1:25 UTC (permalink / raw)
  To: Marco Elver
  Cc: Andrey Konovalov, Alexander Potapenko, Dmitry Vyukov,
	Vlastimil Babka, Oscar Salvador, linux-kernel, linux-mm,
	kasan-dev, Sebastian Andrzej Siewior

On Fri, 22 Nov 2024 16:39:47 +0100 Marco Elver <elver@google.com> wrote:

> Per documentation, stack_depot_save_flags() was meant to be usable from
> NMI context if STACK_DEPOT_FLAG_CAN_ALLOC is unset. However, it still
> would try to take the pool_lock in an attempt to save a stack trace in
> the current pool (if space is available).
> 
> This could result in deadlock if an NMI is handled while pool_lock is
> already held. To avoid deadlock, only try to take the lock in NMI
> context and give up if unsuccessful.

Is it possible to trigger this deadlock in current kernels, or is this
a might-happen-in-the-future thing?

> The documentation is fixed to clearly convey this.
> 



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] stackdepot: fix stack_depot_save_flags() in NMI context
  2024-11-28  1:25 ` Andrew Morton
@ 2024-11-28  9:13   ` Marco Elver
  0 siblings, 0 replies; 4+ messages in thread
From: Marco Elver @ 2024-11-28  9:13 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Andrey Konovalov, Alexander Potapenko, Dmitry Vyukov,
	Vlastimil Babka, Oscar Salvador, linux-kernel, linux-mm,
	kasan-dev, Sebastian Andrzej Siewior

On Thu, 28 Nov 2024 at 02:25, Andrew Morton <akpm@linux-foundation.org> wrote:
>
> On Fri, 22 Nov 2024 16:39:47 +0100 Marco Elver <elver@google.com> wrote:
>
> > Per documentation, stack_depot_save_flags() was meant to be usable from
> > NMI context if STACK_DEPOT_FLAG_CAN_ALLOC is unset. However, it still
> > would try to take the pool_lock in an attempt to save a stack trace in
> > the current pool (if space is available).
> >
> > This could result in deadlock if an NMI is handled while pool_lock is
> > already held. To avoid deadlock, only try to take the lock in NMI
> > context and give up if unsuccessful.
>
> Is it possible to trigger this deadlock in current kernels, or is this
> a might-happen-in-the-future thing?

I can't find evidence this happens right now (at least with the quick
test I just ran), so it's more of a might happen if use of this API
broadens.

Thanks,
-- Marco


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2024-11-28  9:14 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-11-22 15:39 [PATCH] stackdepot: fix stack_depot_save_flags() in NMI context Marco Elver
2024-11-22 17:38 ` Sebastian Andrzej Siewior
2024-11-28  1:25 ` Andrew Morton
2024-11-28  9:13   ` Marco Elver

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox