On 2/10/25 10:23 AM, Marco Elver wrote:
If you try to write code where you access a guarded_by variable, but
the lock is held not in all paths we can write it like this:
struct bar {
spinlock_t lock;
bool a; // true if lock held
int counter __var_guarded_by(&lock);
};
void foo(struct bar *d)
{
...
if (d->a) {
lockdep_assert_held(&d->lock);
d->counter++;
} else {
// lock not held!
}
...
}
Without lockdep_assert_held() you get false positives, and there's no
other good way to express this if you do not want to always call foo()
with the lock held.
It essentially forces addition of lockdep checks where the static
analysis can't quite prove what you've done is right. This is
desirable over adding no-analysis attributes and not checking anything
at all.
In the above I see that two different options have been mentioned for
code that includes conditional lockdep_assert_held() calls:
- Either include __assert_cap() in the lockdep_assert_held() definition.
- Or annotate the entire function with __no_thread_safety_analysis.
I think there is a third possibility: add an explicit __assert_cap()
call under the lockdep_assert_held() call. With this approach the
thread-safety analysis remains enabled for the annotated function and
the compiler will complain if neither __must_hold() nor __assert_cap()
has been used.
I prefer the third option since conditional lockdep_assert_held() calls
are relatively rare in the kernel. If I counted correctly, there are
about 40 times more unconditional lockdep_assert_held() calls than
conditional lockdep_assert_held() calls.
Bart.