Re: [PATCH v2 4/4] Revert "lockdep: Annotate lockdep assertions for context analysis"

From: Marco Elver

Date: Wed Feb 25 2026 - 13:41:37 EST


On Wed, 25 Feb 2026 at 19:33, Bart Van Assche <bvanassche@xxxxxxx> wrote:
>
> lockdep_assert_held() supports all data structures that have a member
> with the name dep_map. __assume_ctx_lock() only supports data structures
> that support lock context annotation. Remove __assume_ctx_lock() from
> lockdep_assert_held(). This patch fixes the following build errors if
> lock context analysis is enabled for the entire kernel tree:
>
> drivers/tty/tty_ldisc.c:451:2: error: call to '__assume_ctx_lock' is ambiguous
> 451 | lockdep_assert_held_write(&tty->ldisc_sem);
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>
> drivers/tty/tty_ldisc.c:451:2: error: call to '__assume_ctx_lock' is ambiguous
> 451 | lockdep_assert_held_write(&tty->ldisc_sem);
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

I think that's a hint that that we should just ld_semaphore a
first-class context_lock_struct. That will enable the analysis for all
ld_semaphore users.

> Fixes: 7c451541743c ("lockdep: Annotate lockdep assertions for context analysis")
> Signed-off-by: Bart Van Assche <bvanassche@xxxxxxx>
> ---
> include/linux/lockdep.h | 12 ++++++------
> lib/test_context-analysis.c | 6 +++---
> mm/kfence/report.c | 1 +
> 3 files changed, 10 insertions(+), 9 deletions(-)
>
> diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h
> index 621566345406..dd634103b014 100644
> --- a/include/linux/lockdep.h
> +++ b/include/linux/lockdep.h
> @@ -282,16 +282,16 @@ extern void lock_unpin_lock(struct lockdep_map *lock, struct pin_cookie);
> do { WARN_ON_ONCE(debug_locks && !(cond)); } while (0)
>
> #define lockdep_assert_held(l) \
> - do { lockdep_assert(lockdep_is_held(l) != LOCK_STATE_NOT_HELD); __assume_ctx_lock(l); } while (0)
> + lockdep_assert(lockdep_is_held(l) != LOCK_STATE_NOT_HELD)
>
> #define lockdep_assert_not_held(l) \
> lockdep_assert(lockdep_is_held(l) != LOCK_STATE_HELD)
>
> #define lockdep_assert_held_write(l) \
> - do { lockdep_assert(lockdep_is_held_type(l, 0)); __assume_ctx_lock(l); } while (0)
> + lockdep_assert(lockdep_is_held_type(l, 0))
>
> #define lockdep_assert_held_read(l) \
> - do { lockdep_assert(lockdep_is_held_type(l, 1)); __assume_shared_ctx_lock(l); } while (0)
> + lockdep_assert(lockdep_is_held_type(l, 1))
>
> #define lockdep_assert_held_once(l) \
> lockdep_assert_once(lockdep_is_held(l) != LOCK_STATE_NOT_HELD)
> @@ -389,10 +389,10 @@ extern int lockdep_is_held(const void *);
> #define lockdep_assert(c) do { } while (0)
> #define lockdep_assert_once(c) do { } while (0)
>
> -#define lockdep_assert_held(l) __assume_ctx_lock(l)
> +#define lockdep_assert_held(l) do { (void)(l); } while (0)
> #define lockdep_assert_not_held(l) do { (void)(l); } while (0)
> -#define lockdep_assert_held_write(l) __assume_ctx_lock(l)
> -#define lockdep_assert_held_read(l) __assume_shared_ctx_lock(l)
> +#define lockdep_assert_held_write(l) do { (void)(l); } while (0)
> +#define lockdep_assert_held_read(l) do { (void)(l); } while (0)
> #define lockdep_assert_held_once(l) do { (void)(l); } while (0)
> #define lockdep_assert_none_held_once() do { } while (0)
>
> diff --git a/lib/test_context-analysis.c b/lib/test_context-analysis.c
> index 140efa8a9763..9846da75e9a3 100644
> --- a/lib/test_context-analysis.c
> +++ b/lib/test_context-analysis.c
> @@ -68,7 +68,7 @@ static void __used test_common_helpers(void)
> } \
> static void __used test_##class##_assert(struct test_##class##_data *d) \
> { \
> - lockdep_assert_held(&d->lock); \
> + __assume_ctx_lock(&d->lock); \
> op(d->counter); \
> } \
> static void __used test_##class##_guard(struct test_##class##_data *d) \
> @@ -199,7 +199,7 @@ static void __used test_mutex_trylock(struct test_mutex_data *d, atomic_t *a)
>
> static void __used test_mutex_assert(struct test_mutex_data *d)
> {
> - lockdep_assert_held(&d->mtx);
> + __assume_ctx_lock(&d->mtx);
> d->counter++;

These tests were supposed to demonstrate exactly that
lockdep_assert_held() works and doesn't require adding more pointless
annotations.

Our lockdep_assert follow this exact pattern:
https://clang.llvm.org/docs/ThreadSafetyAnalysis.html#assert-capability-and-assert-shared-capability

> d->counter++;
> }
>
> diff --git a/mm/kfence/report.c b/mm/kfence/report.c
> index 787e87c26926..d50a3f256650 100644
> --- a/mm/kfence/report.c
> +++ b/mm/kfence/report.c
> @@ -263,6 +263,7 @@ void kfence_report_error(unsigned long address, bool is_write, struct pt_regs *r
>
> if (meta) {
> lockdep_assert_held(&meta->lock);
> + __assume_ctx_lock(&meta->lock);

And this example here is exactly the reason why this is wrong - I
don't want pointless annotations like this.

Thanks.