mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 04:34:03 +02:00
locking/lockdep: add sequence counter to held_lock
Add an 8 bit small sequence counter to the held_lock struct to detect if the lock as been dropped and reacquired. This is useful when a data structure depends on a constant locking context, but is not able to detect locking and unlocking of the lock through its own API. Since the __lock_unpin_lock() will no longer detect underflow by casting the unsigned int to a signed int, update the casting code to use a temp variable for calculations using a signed int. Link: https://lore.kernel.org/20260821192627.4085470-3-liam@infradead.org Signed-off-by: Liam R. Howlett (Oracle) <liam@infradead.org> Suggested-by: Peter Zijlstra <peterz@infradead.org> Cc: Ingo Molnar <mingo@redhat.com> Cc: Will Deacon <will@kernel.org> Cc: Boqun Feng <boqun.feng@gmail.com> Cc: Waiman Long <longman@redhat.com> Link: https://lore.kernel.org/all/h3tpnj5kzcrxms5picmimtkpg4aypcpip5wbd6bt2rpdj5k7eb@nhtzs3lefrkq/ Cc: Breno Leitao <leitao@debian.org> Cc: Chris Mason <clm@meta.com> Cc: Chuck Lever <cel@kernel.org> Cc: Jason Gunthorpe <jgg@ziepe.ca> Cc: Joe Perches <joe@perches.com> Cc: Rik van Riel <riel@surriel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
parent
9e32ec53b1
commit
8f21098431
|
|
@ -273,6 +273,9 @@ extern struct pin_cookie lock_pin_lock(struct lockdep_map *lock);
|
|||
extern void lock_repin_lock(struct lockdep_map *lock, struct pin_cookie);
|
||||
extern void lock_unpin_lock(struct lockdep_map *lock, struct pin_cookie);
|
||||
|
||||
extern u32 lock_sequence(struct lockdep_map *lock);
|
||||
#define lockdep_sequence(lock) lock_sequence(&(lock)->dep_map)
|
||||
|
||||
#define lockdep_depth(tsk) (debug_locks ? (tsk)->lockdep_depth : 0)
|
||||
|
||||
#define lockdep_assert(cond) \
|
||||
|
|
|
|||
|
|
@ -253,7 +253,8 @@ struct held_lock {
|
|||
unsigned int hardirqs_off:1;
|
||||
unsigned int sync:1;
|
||||
unsigned int references:11; /* 32 bits */
|
||||
unsigned int pin_count;
|
||||
unsigned int pin_count:24;
|
||||
unsigned int seq_count:8;
|
||||
};
|
||||
|
||||
#else /* !CONFIG_LOCKDEP */
|
||||
|
|
|
|||
|
|
@ -1288,6 +1288,7 @@ struct task_struct {
|
|||
u64 curr_chain_key;
|
||||
int lockdep_depth;
|
||||
unsigned int lockdep_recursion;
|
||||
unsigned int lockdep_seq;
|
||||
struct held_lock held_locks[MAX_LOCK_DEPTH];
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -5077,7 +5077,7 @@ static int __lock_is_held(const struct lockdep_map *lock, int read);
|
|||
static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
|
||||
int trylock, int read, int check, int hardirqs_off,
|
||||
struct lockdep_map *nest_lock, unsigned long ip,
|
||||
int references, int pin_count, int sync)
|
||||
int references, int pin_count, int sync, int seq)
|
||||
{
|
||||
struct task_struct *curr = current;
|
||||
struct lock_class *class = NULL;
|
||||
|
|
@ -5183,6 +5183,7 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
|
|||
hlock->holdtime_stamp = lockstat_clock();
|
||||
#endif
|
||||
hlock->pin_count = pin_count;
|
||||
hlock->seq_count = seq;
|
||||
|
||||
if (check_wait_context(curr, hlock))
|
||||
return 0;
|
||||
|
|
@ -5388,7 +5389,7 @@ static int reacquire_held_locks(struct task_struct *curr, unsigned int depth,
|
|||
hlock->read, hlock->check,
|
||||
hlock->hardirqs_off,
|
||||
hlock->nest_lock, hlock->acquire_ip,
|
||||
hlock->references, hlock->pin_count, 0)) {
|
||||
hlock->references, hlock->pin_count, 0, hlock->seq_count)) {
|
||||
case 0:
|
||||
return 1;
|
||||
case 1:
|
||||
|
|
@ -5669,14 +5670,17 @@ static void __lock_unpin_lock(struct lockdep_map *lock, struct pin_cookie cookie
|
|||
struct held_lock *hlock = curr->held_locks + i;
|
||||
|
||||
if (match_held_lock(hlock, lock)) {
|
||||
int pin_count;
|
||||
|
||||
if (WARN(!hlock->pin_count, "unpinning an unpinned lock\n"))
|
||||
return;
|
||||
|
||||
hlock->pin_count -= cookie.val;
|
||||
pin_count = hlock->pin_count - cookie.val;
|
||||
|
||||
if (WARN((int)hlock->pin_count < 0, "pin count corrupted\n"))
|
||||
hlock->pin_count = 0;
|
||||
if (WARN(pin_count < 0, "pin count corrupted\n"))
|
||||
pin_count = 0;
|
||||
|
||||
hlock->pin_count = pin_count;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -5684,6 +5688,24 @@ static void __lock_unpin_lock(struct lockdep_map *lock, struct pin_cookie cookie
|
|||
WARN(1, "unpinning an unheld lock\n");
|
||||
}
|
||||
|
||||
static u32 __lock_sequence(struct lockdep_map *lock)
|
||||
{
|
||||
struct task_struct *curr = current;
|
||||
int i;
|
||||
|
||||
if (unlikely(!debug_locks))
|
||||
return ~0;
|
||||
|
||||
for (i = 0; i < curr->lockdep_depth; i++) {
|
||||
struct held_lock *hlock = curr->held_locks + i;
|
||||
|
||||
if (match_held_lock(hlock, lock))
|
||||
return hlock->seq_count;
|
||||
}
|
||||
|
||||
return ~0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether we follow the irq-flags state precisely:
|
||||
*/
|
||||
|
|
@ -5866,7 +5888,8 @@ void lock_acquire(struct lockdep_map *lock, unsigned int subclass,
|
|||
|
||||
lockdep_recursion_inc();
|
||||
__lock_acquire(lock, subclass, trylock, read, check,
|
||||
irqs_disabled_flags(flags), nest_lock, ip, 0, 0, 0);
|
||||
irqs_disabled_flags(flags), nest_lock, ip, 0, 0, 0,
|
||||
++current->lockdep_seq);
|
||||
lockdep_recursion_finish();
|
||||
raw_local_irq_restore(flags);
|
||||
}
|
||||
|
|
@ -5914,7 +5937,8 @@ void lock_sync(struct lockdep_map *lock, unsigned subclass, int read,
|
|||
|
||||
lockdep_recursion_inc();
|
||||
__lock_acquire(lock, subclass, 0, read, check,
|
||||
irqs_disabled_flags(flags), nest_lock, ip, 0, 0, 1);
|
||||
irqs_disabled_flags(flags), nest_lock, ip, 0, 0, 1,
|
||||
++current->lockdep_seq);
|
||||
check_chain_key(current);
|
||||
lockdep_recursion_finish();
|
||||
raw_local_irq_restore(flags);
|
||||
|
|
@ -6000,6 +6024,26 @@ void lock_unpin_lock(struct lockdep_map *lock, struct pin_cookie cookie)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(lock_unpin_lock);
|
||||
|
||||
u32 lock_sequence(struct lockdep_map *lock)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 seq = ~0;
|
||||
|
||||
if (unlikely(!lockdep_enabled()))
|
||||
return seq;
|
||||
|
||||
raw_local_irq_save(flags);
|
||||
check_flags(flags);
|
||||
|
||||
lockdep_recursion_inc();
|
||||
seq = __lock_sequence(lock);
|
||||
lockdep_recursion_finish();
|
||||
raw_local_irq_restore(flags);
|
||||
|
||||
return seq;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lock_sequence);
|
||||
|
||||
#ifdef CONFIG_LOCK_STAT
|
||||
static void print_lock_contention_bug(struct task_struct *curr,
|
||||
struct lockdep_map *lock,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user