Skip to content

Commit 2bb8945

Browse files
Peter ZijlstraIngo Molnar
authored andcommitted
lockdep: Fix usage_traceoverflow
Basically print_lock_class_header()'s for loop is out of sync with the the size of of ->usage_traces[]. Also clean things up a bit while at it, to avoid such mishaps in the future. Fixes: 23870f1 ("locking/lockdep: Fix "USED" <- "IN-NMI" inversions") Reported-by: Qian Cai <cai@redhat.com> Debugged-by: Boqun Feng <boqun.feng@gmail.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Ingo Molnar <mingo@kernel.org> Tested-by: Qian Cai <cai@redhat.com> Link: https://lkml.kernel.org/r/20200930094937.GE2651@hirez.programming.kicks-ass.net
1 parent 583090b commit 2bb8945

File tree

3 files changed

+26
-21
lines changed

3 files changed

+26
-21
lines changed

include/linux/lockdep_types.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,12 @@ enum lockdep_wait_type {
3535
/*
3636
* We'd rather not expose kernel/lockdep_states.h this wide, but we do need
3737
* the total number of states... :-(
38+
*
39+
* XXX_LOCK_USAGE_STATES is the number of lines in lockdep_states.h, for each
40+
* of those we generates 4 states, Additionally we report on USED and USED_READ.
3841
*/
39-
#define XXX_LOCK_USAGE_STATES (1+2*4)
42+
#define XXX_LOCK_USAGE_STATES 2
43+
#define LOCK_TRACE_STATES (XXX_LOCK_USAGE_STATES*4 + 2)
4044

4145
/*
4246
* NR_LOCKDEP_CACHING_CLASSES ... Number of classes
@@ -106,7 +110,7 @@ struct lock_class {
106110
* IRQ/softirq usage tracking bits:
107111
*/
108112
unsigned long usage_mask;
109-
const struct lock_trace *usage_traces[XXX_LOCK_USAGE_STATES];
113+
const struct lock_trace *usage_traces[LOCK_TRACE_STATES];
110114

111115
/*
112116
* Generation counter, when doing certain classes of graph walking,

kernel/locking/lockdep.c

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,8 @@ static const char *usage_str[] =
585585
#include "lockdep_states.h"
586586
#undef LOCKDEP_STATE
587587
[LOCK_USED] = "INITIAL USE",
588+
[LOCK_USED_READ] = "INITIAL READ USE",
589+
/* abused as string storage for verify_lock_unused() */
588590
[LOCK_USAGE_STATES] = "IN-NMI",
589591
};
590592
#endif
@@ -1939,7 +1941,7 @@ static void print_lock_class_header(struct lock_class *class, int depth)
19391941
#endif
19401942
printk(KERN_CONT " {\n");
19411943

1942-
for (bit = 0; bit < LOCK_USAGE_STATES; bit++) {
1944+
for (bit = 0; bit < LOCK_TRACE_STATES; bit++) {
19431945
if (class->usage_mask & (1 << bit)) {
19441946
int len = depth;
19451947

@@ -3969,7 +3971,7 @@ static int separate_irq_context(struct task_struct *curr,
39693971
static int mark_lock(struct task_struct *curr, struct held_lock *this,
39703972
enum lock_usage_bit new_bit)
39713973
{
3972-
unsigned int old_mask, new_mask, ret = 1;
3974+
unsigned int new_mask, ret = 1;
39733975

39743976
if (new_bit >= LOCK_USAGE_STATES) {
39753977
DEBUG_LOCKS_WARN_ON(1);
@@ -3996,30 +3998,26 @@ static int mark_lock(struct task_struct *curr, struct held_lock *this,
39963998
if (unlikely(hlock_class(this)->usage_mask & new_mask))
39973999
goto unlock;
39984000

3999-
old_mask = hlock_class(this)->usage_mask;
40004001
hlock_class(this)->usage_mask |= new_mask;
40014002

4002-
/*
4003-
* Save one usage_traces[] entry and map both LOCK_USED and
4004-
* LOCK_USED_READ onto the same entry.
4005-
*/
4006-
if (new_bit == LOCK_USED || new_bit == LOCK_USED_READ) {
4007-
if (old_mask & (LOCKF_USED | LOCKF_USED_READ))
4008-
goto unlock;
4009-
new_bit = LOCK_USED;
4003+
if (new_bit < LOCK_TRACE_STATES) {
4004+
if (!(hlock_class(this)->usage_traces[new_bit] = save_trace()))
4005+
return 0;
40104006
}
40114007

4012-
if (!(hlock_class(this)->usage_traces[new_bit] = save_trace()))
4013-
return 0;
4014-
40154008
switch (new_bit) {
4009+
case 0 ... LOCK_USED-1:
4010+
ret = mark_lock_irq(curr, this, new_bit);
4011+
if (!ret)
4012+
return 0;
4013+
break;
4014+
40164015
case LOCK_USED:
40174016
debug_atomic_dec(nr_unused_locks);
40184017
break;
4018+
40194019
default:
4020-
ret = mark_lock_irq(curr, this, new_bit);
4021-
if (!ret)
4022-
return 0;
4020+
break;
40234021
}
40244022

40254023
unlock:

kernel/locking/lockdep_internals.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,12 @@ enum lock_usage_bit {
2020
#undef LOCKDEP_STATE
2121
LOCK_USED,
2222
LOCK_USED_READ,
23-
LOCK_USAGE_STATES
23+
LOCK_USAGE_STATES,
2424
};
2525

26+
/* states after LOCK_USED_READ are not traced and printed */
27+
static_assert(LOCK_TRACE_STATES == LOCK_USAGE_STATES);
28+
2629
#define LOCK_USAGE_READ_MASK 1
2730
#define LOCK_USAGE_DIR_MASK 2
2831
#define LOCK_USAGE_STATE_MASK (~(LOCK_USAGE_READ_MASK | LOCK_USAGE_DIR_MASK))
@@ -121,7 +124,7 @@ static const unsigned long LOCKF_USED_IN_IRQ_READ =
121124
extern struct list_head all_lock_classes;
122125
extern struct lock_chain lock_chains[];
123126

124-
#define LOCK_USAGE_CHARS (1+LOCK_USAGE_STATES/2)
127+
#define LOCK_USAGE_CHARS (2*XXX_LOCK_USAGE_STATES + 1)
125128

126129
extern void get_usage_chars(struct lock_class *class,
127130
char usage[LOCK_USAGE_CHARS]);

0 commit comments

Comments
 (0)