From: Nathan Chancellor <nathan@kernel.org>
To: Marco Elver <elver@google.com>
Cc: Peter Zijlstra <peterz@infradead.org>,
Ingo Molnar <mingo@kernel.org>,
Nick Desaulniers <nick.desaulniers+lkml@gmail.com>,
Bill Wendling <morbo@google.com>,
Justin Stitt <justinstitt@google.com>,
llvm@lists.linux.dev, Bart Van Assche <bvanassche@acm.org>,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH tip/locking/core] compiler-context-analysis: Add support for multi-argument guarded_by
Date: Mon, 23 Mar 2026 16:28:31 -0700 [thread overview]
Message-ID: <20260323232831.GB4147808@ax162> (raw)
In-Reply-To: <20260323153351.1412355-1-elver@google.com>
On Mon, Mar 23, 2026 at 04:33:32PM +0100, Marco Elver wrote:
> Clang 23 introduces support for multiple arguments in the `guarded_by`
> and `pt_guarded_by` attributes [1]. This allows defining variables
> protected by multiple context locks, where read access requires holding
> at least one lock (shared or exclusive), and write access requires
> holding all of them exclusively.
>
> To use the feature while maintaining compatibility with Clang 22, add
> the `__guarded_by_any()` and `__pt_guarded_by_any()` macros. On Clang 23
> and newer, these expand to the underlying attributes; with older Clang
> versions, they fall back to a no-op (false negatives possible).
>
> Link: https://github.com/llvm/llvm-project/pull/186838 [1]
> Requested-by: Peter Zijlstra <peterz@infradead.org>
> Signed-off-by: Marco Elver <elver@google.com>
Reviewed-by: Nathan Chancellor <nathan@kernel.org>
One small comment below.
> ---
> include/linux/compiler-context-analysis.h | 66 ++++++++++++++++++++---
> init/Kconfig | 5 ++
> lib/test_context-analysis.c | 24 +++++++++
> 3 files changed, 87 insertions(+), 8 deletions(-)
>
> diff --git a/include/linux/compiler-context-analysis.h b/include/linux/compiler-context-analysis.h
> index 00c074a2ccb0..a0d135e500dd 100644
> --- a/include/linux/compiler-context-analysis.h
> +++ b/include/linux/compiler-context-analysis.h
> @@ -39,8 +39,9 @@
> # define __assumes_shared_ctx_lock(...) __attribute__((assert_shared_capability(__VA_ARGS__)))
>
> /**
> - * __guarded_by - struct member and globals attribute, declares variable
> - * only accessible within active context
> + * __guarded_by() - struct member and globals attribute, declares variable
> + * only accessible within active context
> + * @x: context lock instance pointer
> *
> * Declares that the struct member or global variable is only accessible within
> * the context entered by the given context lock. Read operations on the data
> @@ -53,11 +54,12 @@
> * long counter __guarded_by(&lock);
> * };
> */
> -# define __guarded_by(...) __attribute__((guarded_by(__VA_ARGS__)))
> +# define __guarded_by(x) __attribute__((guarded_by(x)))
>
> /**
> - * __pt_guarded_by - struct member and globals attribute, declares pointed-to
> - * data only accessible within active context
> + * __pt_guarded_by() - struct member and globals attribute, declares pointed-to
> + * data only accessible within active context
> + * @x: context lock instance pointer
> *
> * Declares that the data pointed to by the struct member pointer or global
> * pointer is only accessible within the context entered by the given context
> @@ -71,7 +73,53 @@
> * long *counter __pt_guarded_by(&lock);
> * };
> */
> -# define __pt_guarded_by(...) __attribute__((pt_guarded_by(__VA_ARGS__)))
> +# define __pt_guarded_by(x) __attribute__((pt_guarded_by(x)))
> +
> +/**
> + * __guarded_by_any() - struct member and globals attribute, declares variable
> + * only accessible within active contexts
> + * @...: context lock instance pointers
> + *
> + * Declares that the struct member or global variable is protected by multiple
> + * context locks. Write access requires all listed context locks to be held
> + * exclusively; read access requires at least one of them to be held (shared or
> + * exclusive).
> + *
> + * .. code-block:: c
> + *
> + * struct some_state {
> + * spinlock_t lock1, lock2;
> + * long counter __guarded_by_any(&lock1, &lock2);
> + * };
> + */
> +# ifdef CONFIG_CC_HAS_MULTI_ARG_GUARDED_BY_ATTR
> +# define __guarded_by_any(...) __attribute__((guarded_by(__VA_ARGS__)))
> +# else
> +# define __guarded_by_any(...)
> +# endif
> +
> +/**
> + * __pt_guarded_by_any() - struct member and globals attribute, declares pointed-to
> + * data only accessible within active contexts
> + * @...: context lock instance pointers
> + *
> + * Declares that the data pointed to by the struct member pointer or global
> + * pointer is protected by multiple context locks. Write access requires all
> + * listed context locks to be held exclusively; read access requires at least
> + * one of them to be held (shared or exclusive).
> + *
> + * .. code-block:: c
> + *
> + * struct some_state {
> + * spinlock_t lock1, lock2;
> + * long *counter __pt_guarded_by_any(&lock1, &lock2);
> + * };
> + */
> +# ifdef CONFIG_CC_HAS_MULTI_ARG_GUARDED_BY_ATTR
> +# define __pt_guarded_by_any(...) __attribute__((pt_guarded_by(__VA_ARGS__)))
> +# else
> +# define __pt_guarded_by_any(...)
> +# endif
>
> /**
> * context_lock_struct() - declare or define a context lock struct
> @@ -158,8 +206,10 @@
> # define __assumes_ctx_lock(...)
> # define __assumes_shared_ctx_lock(...)
> # define __returns_ctx_lock(var)
> -# define __guarded_by(...)
> -# define __pt_guarded_by(...)
> +# define __guarded_by(x)
> +# define __pt_guarded_by(x)
> +# define __guarded_by_any(...)
> +# define __pt_guarded_by_any(...)
> # define __excludes_ctx_lock(...)
> # define __requires_ctx_lock(...)
> # define __requires_shared_ctx_lock(...)
> diff --git a/init/Kconfig b/init/Kconfig
> index 444ce811ea67..9f9a800822ff 100644
> --- a/init/Kconfig
> +++ b/init/Kconfig
> @@ -158,6 +158,11 @@ config CC_HAS_BROKEN_COUNTED_BY_REF
> config CC_HAS_MULTIDIMENSIONAL_NONSTRING
> def_bool $(success,echo 'char tag[][4] __attribute__((__nonstring__)) = { };' | $(CC) $(CLANG_FLAGS) -x c - -c -o /dev/null -Werror)
>
> +config CC_HAS_MULTI_ARG_GUARDED_BY_ATTR
> + # supported since clang 23
> + depends on CC_IS_CLANG
> + def_bool $(success,echo 'typedef int __attribute__((capability("l"))) L; L l1; L l2; int __attribute__((guarded_by(&l1, &l2))) x;' | $(CC) -x c - -c -o /dev/null -Werror)
Include $(CLANG_FLAGS) after $(CC) like the test above to harden against
the weird case when $(CC) does not have the host backend enabled (dumb,
I know, but I have seen it).
> +
> config LD_CAN_USE_KEEP_IN_OVERLAY
> # ld.lld prior to 21.0.0 did not support KEEP within an overlay description
> # https://github.com/llvm/llvm-project/pull/130661
> diff --git a/lib/test_context-analysis.c b/lib/test_context-analysis.c
> index 06b4a6a028e0..691fb2d6fc45 100644
> --- a/lib/test_context-analysis.c
> +++ b/lib/test_context-analysis.c
> @@ -159,6 +159,10 @@ TEST_SPINLOCK_COMMON(read_lock,
> struct test_mutex_data {
> struct mutex mtx;
> int counter __guarded_by(&mtx);
> +
> + struct mutex mtx2;
> + int anyread __guarded_by_any(&mtx, &mtx2);
> + int *anyptr __pt_guarded_by_any(&mtx, &mtx2);
> };
>
> static void __used test_mutex_init(struct test_mutex_data *d)
> @@ -219,6 +223,26 @@ static void __used test_mutex_cond_guard(struct test_mutex_data *d)
> }
> }
>
> +static void __used test_mutex_multiguard(struct test_mutex_data *d)
> +{
> + mutex_lock(&d->mtx);
> + (void)d->anyread;
> + (void)*d->anyptr;
> + mutex_unlock(&d->mtx);
> +
> + mutex_lock(&d->mtx2);
> + (void)d->anyread;
> + (void)*d->anyptr;
> + mutex_unlock(&d->mtx2);
> +
> + mutex_lock(&d->mtx);
> + mutex_lock(&d->mtx2);
> + d->anyread++;
> + (*d->anyptr)++;
> + mutex_unlock(&d->mtx2);
> + mutex_unlock(&d->mtx);
> +}
> +
> struct test_seqlock_data {
> seqlock_t sl;
> int counter __guarded_by(&sl);
> --
> 2.53.0.1018.g2bb0e51243-goog
>
prev parent reply other threads:[~2026-03-23 23:28 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-23 15:33 [PATCH tip/locking/core] compiler-context-analysis: Add support for multi-argument guarded_by Marco Elver
2026-03-23 15:39 ` Marco Elver
2026-03-25 15:20 ` Peter Zijlstra
2026-03-30 14:09 ` [PATCH tip/locking/core] compiler-context-analysis: Bump required Clang version to 23 Marco Elver
2026-03-30 14:18 ` Nathan Chancellor
2026-03-30 14:22 ` Marco Elver
2026-03-23 23:28 ` Nathan Chancellor [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260323232831.GB4147808@ax162 \
--to=nathan@kernel.org \
--cc=bvanassche@acm.org \
--cc=elver@google.com \
--cc=justinstitt@google.com \
--cc=linux-kernel@vger.kernel.org \
--cc=llvm@lists.linux.dev \
--cc=mingo@kernel.org \
--cc=morbo@google.com \
--cc=nick.desaulniers+lkml@gmail.com \
--cc=peterz@infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox