public inbox for llvm@lists.linux.dev
 help / color / mirror / Atom feed
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
> 

      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