All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH] srcu: Use try-lock lockdep annotation for NMI-safe access.
@ 2023-09-27 16:02 Sebastian Andrzej Siewior
  2023-09-28  6:06 ` Boqun Feng
  0 siblings, 1 reply; 8+ messages in thread
From: Sebastian Andrzej Siewior @ 2023-09-27 16:02 UTC (permalink / raw)
  To: linux-kernel, rcu
  Cc: Paul E. McKenney, Boqun Feng, Frederic Weisbecker, Ingo Molnar,
	Joel Fernandes, John Ogness, Josh Triplett, Lai Jiangshan,
	Mathieu Desnoyers, Neeraj Upadhyay, Peter Zijlstra,
	Steven Rostedt, Thomas Gleixner, Waiman Long, Will Deacon,
	Zqiang

It is claimed that srcu_read_lock_nmisafe() NMI-safe. However it
triggers a lockdep if used from NMI because lockdep expects a deadlock
since nothing disables NMIs while the lock is acquired.

Use a try-lock annotation for srcu_read_lock_nmisafe() to avoid lockdep
complains if used from NMI.

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

The splat:
| ================================
| WARNING: inconsistent lock state
| 6.6.0-rc3-rt5+ #85 Not tainted
| --------------------------------
| inconsistent {INITIAL USE} -> {IN-NMI} usage.
| swapper/0/0 [HC1[1]:SC0[0]:HE0:SE1] takes:
| ffffffff828e6c90 (console_srcu){....}-{0:0}, at: console_srcu_read_lock+0x3a/0x50
| {INITIAL USE} state was registered at:
…
|        CPU0
|        ----
|   lock(console_srcu);
|   <Interrupt>
|     lock(console_srcu);
|
|  *** DEADLOCK ***
|

My guess is that trylock annotation should not apply to
rcu_lock_acquire(). This would distinguish it from from non-NMI safe
srcu_read_lock_nmisafe() and NMI check in rcu_read_unlock() is only
there to survive if accidentally used in-NMI.

 include/linux/rcupdate.h | 6 ++++++
 include/linux/srcu.h     | 2 +-
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index 5e5f920ade909..44aab5c0bd2c1 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -303,6 +303,11 @@ static inline void rcu_lock_acquire(struct lockdep_map *map)
 	lock_acquire(map, 0, 0, 2, 0, NULL, _THIS_IP_);
 }
 
+static inline void rcu_try_lock_acquire(struct lockdep_map *map)
+{
+	lock_acquire(map, 0, 1, 2, 0, NULL, _THIS_IP_);
+}
+
 static inline void rcu_lock_release(struct lockdep_map *map)
 {
 	lock_release(map, _THIS_IP_);
@@ -317,6 +322,7 @@ int rcu_read_lock_any_held(void);
 #else /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */
 
 # define rcu_lock_acquire(a)		do { } while (0)
+# define rcu_try_lock_acquire(a)	do { } while (0)
 # define rcu_lock_release(a)		do { } while (0)
 
 static inline int rcu_read_lock_held(void)
diff --git a/include/linux/srcu.h b/include/linux/srcu.h
index 127ef3b2e6073..236610e4a8fa5 100644
--- a/include/linux/srcu.h
+++ b/include/linux/srcu.h
@@ -229,7 +229,7 @@ static inline int srcu_read_lock_nmisafe(struct srcu_struct *ssp) __acquires(ssp
 
 	srcu_check_nmi_safety(ssp, true);
 	retval = __srcu_read_lock_nmisafe(ssp);
-	rcu_lock_acquire(&ssp->dep_map);
+	rcu_try_lock_acquire(&ssp->dep_map);
 	return retval;
 }
 
-- 
2.40.1


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

* Re: [RFC PATCH] srcu: Use try-lock lockdep annotation for NMI-safe access.
  2023-09-27 16:02 [RFC PATCH] srcu: Use try-lock lockdep annotation for NMI-safe access Sebastian Andrzej Siewior
@ 2023-09-28  6:06 ` Boqun Feng
  2023-09-28  6:33   ` Sebastian Andrzej Siewior
                     ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Boqun Feng @ 2023-09-28  6:06 UTC (permalink / raw)
  To: Sebastian Andrzej Siewior
  Cc: linux-kernel, rcu, Paul E. McKenney, Frederic Weisbecker,
	Ingo Molnar, Joel Fernandes, John Ogness, Josh Triplett,
	Lai Jiangshan, Mathieu Desnoyers, Neeraj Upadhyay,
	Peter Zijlstra, Steven Rostedt, Thomas Gleixner, Waiman Long,
	Will Deacon, Zqiang

On Wed, Sep 27, 2023 at 06:02:31PM +0200, Sebastian Andrzej Siewior wrote:
> It is claimed that srcu_read_lock_nmisafe() NMI-safe. However it
> triggers a lockdep if used from NMI because lockdep expects a deadlock
> since nothing disables NMIs while the lock is acquired.
> 
> Use a try-lock annotation for srcu_read_lock_nmisafe() to avoid lockdep
> complains if used from NMI.
> 
> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> ---
> 
> The splat:
> | ================================
> | WARNING: inconsistent lock state
> | 6.6.0-rc3-rt5+ #85 Not tainted
> | --------------------------------
> | inconsistent {INITIAL USE} -> {IN-NMI} usage.
> | swapper/0/0 [HC1[1]:SC0[0]:HE0:SE1] takes:
> | ffffffff828e6c90 (console_srcu){....}-{0:0}, at: console_srcu_read_lock+0x3a/0x50
> | {INITIAL USE} state was registered at:
> …
> |        CPU0
> |        ----
> |   lock(console_srcu);
> |   <Interrupt>
> |     lock(console_srcu);
> |
> |  *** DEADLOCK ***
> |
> 
> My guess is that trylock annotation should not apply to
> rcu_lock_acquire(). This would distinguish it from from non-NMI safe
> srcu_read_lock_nmisafe() and NMI check in rcu_read_unlock() is only
> there to survive if accidentally used in-NMI.

I think this is a "side-effect" of commit f0f44752f5f6 ("rcu: Annotate
SRCU's update-side lockdep dependencies"). In verify_lock_unused(), i.e.
the checking for NMI lock usages, the logic is that

1)	read lock usages in NMI conflicts with write lock usage in
	normal context (i.e. LOCKF_USED)

2)	write lock usage in NMI conflicts with read and write lock usage
	in normal context (i.e. LOCKF_USED | LOCKF_USED_READ)

before that commit, only read-side of SRCU is annotated, in other words,
SRCU only has read lock usage from lockdep PoV, but after that commit,
we annotate synchronize_srcu() as a write lock usage, so that we can
detect deadlocks between *normal* srcu_read_lock() and
synchronize_srcu(), however the side effect is now SRCU has a write lock
usage from lockdep PoV.

Actually in the above commit, I explicitly leave
srcu_read_lock_nmisafe() alone since its locking rules may be different
compared to srcu_read_lock(). In lockdep terms, srcu_read_lock_nmisafe()
is a !check read lock and srcu_read_lock() is a check read lock. Maybe
instead of using the trylock trick, we change lockdep to igore !check
locks for NMI context detection? Untested code as below:

diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c
index e85b5ad3e206..1af8d44e5eb4 100644
--- a/kernel/locking/lockdep.c
+++ b/kernel/locking/lockdep.c
@@ -5727,8 +5727,9 @@ void lock_acquire(struct lockdep_map *lock, unsigned int subclass,
                return;

        if (unlikely(!lockdep_enabled())) {
+               /* Only do NMI context checking if it's a check lock */
                /* XXX allow trylock from NMI ?!? */
-               if (lockdep_nmi() && !trylock) {
+               if (check && lockdep_nmi() && !trylock) {
                        struct held_lock hlock;

                        hlock.acquire_ip = ip;

Peter, thoughts?

Of course, either way, we need

Fixes: f0f44752f5f6 ("rcu: Annotate SRCU's update-side lockdep dependencies")

Regards,
Boqun

> 
>  include/linux/rcupdate.h | 6 ++++++
>  include/linux/srcu.h     | 2 +-
>  2 files changed, 7 insertions(+), 1 deletion(-)
> 
> diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
> index 5e5f920ade909..44aab5c0bd2c1 100644
> --- a/include/linux/rcupdate.h
> +++ b/include/linux/rcupdate.h
> @@ -303,6 +303,11 @@ static inline void rcu_lock_acquire(struct lockdep_map *map)
>  	lock_acquire(map, 0, 0, 2, 0, NULL, _THIS_IP_);
>  }
>  
> +static inline void rcu_try_lock_acquire(struct lockdep_map *map)
> +{
> +	lock_acquire(map, 0, 1, 2, 0, NULL, _THIS_IP_);
> +}
> +
>  static inline void rcu_lock_release(struct lockdep_map *map)
>  {
>  	lock_release(map, _THIS_IP_);
> @@ -317,6 +322,7 @@ int rcu_read_lock_any_held(void);
>  #else /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */
>  
>  # define rcu_lock_acquire(a)		do { } while (0)
> +# define rcu_try_lock_acquire(a)	do { } while (0)
>  # define rcu_lock_release(a)		do { } while (0)
>  
>  static inline int rcu_read_lock_held(void)
> diff --git a/include/linux/srcu.h b/include/linux/srcu.h
> index 127ef3b2e6073..236610e4a8fa5 100644
> --- a/include/linux/srcu.h
> +++ b/include/linux/srcu.h
> @@ -229,7 +229,7 @@ static inline int srcu_read_lock_nmisafe(struct srcu_struct *ssp) __acquires(ssp
>  
>  	srcu_check_nmi_safety(ssp, true);
>  	retval = __srcu_read_lock_nmisafe(ssp);
> -	rcu_lock_acquire(&ssp->dep_map);
> +	rcu_try_lock_acquire(&ssp->dep_map);
>  	return retval;
>  }
>  
> -- 
> 2.40.1
> 

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

* Re: [RFC PATCH] srcu: Use try-lock lockdep annotation for NMI-safe access.
  2023-09-28  6:06 ` Boqun Feng
@ 2023-09-28  6:33   ` Sebastian Andrzej Siewior
  2023-09-28  8:05   ` Peter Zijlstra
  2023-09-28  8:09   ` Peter Zijlstra
  2 siblings, 0 replies; 8+ messages in thread
From: Sebastian Andrzej Siewior @ 2023-09-28  6:33 UTC (permalink / raw)
  To: Boqun Feng
  Cc: linux-kernel, rcu, Paul E. McKenney, Frederic Weisbecker,
	Ingo Molnar, Joel Fernandes, John Ogness, Josh Triplett,
	Lai Jiangshan, Mathieu Desnoyers, Neeraj Upadhyay,
	Peter Zijlstra, Steven Rostedt, Thomas Gleixner, Waiman Long,
	Will Deacon, Zqiang

On 2023-09-27 23:06:09 [-0700], Boqun Feng wrote:
> SRCU only has read lock usage from lockdep PoV, but after that commit,
> we annotate synchronize_srcu() as a write lock usage, so that we can
> detect deadlocks between *normal* srcu_read_lock() and
> synchronize_srcu(), however the side effect is now SRCU has a write lock
> usage from lockdep PoV.

Ach. There is a write annotation for SRCU and RCU has none. Okay that
explains it.

> Actually in the above commit, I explicitly leave
> srcu_read_lock_nmisafe() alone since its locking rules may be different
> compared to srcu_read_lock(). In lockdep terms, srcu_read_lock_nmisafe()
> is a !check read lock and srcu_read_lock() is a check read lock.

This was on v6.6-rc3 so it has the commit f0f44752f5f61 ("rcu: Annotate
SRCU's update-side lockdep dependencies").

>                                                                  Maybe
> instead of using the trylock trick, we change lockdep to igore !check
> locks for NMI context detection? Untested code as below:

Just tested, no splat for the SRCU-in-NMI usage.

Sebastian

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

* Re: [RFC PATCH] srcu: Use try-lock lockdep annotation for NMI-safe access.
  2023-09-28  6:06 ` Boqun Feng
  2023-09-28  6:33   ` Sebastian Andrzej Siewior
@ 2023-09-28  8:05   ` Peter Zijlstra
  2023-09-28  8:09   ` Peter Zijlstra
  2 siblings, 0 replies; 8+ messages in thread
From: Peter Zijlstra @ 2023-09-28  8:05 UTC (permalink / raw)
  To: Boqun Feng
  Cc: Sebastian Andrzej Siewior, linux-kernel, rcu, Paul E. McKenney,
	Frederic Weisbecker, Ingo Molnar, Joel Fernandes, John Ogness,
	Josh Triplett, Lai Jiangshan, Mathieu Desnoyers, Neeraj Upadhyay,
	Steven Rostedt, Thomas Gleixner, Waiman Long, Will Deacon,
	Zqiang

On Wed, Sep 27, 2023 at 11:06:09PM -0700, Boqun Feng wrote:

> diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c
> index e85b5ad3e206..1af8d44e5eb4 100644
> --- a/kernel/locking/lockdep.c
> +++ b/kernel/locking/lockdep.c
> @@ -5727,8 +5727,9 @@ void lock_acquire(struct lockdep_map *lock, unsigned int subclass,
>                 return;
> 
>         if (unlikely(!lockdep_enabled())) {
> +               /* Only do NMI context checking if it's a check lock */
>                 /* XXX allow trylock from NMI ?!? */
> -               if (lockdep_nmi() && !trylock) {
> +               if (check && lockdep_nmi() && !trylock) {
>                         struct held_lock hlock;
> 
>                         hlock.acquire_ip = ip;
> 
> Peter, thoughts?
> 

I think I prefer the trylock one. Fundamentally trylock conveys the 'we
wont block' thing. Making 'lock' sometimes work for NMI is just
confusing.

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

* Re: [RFC PATCH] srcu: Use try-lock lockdep annotation for NMI-safe access.
  2023-09-28  6:06 ` Boqun Feng
  2023-09-28  6:33   ` Sebastian Andrzej Siewior
  2023-09-28  8:05   ` Peter Zijlstra
@ 2023-09-28  8:09   ` Peter Zijlstra
  2023-09-28 14:54     ` Boqun Feng
  2 siblings, 1 reply; 8+ messages in thread
From: Peter Zijlstra @ 2023-09-28  8:09 UTC (permalink / raw)
  To: Boqun Feng
  Cc: Sebastian Andrzej Siewior, linux-kernel, rcu, Paul E. McKenney,
	Frederic Weisbecker, Ingo Molnar, Joel Fernandes, John Ogness,
	Josh Triplett, Lai Jiangshan, Mathieu Desnoyers, Neeraj Upadhyay,
	Steven Rostedt, Thomas Gleixner, Waiman Long, Will Deacon,
	Zqiang

On Wed, Sep 27, 2023 at 11:06:09PM -0700, Boqun Feng wrote:

> I think this is a "side-effect" of commit f0f44752f5f6 ("rcu: Annotate
> SRCU's update-side lockdep dependencies"). In verify_lock_unused(), i.e.
> the checking for NMI lock usages, the logic is that

I think I'm having a problem with this commit -- that is, by adding
lockdep you're adding tracepoint, which rely on RCU being active.

The result is that SRCU is now no longer usable from !RCU regions.

Was this considered and intended?


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

* Re: [RFC PATCH] srcu: Use try-lock lockdep annotation for NMI-safe access.
  2023-09-28  8:09   ` Peter Zijlstra
@ 2023-09-28 14:54     ` Boqun Feng
  2023-09-28 15:29       ` Peter Zijlstra
  0 siblings, 1 reply; 8+ messages in thread
From: Boqun Feng @ 2023-09-28 14:54 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Sebastian Andrzej Siewior, linux-kernel, rcu, Paul E. McKenney,
	Frederic Weisbecker, Ingo Molnar, Joel Fernandes, John Ogness,
	Josh Triplett, Lai Jiangshan, Mathieu Desnoyers, Neeraj Upadhyay,
	Steven Rostedt, Thomas Gleixner, Waiman Long, Will Deacon,
	Zqiang

On Thu, Sep 28, 2023 at 10:09:00AM +0200, Peter Zijlstra wrote:
> On Wed, Sep 27, 2023 at 11:06:09PM -0700, Boqun Feng wrote:
> 
> > I think this is a "side-effect" of commit f0f44752f5f6 ("rcu: Annotate
> > SRCU's update-side lockdep dependencies"). In verify_lock_unused(), i.e.
> > the checking for NMI lock usages, the logic is that
> 
> I think I'm having a problem with this commit -- that is, by adding
> lockdep you're adding tracepoint, which rely on RCU being active.
> 
> The result is that SRCU is now no longer usable from !RCU regions.
> 

Interesting

> Was this considered and intended?
> 

No, I don't think I have considered this before, I think I may still
miss something here, maybe you or Paul can provide an example for such
a case?

One thing though, before the commit, srcu_read_lock() already has an
rcu_lock_acquire() annotation which eventually calls lock_acquire()
which has a tracepoint in it.

Regards,
Boqun

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

* Re: [RFC PATCH] srcu: Use try-lock lockdep annotation for NMI-safe access.
  2023-09-28 14:54     ` Boqun Feng
@ 2023-09-28 15:29       ` Peter Zijlstra
  2023-09-28 17:09         ` Boqun Feng
  0 siblings, 1 reply; 8+ messages in thread
From: Peter Zijlstra @ 2023-09-28 15:29 UTC (permalink / raw)
  To: Boqun Feng
  Cc: Sebastian Andrzej Siewior, linux-kernel, rcu, Paul E. McKenney,
	Frederic Weisbecker, Ingo Molnar, Joel Fernandes, John Ogness,
	Josh Triplett, Lai Jiangshan, Mathieu Desnoyers, Neeraj Upadhyay,
	Steven Rostedt, Thomas Gleixner, Waiman Long, Will Deacon,
	Zqiang

On Thu, Sep 28, 2023 at 07:54:10AM -0700, Boqun Feng wrote:
> On Thu, Sep 28, 2023 at 10:09:00AM +0200, Peter Zijlstra wrote:
> > On Wed, Sep 27, 2023 at 11:06:09PM -0700, Boqun Feng wrote:
> > 
> > > I think this is a "side-effect" of commit f0f44752f5f6 ("rcu: Annotate
> > > SRCU's update-side lockdep dependencies"). In verify_lock_unused(), i.e.
> > > the checking for NMI lock usages, the logic is that
> > 
> > I think I'm having a problem with this commit -- that is, by adding
> > lockdep you're adding tracepoint, which rely on RCU being active.
> > 
> > The result is that SRCU is now no longer usable from !RCU regions.
> > 
> 
> Interesting
> 
> > Was this considered and intended?
> > 
> 
> No, I don't think I have considered this before, I think I may still
> miss something here, maybe you or Paul can provide an example for such
> a case?

The whole trace_.*_rcuidle() machinery. Which I thought I had fully
eradicated, but apparently still exists (with *one* user) :-/

Search for rcuidle in include/linux/tracepoint.h

Also, git grep trace_.*_rcuidle



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

* Re: [RFC PATCH] srcu: Use try-lock lockdep annotation for NMI-safe access.
  2023-09-28 15:29       ` Peter Zijlstra
@ 2023-09-28 17:09         ` Boqun Feng
  0 siblings, 0 replies; 8+ messages in thread
From: Boqun Feng @ 2023-09-28 17:09 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Sebastian Andrzej Siewior, linux-kernel, rcu, Paul E. McKenney,
	Frederic Weisbecker, Ingo Molnar, Joel Fernandes, John Ogness,
	Josh Triplett, Lai Jiangshan, Mathieu Desnoyers, Neeraj Upadhyay,
	Steven Rostedt, Thomas Gleixner, Waiman Long, Will Deacon,
	Zqiang

On Thu, Sep 28, 2023 at 05:29:42PM +0200, Peter Zijlstra wrote:
> On Thu, Sep 28, 2023 at 07:54:10AM -0700, Boqun Feng wrote:
> > On Thu, Sep 28, 2023 at 10:09:00AM +0200, Peter Zijlstra wrote:
> > > On Wed, Sep 27, 2023 at 11:06:09PM -0700, Boqun Feng wrote:
> > > 
> > > > I think this is a "side-effect" of commit f0f44752f5f6 ("rcu: Annotate
> > > > SRCU's update-side lockdep dependencies"). In verify_lock_unused(), i.e.
> > > > the checking for NMI lock usages, the logic is that
> > > 
> > > I think I'm having a problem with this commit -- that is, by adding
> > > lockdep you're adding tracepoint, which rely on RCU being active.
> > > 
> > > The result is that SRCU is now no longer usable from !RCU regions.
> > > 
> > 
> > Interesting
> > 
> > > Was this considered and intended?
> > > 
> > 
> > No, I don't think I have considered this before, I think I may still
> > miss something here, maybe you or Paul can provide an example for such
> > a case?
> 
> The whole trace_.*_rcuidle() machinery. Which I thought I had fully
> eradicated, but apparently still exists (with *one* user) :-/
> 
> Search for rcuidle in include/linux/tracepoint.h
> 
> Also, git grep trace_.*_rcuidle
> 

Thanks! But as I mentioned in the IRC, trace_.*_rcuidle() call the
special APIs srcu_read_{un,}lock_notrace(), and these won't call lockdep
annotation functions. And what the commit did was only changing the
lockdep annotation of srcu_read_{un,}lock(), so we are still fine here?

Regards,
Boqun

> 

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

end of thread, other threads:[~2023-09-28 17:10 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-09-27 16:02 [RFC PATCH] srcu: Use try-lock lockdep annotation for NMI-safe access Sebastian Andrzej Siewior
2023-09-28  6:06 ` Boqun Feng
2023-09-28  6:33   ` Sebastian Andrzej Siewior
2023-09-28  8:05   ` Peter Zijlstra
2023-09-28  8:09   ` Peter Zijlstra
2023-09-28 14:54     ` Boqun Feng
2023-09-28 15:29       ` Peter Zijlstra
2023-09-28 17:09         ` Boqun Feng

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.