mirror of
https://github.com/torvalds/linux.git
synced 2026-01-25 15:03:52 +08:00
locking/lockdep: Introduce lock_sync()
Currently, functions like synchronize_srcu() do not have lockdep
annotations resembling those of other write-side locking primitives.
Such annotations might look as follows:
lock_acquire();
lock_release();
Such annotations would tell lockdep that synchronize_srcu() acts like
an empty critical section that waits for other (read-side) critical
sections to finish. This would definitely catch some deadlock, but
as pointed out by Paul Mckenney [1], this could also introduce false
positives because of irq-safe/unsafe detection. Of course, there are
tricks could help with this:
might_sleep(); // Existing statement in __synchronize_srcu().
if (IS_ENABLED(CONFIG_PROVE_LOCKING)) {
local_irq_disable();
lock_acquire();
lock_release();
local_irq_enable();
}
But it would be better for lockdep to provide a separate annonation for
functions like synchronize_srcu(), so that people won't need to repeat
the ugly tricks above.
Therefore introduce lock_sync(), which is simply an lock+unlock
pair with no irq safe/unsafe deadlock check. This works because the
to-be-annontated functions do not create real critical sections, and
there is therefore no way that irq can create extra dependencies.
[1]: https://lore.kernel.org/lkml/20180412021233.ewncg5jjuzjw3x62@tardis/
Signed-off-by: Boqun Feng <boqun.feng@gmail.com>
Acked-by: Waiman Long <longman@redhat.com>
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
[ boqun: Fix typos reported by Davidlohr Bueso and Paul E. Mckenney ]
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Boqun Feng <boqun.feng@gmail.com>
This commit is contained in:
@@ -5693,6 +5693,40 @@ void lock_release(struct lockdep_map *lock, unsigned long ip)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lock_release);
|
||||
|
||||
/*
|
||||
* lock_sync() - A special annotation for synchronize_{s,}rcu()-like API.
|
||||
*
|
||||
* No actual critical section is created by the APIs annotated with this: these
|
||||
* APIs are used to wait for one or multiple critical sections (on other CPUs
|
||||
* or threads), and it means that calling these APIs inside these critical
|
||||
* sections is potential deadlock.
|
||||
*
|
||||
* This annotation acts as an acquire+release annotation pair with hardirqoff
|
||||
* being 1. Since there's no critical section, no interrupt can create extra
|
||||
* dependencies "inside" the annotation, hardirqoff == 1 allows us to avoid
|
||||
* false positives.
|
||||
*/
|
||||
void lock_sync(struct lockdep_map *lock, unsigned subclass, int read,
|
||||
int check, struct lockdep_map *nest_lock, unsigned long ip)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (unlikely(!lockdep_enabled()))
|
||||
return;
|
||||
|
||||
raw_local_irq_save(flags);
|
||||
check_flags(flags);
|
||||
|
||||
lockdep_recursion_inc();
|
||||
__lock_acquire(lock, subclass, 0, read, check, 1, nest_lock, ip, 0, 0);
|
||||
|
||||
if (__lock_release(lock, ip))
|
||||
check_chain_key(current);
|
||||
lockdep_recursion_finish();
|
||||
raw_local_irq_restore(flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lock_sync);
|
||||
|
||||
noinstr int lock_is_held_type(const struct lockdep_map *lock, int read)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
Reference in New Issue
Block a user