| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- .. SPDX-License-Identifier: GPL-2.0
- .. Copyright (C) 2025, Google LLC.
- .. _context-analysis:
- Compiler-Based Context Analysis
- ===============================
- Context Analysis is a language extension, which enables statically checking
- that required contexts are active (or inactive) by acquiring and releasing
- user-definable "context locks". An obvious application is lock-safety checking
- for the kernel's various synchronization primitives (each of which represents a
- "context lock"), and checking that locking rules are not violated.
- The Clang compiler currently supports the full set of context analysis
- features. To enable for Clang, configure the kernel with::
- CONFIG_WARN_CONTEXT_ANALYSIS=y
- The feature requires Clang 22 or later.
- The analysis is *opt-in by default*, and requires declaring which modules and
- subsystems should be analyzed in the respective `Makefile`::
- CONTEXT_ANALYSIS_mymodule.o := y
- Or for all translation units in the directory::
- CONTEXT_ANALYSIS := y
- It is possible to enable the analysis tree-wide, however, which will result in
- numerous false positive warnings currently and is *not* generally recommended::
- CONFIG_WARN_CONTEXT_ANALYSIS_ALL=y
- Programming Model
- -----------------
- The below describes the programming model around using context lock types.
- .. note::
- Enabling context analysis can be seen as enabling a dialect of Linux C with
- a Context System. Some valid patterns involving complex control-flow are
- constrained (such as conditional acquisition and later conditional release
- in the same function).
- Context analysis is a way to specify permissibility of operations to depend on
- context locks being held (or not held). Typically we are interested in
- protecting data and code in a critical section by requiring a specific context
- to be active, for example by holding a specific lock. The analysis ensures that
- callers cannot perform an operation without the required context being active.
- Context locks are associated with named structs, along with functions that
- operate on struct instances to acquire and release the associated context lock.
- Context locks can be held either exclusively or shared. This mechanism allows
- assigning more precise privileges when a context is active, typically to
- distinguish where a thread may only read (shared) or also write (exclusive) to
- data guarded within a context.
- The set of contexts that are actually active in a given thread at a given point
- in program execution is a run-time concept. The static analysis works by
- calculating an approximation of that set, called the context environment. The
- context environment is calculated for every program point, and describes the
- set of contexts that are statically known to be active, or inactive, at that
- particular point. This environment is a conservative approximation of the full
- set of contexts that will actually be active in a thread at run-time.
- More details are also documented `here
- <https://clang.llvm.org/docs/ThreadSafetyAnalysis.html>`_.
- .. note::
- Clang's analysis explicitly does not infer context locks acquired or
- released by inline functions. It requires explicit annotations to (a) assert
- that it's not a bug if a context lock is released or acquired, and (b) to
- retain consistency between inline and non-inline function declarations.
- Supported Kernel Primitives
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Currently the following synchronization primitives are supported:
- `raw_spinlock_t`, `spinlock_t`, `rwlock_t`, `mutex`, `seqlock_t`,
- `bit_spinlock`, RCU, SRCU (`srcu_struct`), `rw_semaphore`, `local_lock_t`,
- `ww_mutex`.
- To initialize variables guarded by a context lock with an initialization
- function (``type_init(&lock)``), prefer using ``guard(type_init)(&lock)`` or
- ``scoped_guard(type_init, &lock) { ... }`` to initialize such guarded members
- or globals in the enclosing scope. This initializes the context lock and treats
- the context as active within the initialization scope (initialization implies
- exclusive access to the underlying object).
- For example::
- struct my_data {
- spinlock_t lock;
- int counter __guarded_by(&lock);
- };
- void init_my_data(struct my_data *d)
- {
- ...
- guard(spinlock_init)(&d->lock);
- d->counter = 0;
- ...
- }
- Alternatively, initializing guarded variables can be done with context analysis
- disabled, preferably in the smallest possible scope (due to lack of any other
- checking): either with a ``context_unsafe(var = init)`` expression, or by
- marking small initialization functions with the ``__context_unsafe(init)``
- attribute.
- Lockdep assertions, such as `lockdep_assert_held()`, inform the compiler's
- context analysis that the associated synchronization primitive is held after
- the assertion. This avoids false positives in complex control-flow scenarios
- and encourages the use of Lockdep where static analysis is limited. For
- example, this is useful when a function doesn't *always* require a lock, making
- `__must_hold()` inappropriate.
- Keywords
- ~~~~~~~~
- .. kernel-doc:: include/linux/compiler-context-analysis.h
- :identifiers: context_lock_struct
- token_context_lock token_context_lock_instance
- __guarded_by __pt_guarded_by
- __must_hold
- __must_not_hold
- __acquires
- __cond_acquires
- __releases
- __must_hold_shared
- __acquires_shared
- __cond_acquires_shared
- __releases_shared
- __acquire
- __release
- __acquire_shared
- __release_shared
- __acquire_ret
- __acquire_shared_ret
- context_unsafe
- __context_unsafe
- disable_context_analysis enable_context_analysis
- .. note::
- The function attribute `__no_context_analysis` is reserved for internal
- implementation of context lock types, and should be avoided in normal code.
- Background
- ----------
- Clang originally called the feature `Thread Safety Analysis
- <https://clang.llvm.org/docs/ThreadSafetyAnalysis.html>`_, with some keywords
- and documentation still using the thread-safety-analysis-only terminology. This
- was later changed and the feature became more flexible, gaining the ability to
- define custom "capabilities". Its foundations can be found in `Capability
- Systems <https://www.cs.cornell.edu/talc/papers/capabilities.pdf>`_, used to
- specify the permissibility of operations to depend on some "capability" being
- held (or not held).
- Because the feature is not just able to express capabilities related to
- synchronization primitives, and "capability" is already overloaded in the
- kernel, the naming chosen for the kernel departs from Clang's initial "Thread
- Safety" and "capability" nomenclature; we refer to the feature as "Context
- Analysis" to avoid confusion. The internal implementation still makes
- references to Clang's terminology in a few places, such as `-Wthread-safety`
- being the warning option that also still appears in diagnostic messages.
|