170 lines
7.0 KiB
ReStructuredText
170 lines
7.0 KiB
ReStructuredText
.. 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.
|