[PATCH] lockdep: add graph depth information to /proc/lockdep

Generate locking graph information into /proc/lockdep, for lock hierarchy
documentation and visualization purposes.

sample output:

 c089fd5c OPS:     138 FD:   14 BD:    1 --..: &tty->termios_mutex
  -> [c07a3430] tty_ldisc_lock
  -> [c07a37f0] &port_lock_key
  -> [c07afdc0] &rq->rq_lock_key#2

The lock classes listed are all the first-hop lock dependencies that
lockdep has seen so far.

Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Jason Baron 2007-02-10 01:44:59 -08:00 committed by Linus Torvalds
parent 381a229209
commit 068135e635
3 changed files with 42 additions and 19 deletions

View file

@ -132,6 +132,7 @@ struct lock_list {
struct list_head entry; struct list_head entry;
struct lock_class *class; struct lock_class *class;
struct stack_trace trace; struct stack_trace trace;
int distance;
}; };
/* /*

View file

@ -490,7 +490,7 @@ static void print_lock_dependencies(struct lock_class *class, int depth)
* Add a new dependency to the head of the list: * Add a new dependency to the head of the list:
*/ */
static int add_lock_to_list(struct lock_class *class, struct lock_class *this, static int add_lock_to_list(struct lock_class *class, struct lock_class *this,
struct list_head *head, unsigned long ip) struct list_head *head, unsigned long ip, int distance)
{ {
struct lock_list *entry; struct lock_list *entry;
/* /*
@ -502,6 +502,7 @@ static int add_lock_to_list(struct lock_class *class, struct lock_class *this,
return 0; return 0;
entry->class = this; entry->class = this;
entry->distance = distance;
if (!save_trace(&entry->trace)) if (!save_trace(&entry->trace))
return 0; return 0;
@ -906,7 +907,7 @@ check_deadlock(struct task_struct *curr, struct held_lock *next,
*/ */
static int static int
check_prev_add(struct task_struct *curr, struct held_lock *prev, check_prev_add(struct task_struct *curr, struct held_lock *prev,
struct held_lock *next) struct held_lock *next, int distance)
{ {
struct lock_list *entry; struct lock_list *entry;
int ret; int ret;
@ -984,8 +985,11 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev,
* L2 added to its dependency list, due to the first chain.) * L2 added to its dependency list, due to the first chain.)
*/ */
list_for_each_entry(entry, &prev->class->locks_after, entry) { list_for_each_entry(entry, &prev->class->locks_after, entry) {
if (entry->class == next->class) if (entry->class == next->class) {
if (distance == 1)
entry->distance = 1;
return 2; return 2;
}
} }
/* /*
@ -993,12 +997,13 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev,
* to the previous lock's dependency list: * to the previous lock's dependency list:
*/ */
ret = add_lock_to_list(prev->class, next->class, ret = add_lock_to_list(prev->class, next->class,
&prev->class->locks_after, next->acquire_ip); &prev->class->locks_after, next->acquire_ip, distance);
if (!ret) if (!ret)
return 0; return 0;
ret = add_lock_to_list(next->class, prev->class, ret = add_lock_to_list(next->class, prev->class,
&next->class->locks_before, next->acquire_ip); &next->class->locks_before, next->acquire_ip, distance);
if (!ret) if (!ret)
return 0; return 0;
@ -1046,13 +1051,14 @@ check_prevs_add(struct task_struct *curr, struct held_lock *next)
goto out_bug; goto out_bug;
for (;;) { for (;;) {
int distance = curr->lockdep_depth - depth + 1;
hlock = curr->held_locks + depth-1; hlock = curr->held_locks + depth-1;
/* /*
* Only non-recursive-read entries get new dependencies * Only non-recursive-read entries get new dependencies
* added: * added:
*/ */
if (hlock->read != 2) { if (hlock->read != 2) {
if (!check_prev_add(curr, hlock, next)) if (!check_prev_add(curr, hlock, next, distance))
return 0; return 0;
/* /*
* Stop after the first non-trylock entry, * Stop after the first non-trylock entry,
@ -2779,4 +2785,3 @@ void debug_show_held_locks(struct task_struct *task)
} }
EXPORT_SYMBOL_GPL(debug_show_held_locks); EXPORT_SYMBOL_GPL(debug_show_held_locks);

View file

@ -77,12 +77,29 @@ static unsigned long count_backward_deps(struct lock_class *class)
return ret; return ret;
} }
static void print_name(struct seq_file *m, struct lock_class *class)
{
char str[128];
const char *name = class->name;
if (!name) {
name = __get_key_name(class->key, str);
seq_printf(m, "%s", name);
} else{
seq_printf(m, "%s", name);
if (class->name_version > 1)
seq_printf(m, "#%d", class->name_version);
if (class->subclass)
seq_printf(m, "/%d", class->subclass);
}
}
static int l_show(struct seq_file *m, void *v) static int l_show(struct seq_file *m, void *v)
{ {
unsigned long nr_forward_deps, nr_backward_deps; unsigned long nr_forward_deps, nr_backward_deps;
struct lock_class *class = m->private; struct lock_class *class = m->private;
char str[128], c1, c2, c3, c4; struct lock_list *entry;
const char *name; char c1, c2, c3, c4;
seq_printf(m, "%p", class->key); seq_printf(m, "%p", class->key);
#ifdef CONFIG_DEBUG_LOCKDEP #ifdef CONFIG_DEBUG_LOCKDEP
@ -97,16 +114,16 @@ static int l_show(struct seq_file *m, void *v)
get_usage_chars(class, &c1, &c2, &c3, &c4); get_usage_chars(class, &c1, &c2, &c3, &c4);
seq_printf(m, " %c%c%c%c", c1, c2, c3, c4); seq_printf(m, " %c%c%c%c", c1, c2, c3, c4);
name = class->name; seq_printf(m, ": ");
if (!name) { print_name(m, class);
name = __get_key_name(class->key, str); seq_puts(m, "\n");
seq_printf(m, ": %s", name);
} else{ list_for_each_entry(entry, &class->locks_after, entry) {
seq_printf(m, ": %s", name); if (entry->distance == 1) {
if (class->name_version > 1) seq_printf(m, " -> [%p] ", entry->class);
seq_printf(m, "#%d", class->name_version); print_name(m, entry->class);
if (class->subclass) seq_puts(m, "\n");
seq_printf(m, "/%d", class->subclass); }
} }
seq_puts(m, "\n"); seq_puts(m, "\n");