mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 19:56:18 +00:00
[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:
parent
381a229209
commit
068135e635
3 changed files with 42 additions and 19 deletions
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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");
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue