[RFC][PATCH 0/4] locking: Add/convert context analysis bits

Peter Zijlstra posted 4 patches 2 weeks, 3 days ago
[RFC][PATCH 0/4] locking: Add/convert context analysis bits
Posted by Peter Zijlstra 2 weeks, 3 days ago
Hai

This is on top of tip/locking/core with these patches on:

  https://lkml.kernel.org/r/20260119094029.1344361-1-elver@google.com

and converts mutex, rtmutex, ww_mutex and futex to use the new context analysis
bits.

There is one snafu:

ww_mutex_set_context_fastpath()'s data_race() usage doesn't stop the compiler
from complaining when building a defconfig+PREEMPT_RT+LOCKDEP build:

../kernel/locking/ww_mutex.h:439:24: error: calling function '__ww_mutex_has_waiters' requires holding raw_spinlock 'lock->base.rtmutex.wait_lock' exclusively [-Werror,-Wthread-safety-analysis]
  439 |         if (likely(!data_race(__ww_mutex_has_waiters(&lock->base))))
      |                               ^
1 error generated.
Re: [RFC][PATCH 0/4] locking: Add/convert context analysis bits
Posted by Peter Zijlstra 2 weeks, 2 days ago
On Wed, Jan 21, 2026 at 12:07:04PM +0100, Peter Zijlstra wrote:
> Hai
> 
> This is on top of tip/locking/core with these patches on:
> 
>   https://lkml.kernel.org/r/20260119094029.1344361-1-elver@google.com
> 
> and converts mutex, rtmutex, ww_mutex and futex to use the new context analysis
> bits.
> 

Pushed out an updated/fixed series to:

  git://git.kernel.org/pub/scm/linux/kernel/git/peterz/queue.git locking/core
Re: [RFC][PATCH 0/4] locking: Add/convert context analysis bits
Posted by Sebastian Andrzej Siewior 2 weeks, 1 day ago
On 2026-01-21 20:23:49 [+0100], Peter Zijlstra wrote:
> On Wed, Jan 21, 2026 at 12:07:04PM +0100, Peter Zijlstra wrote:
> > Hai
> > 
> > This is on top of tip/locking/core with these patches on:
> > 
> >   https://lkml.kernel.org/r/20260119094029.1344361-1-elver@google.com
> > 
> > and converts mutex, rtmutex, ww_mutex and futex to use the new context analysis
> > bits.
> > 
> 
> Pushed out an updated/fixed series to:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/peterz/queue.git locking/core

I went through what you have there now and it looks good and I did not
find anything while testing. Full ACK.

Sebastian
Re: [RFC][PATCH 0/4] locking: Add/convert context analysis bits
Posted by Bart Van Assche 2 weeks, 2 days ago
On 1/21/26 11:23 AM, Peter Zijlstra wrote:
> Pushed out an updated/fixed series to:
> 
>    git://git.kernel.org/pub/scm/linux/kernel/git/peterz/queue.git locking/core

With CONFIG_WARN_CONTEXT_ANALYSIS=y, CONFIG_WARN_CONTEXT_ANALYSIS_ALL=n
and "+src:*include/*=emit" in scripts/context-analysis-suppression.txt
I see the following error messages for that tree:

In file included from kernel/locking/mutex.c:22:
In file included from ./include/linux/ww_mutex.h:21:
./include/linux/rtmutex.h:44:25: error: reading variable 'owner' 
requires holding raw_spinlock '&rt_mutex_base::wait_lock' 
[-Werror,-Wthread-safety-analysis]
    44 |         return READ_ONCE(lock->owner) != NULL;
       |                                ^
./include/linux/rtmutex.h:52:56: error: reading variable 'owner' 
requires holding raw_spinlock '&rt_mutex_base::wait_lock' 
[-Werror,-Wthread-safety-analysis]
    52 |         unsigned long owner = (unsigned long) 
READ_ONCE(lock->owner);
       |                                                               ^
2 errors generated.

Should this series perhaps include changes for the file
scripts/context-analysis-suppression.txt?

Thanks,

Bart.
Re: [RFC][PATCH 0/4] locking: Add/convert context analysis bits
Posted by Peter Zijlstra 2 weeks, 2 days ago
On Wed, Jan 21, 2026 at 12:37:21PM -0800, Bart Van Assche wrote:
> On 1/21/26 11:23 AM, Peter Zijlstra wrote:
> > Pushed out an updated/fixed series to:
> > 
> >    git://git.kernel.org/pub/scm/linux/kernel/git/peterz/queue.git locking/core
> 
> With CONFIG_WARN_CONTEXT_ANALYSIS=y, CONFIG_WARN_CONTEXT_ANALYSIS_ALL=n
> and "+src:*include/*=emit" in scripts/context-analysis-suppression.txt
> I see the following error messages for that tree:
> 
> In file included from kernel/locking/mutex.c:22:
> In file included from ./include/linux/ww_mutex.h:21:
> ./include/linux/rtmutex.h:44:25: error: reading variable 'owner' requires
> holding raw_spinlock '&rt_mutex_base::wait_lock'
> [-Werror,-Wthread-safety-analysis]
>    44 |         return READ_ONCE(lock->owner) != NULL;
>       |                                ^
> ./include/linux/rtmutex.h:52:56: error: reading variable 'owner' requires
> holding raw_spinlock '&rt_mutex_base::wait_lock'
> [-Werror,-Wthread-safety-analysis]
>    52 |         unsigned long owner = (unsigned long)
> READ_ONCE(lock->owner);
>       |                                                               ^
> 2 errors generated.
> 
> Should this series perhaps include changes for the file
> scripts/context-analysis-suppression.txt?

I'm having trouble reproducing :-(

You're speaking of something like the below, on a defconfig build,
right?

---
diff --git a/scripts/context-analysis-suppression.txt b/scripts/context-analysis-suppression.txt
index fd8951d06706..6c31eadd0244 100644
--- a/scripts/context-analysis-suppression.txt
+++ b/scripts/context-analysis-suppression.txt
@@ -14,6 +14,7 @@ src:*include/linux/*
 src:*include/net/*
 
 # Opt-in headers:
+src:*include/*=emit
 src:*include/linux/bit_spinlock.h=emit
 src:*include/linux/cleanup.h=emit
 src:*include/linux/kref.h=emit
Re: [RFC][PATCH 0/4] locking: Add/convert context analysis bits
Posted by Bart Van Assche 2 weeks, 2 days ago
On 1/22/26 1:04 AM, Peter Zijlstra wrote:
> I'm having trouble reproducing :-(

Hi Peter,

With this patch applied:

diff --git a/scripts/context-analysis-suppression.txt 
b/scripts/context-analysis-suppression.txt
index fd8951d06706..1c51b6153f08 100644
--- a/scripts/context-analysis-suppression.txt
+++ b/scripts/context-analysis-suppression.txt
@@ -24,6 +24,7 @@ src:*include/linux/mutex*.h=emit
  src:*include/linux/rcupdate.h=emit
  src:*include/linux/refcount.h=emit
  src:*include/linux/rhashtable.h=emit
+src:*include/linux/rtmutex*.h=emit
  src:*include/linux/rwlock*.h=emit
  src:*include/linux/rwsem.h=emit
  src:*include/linux/sched*=emit

and if I run the following commands:

build-kernel-with-clang allmodconfig
build-kernel-with-clang kernel/locking/mutex.o

then the following output appears:

   CALL    scripts/checksyscalls.sh
   DESCEND objtool
   INSTALL libsubcmd_headers
   CC      kernel/locking/mutex.o
In file included from kernel/locking/mutex.c:22:
In file included from ./include/linux/ww_mutex.h:21:
./include/linux/rtmutex.h:44:25: error: reading variable 'owner' requires
       holding raw_spinlock '&rt_mutex_base::wait_lock'
       [-Werror,-Wthread-safety-analysis]
    44 |         return READ_ONCE(lock->owner) != NULL;
       |                                ^
./include/linux/rtmutex.h:52:56: error: reading variable 'owner' requires
       holding raw_spinlock '&rt_mutex_base::wait_lock'
       [-Werror,-Wthread-safety-analysis]
    52 |         unsigned long owner = (unsigned long) 
READ_ONCE(lock->owner);
       |                                                               ^
2 errors generated.

The build-kernel-with-clang script is as follows (this may not be the
recommended way to build the kernel with clang):

#!/bin/bash
export CC=clang
export LD=ld.lld      # Use LLVM's linker (optional but recommended)
export AR=llvm-ar
export NM=llvm-nm
export OBJCOPY=llvm-objcopy
export OBJDUMP=llvm-objdump
export STRIP=llvm-strip
export READELF=llvm-readelf
make LLVM=1 CC=clang "$@"

Please let me know if you need more information.

Bart.
Re: [RFC][PATCH 0/4] locking: Add/convert context analysis bits
Posted by Peter Zijlstra 2 weeks, 1 day ago
On Thu, Jan 22, 2026 at 08:28:44AM -0800, Bart Van Assche wrote:

> then the following output appears:
> 
>   CALL    scripts/checksyscalls.sh
>   DESCEND objtool
>   INSTALL libsubcmd_headers
>   CC      kernel/locking/mutex.o
> In file included from kernel/locking/mutex.c:22:
> In file included from ./include/linux/ww_mutex.h:21:
> ./include/linux/rtmutex.h:44:25: error: reading variable 'owner' requires
>       holding raw_spinlock '&rt_mutex_base::wait_lock'
>       [-Werror,-Wthread-safety-analysis]
>    44 |         return READ_ONCE(lock->owner) != NULL;
>       |                                ^
> ./include/linux/rtmutex.h:52:56: error: reading variable 'owner' requires
>       holding raw_spinlock '&rt_mutex_base::wait_lock'
>       [-Werror,-Wthread-safety-analysis]
>    52 |         unsigned long owner = (unsigned long)
> READ_ONCE(lock->owner);
>       |                                                               ^
> 2 errors generated.
> 

Indeed; I shall fold the below into the rtmutex patch. Thanks!

---
--- a/include/linux/rtmutex.h
+++ b/include/linux/rtmutex.h
@@ -41,7 +41,7 @@ struct rt_mutex_base {
  */
 static inline bool rt_mutex_base_is_locked(struct rt_mutex_base *lock)
 {
-	return READ_ONCE(lock->owner) != NULL;
+	return data_race(READ_ONCE(lock->owner) != NULL);
 }
 
 #ifdef CONFIG_RT_MUTEXES
@@ -49,7 +49,7 @@ static inline bool rt_mutex_base_is_lock
 
 static inline struct task_struct *rt_mutex_owner(struct rt_mutex_base *lock)
 {
-	unsigned long owner = (unsigned long) READ_ONCE(lock->owner);
+	unsigned long owner = (unsigned long) data_race(READ_ONCE(lock->owner));
 
 	return (struct task_struct *) (owner & ~RT_MUTEX_HAS_WAITERS);
 }
--- a/scripts/context-analysis-suppression.txt
+++ b/scripts/context-analysis-suppression.txt
@@ -24,6 +24,7 @@ src:*include/linux/mutex*.h=emit
 src:*include/linux/rcupdate.h=emit
 src:*include/linux/refcount.h=emit
 src:*include/linux/rhashtable.h=emit
+src:*include/linux/rtmutex*.h=emit
 src:*include/linux/rwlock*.h=emit
 src:*include/linux/rwsem.h=emit
 src:*include/linux/sched*=emit
Re: [RFC][PATCH 0/4] locking: Add/convert context analysis bits
Posted by Bart Van Assche 2 weeks ago
On 1/23/26 3:15 AM, Peter Zijlstra wrote:
> --- a/include/linux/rtmutex.h
> +++ b/include/linux/rtmutex.h
> @@ -41,7 +41,7 @@ struct rt_mutex_base {
>    */
>   static inline bool rt_mutex_base_is_locked(struct rt_mutex_base *lock)
>   {
> -	return READ_ONCE(lock->owner) != NULL;
> +	return data_race(READ_ONCE(lock->owner) != NULL);
>   }
>   
>   #ifdef CONFIG_RT_MUTEXES
> @@ -49,7 +49,7 @@ static inline bool rt_mutex_base_is_lock
>   
>   static inline struct task_struct *rt_mutex_owner(struct rt_mutex_base *lock)
>   {
> -	unsigned long owner = (unsigned long) READ_ONCE(lock->owner);
> +	unsigned long owner = (unsigned long) data_race(READ_ONCE(lock->owner));
>   
>   	return (struct task_struct *) (owner & ~RT_MUTEX_HAS_WAITERS);
>   }
Marco, shouldn't lock context analysis be disabled for all READ_ONCE()
invocations? I expect that all code that uses READ_ONCE() to read a
structure member annotated with __guarded_by() will have to be annotated
with data_race(). Shouldn't the data_race() invocation be moved into the
READ_ONCE() definition?

Thanks,

Bart.
Re: [RFC][PATCH 0/4] locking: Add/convert context analysis bits
Posted by Marco Elver 2 weeks ago
On Fri, 23 Jan 2026 at 19:58, Bart Van Assche <bvanassche@acm.org> wrote:
>
> On 1/23/26 3:15 AM, Peter Zijlstra wrote:
> > --- a/include/linux/rtmutex.h
> > +++ b/include/linux/rtmutex.h
> > @@ -41,7 +41,7 @@ struct rt_mutex_base {
> >    */
> >   static inline bool rt_mutex_base_is_locked(struct rt_mutex_base *lock)
> >   {
> > -     return READ_ONCE(lock->owner) != NULL;
> > +     return data_race(READ_ONCE(lock->owner) != NULL);
> >   }
> >
> >   #ifdef CONFIG_RT_MUTEXES
> > @@ -49,7 +49,7 @@ static inline bool rt_mutex_base_is_lock
> >
> >   static inline struct task_struct *rt_mutex_owner(struct rt_mutex_base *lock)
> >   {
> > -     unsigned long owner = (unsigned long) READ_ONCE(lock->owner);
> > +     unsigned long owner = (unsigned long) data_race(READ_ONCE(lock->owner));
> >
> >       return (struct task_struct *) (owner & ~RT_MUTEX_HAS_WAITERS);
> >   }
> Marco, shouldn't lock context analysis be disabled for all READ_ONCE()
> invocations? I expect that all code that uses READ_ONCE() to read a
> structure member annotated with __guarded_by() will have to be annotated
> with data_race(). Shouldn't the data_race() invocation be moved into the
> READ_ONCE() definition?

Unclear, guarded variables accessed with READ_ONCE() do not
necessarily imply access without said lock is safe.

Second, a READ_ONCE() paired with another marked primitive never
results in a data race, and using data_race() actually prohibits KCSAN
from detecting real data races if any would be introduced, but we're
not expecting any.

In the above case, if there aren't actually any data races, the
data_race() addition does look odd.
Perhaps context_unsafe(READ_ONCE(..)) would be more appropriate if
there's no actual data race. That will signal context analysis this is
safe, and if there are any real data races introduced here (e.g. by a
concurrent plain write or such), we'd learn about it if KCSAN detects
it.
Re: [RFC][PATCH 0/4] locking: Add/convert context analysis bits
Posted by Nathan Chancellor 2 weeks, 1 day ago
On Thu, Jan 22, 2026 at 08:28:44AM -0800, Bart Van Assche wrote:
> The build-kernel-with-clang script is as follows (this may not be the
> recommended way to build the kernel with clang):
> 
> #!/bin/bash
> export CC=clang
> export LD=ld.lld      # Use LLVM's linker (optional but recommended)
> export AR=llvm-ar
> export NM=llvm-nm
> export OBJCOPY=llvm-objcopy
> export OBJDUMP=llvm-objdump
> export STRIP=llvm-strip
> export READELF=llvm-readelf
> make LLVM=1 CC=clang "$@"

FWIW, this could ultimately simplify to

    make LLVM=1 "$@"

as LLVM=1 is the shorthand for

    make CC=clang LD=ld.lld AR=llvm-ar NM=llvm-nm STRIP=llvm-strip \
         OBJCOPY=llvm-objcopy OBJDUMP=llvm-objdump READELF=llvm-readelf \
         HOSTCC=clang HOSTCXX=clang++ HOSTAR=llvm-ar HOSTLD=ld.lld

as noted in Documentation/kbuild/llvm.rst /
https://docs.kernel.org/kbuild/llvm.html.

Cheers,
Nathan
Re: [RFC][PATCH 0/4] locking: Add/convert context analysis bits
Posted by Peter Zijlstra 2 weeks, 1 day ago
On Thu, Jan 22, 2026 at 11:58:12AM -0700, Nathan Chancellor wrote:
> On Thu, Jan 22, 2026 at 08:28:44AM -0800, Bart Van Assche wrote:
> > The build-kernel-with-clang script is as follows (this may not be the
> > recommended way to build the kernel with clang):
> > 
> > #!/bin/bash
> > export CC=clang
> > export LD=ld.lld      # Use LLVM's linker (optional but recommended)
> > export AR=llvm-ar
> > export NM=llvm-nm
> > export OBJCOPY=llvm-objcopy
> > export OBJDUMP=llvm-objdump
> > export STRIP=llvm-strip
> > export READELF=llvm-readelf
> > make LLVM=1 CC=clang "$@"
> 
> FWIW, this could ultimately simplify to
> 
>     make LLVM=1 "$@"
> 
> as LLVM=1 is the shorthand for
> 
>     make CC=clang LD=ld.lld AR=llvm-ar NM=llvm-nm STRIP=llvm-strip \
>          OBJCOPY=llvm-objcopy OBJDUMP=llvm-objdump READELF=llvm-readelf \
>          HOSTCC=clang HOSTCXX=clang++ HOSTAR=llvm-ar HOSTLD=ld.lld
> 

Right, for all of us on Debian, you can use:

  make LLVM=-22 ...
Re: [RFC][PATCH 0/4] locking: Add/convert context analysis bits
Posted by Marco Elver 2 weeks, 3 days ago
On Wed, Jan 21, 2026 at 12:07PM +0100, Peter Zijlstra wrote:
> Hai
> 
> This is on top of tip/locking/core with these patches on:
> 
>   https://lkml.kernel.org/r/20260119094029.1344361-1-elver@google.com
> 
> and converts mutex, rtmutex, ww_mutex and futex to use the new context analysis
> bits.
> 
> There is one snafu:
> 
> ww_mutex_set_context_fastpath()'s data_race() usage doesn't stop the compiler
> from complaining when building a defconfig+PREEMPT_RT+LOCKDEP build:
> 
> ../kernel/locking/ww_mutex.h:439:24: error: calling function '__ww_mutex_has_waiters' requires holding raw_spinlock 'lock->base.rtmutex.wait_lock' exclusively [-Werror,-Wthread-safety-analysis]
>   439 |         if (likely(!data_race(__ww_mutex_has_waiters(&lock->base))))
>       |                               ^
> 1 error generated.

This works:

diff --git a/kernel/locking/ww_mutex.h b/kernel/locking/ww_mutex.h
index 73eed6b7f24e..561e2475954d 100644
--- a/kernel/locking/ww_mutex.h
+++ b/kernel/locking/ww_mutex.h
@@ -436,7 +436,8 @@ ww_mutex_set_context_fastpath(struct ww_mutex *lock, struct ww_acquire_ctx *ctx)
 	 * __ww_mutex_add_waiter() and makes sure we either observe ww->ctx
 	 * and/or !empty list.
 	 */
-	if (likely(!data_race(__ww_mutex_has_waiters(&lock->base))))
+	bool has_waiters = data_race(__ww_mutex_has_waiters(&lock->base));
+	if (likely(!has_waiters))
 		return;
 
 	/*


It appears that the _Pragma are ignored when the expression is inside
__builtin_expect(...). That's a bit inconvenient.

Another option is this given its exclusively used without holding this
lock:

diff --git a/kernel/locking/ww_mutex.h b/kernel/locking/ww_mutex.h
index 73eed6b7f24e..45a9c394fe91 100644
--- a/kernel/locking/ww_mutex.h
+++ b/kernel/locking/ww_mutex.h
@@ -71,7 +71,7 @@ __ww_mutex_owner(struct mutex *lock)
 }
 
 static inline bool
-__ww_mutex_has_waiters(struct mutex *lock)
+__ww_mutex_has_waiters_lockless(struct mutex *lock)
 {
 	return atomic_long_read(&lock->owner) & MUTEX_FLAG_WAITERS;
 }
@@ -151,10 +151,9 @@ __ww_mutex_owner(struct rt_mutex *lock)
 }
 
 static inline bool
-__ww_mutex_has_waiters(struct rt_mutex *lock)
-	__must_hold(&lock->rtmutex.wait_lock)
+__ww_mutex_has_waiters_lockless(struct rt_mutex *lock)
 {
-	return rt_mutex_has_waiters(&lock->rtmutex);
+	return data_race(rt_mutex_has_waiters(&lock->rtmutex));
 }
 
 static inline void lock_wait_lock(struct rt_mutex *lock, unsigned long *flags)
@@ -436,7 +435,7 @@ ww_mutex_set_context_fastpath(struct ww_mutex *lock, struct ww_acquire_ctx *ctx)
 	 * __ww_mutex_add_waiter() and makes sure we either observe ww->ctx
 	 * and/or !empty list.
 	 */
-	if (likely(!data_race(__ww_mutex_has_waiters(&lock->base))))
+	if (likely(!__ww_mutex_has_waiters_lockless(&lock->base)))
 		return;
 
 	/*