diff options
author | Jason Baron <jbaron@redhat.com> | 2007-02-10 04:44:59 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-11 13:51:26 -0500 |
commit | 068135e63518314d4efd711142f674ad0841599e (patch) | |
tree | dbf8193b0e8f3b6c0e735b48c1f8201a6df207ac /kernel | |
parent | 381a229209aa6f7f72375797b7bcfcfe2ae6fcbb (diff) |
[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>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/lockdep.c | 19 | ||||
-rw-r--r-- | kernel/lockdep_proc.c | 41 |
2 files changed, 41 insertions, 19 deletions
diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 2d616f4d853c..592c576d77a7 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c | |||
@@ -490,7 +490,7 @@ static void print_lock_dependencies(struct lock_class *class, int depth) | |||
490 | * Add a new dependency to the head of the list: | 490 | * Add a new dependency to the head of the list: |
491 | */ | 491 | */ |
492 | static int add_lock_to_list(struct lock_class *class, struct lock_class *this, | 492 | static int add_lock_to_list(struct lock_class *class, struct lock_class *this, |
493 | struct list_head *head, unsigned long ip) | 493 | struct list_head *head, unsigned long ip, int distance) |
494 | { | 494 | { |
495 | struct lock_list *entry; | 495 | struct lock_list *entry; |
496 | /* | 496 | /* |
@@ -502,6 +502,7 @@ static int add_lock_to_list(struct lock_class *class, struct lock_class *this, | |||
502 | return 0; | 502 | return 0; |
503 | 503 | ||
504 | entry->class = this; | 504 | entry->class = this; |
505 | entry->distance = distance; | ||
505 | if (!save_trace(&entry->trace)) | 506 | if (!save_trace(&entry->trace)) |
506 | return 0; | 507 | return 0; |
507 | 508 | ||
@@ -906,7 +907,7 @@ check_deadlock(struct task_struct *curr, struct held_lock *next, | |||
906 | */ | 907 | */ |
907 | static int | 908 | static int |
908 | check_prev_add(struct task_struct *curr, struct held_lock *prev, | 909 | check_prev_add(struct task_struct *curr, struct held_lock *prev, |
909 | struct held_lock *next) | 910 | struct held_lock *next, int distance) |
910 | { | 911 | { |
911 | struct lock_list *entry; | 912 | struct lock_list *entry; |
912 | int ret; | 913 | int ret; |
@@ -984,8 +985,11 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev, | |||
984 | * L2 added to its dependency list, due to the first chain.) | 985 | * L2 added to its dependency list, due to the first chain.) |
985 | */ | 986 | */ |
986 | list_for_each_entry(entry, &prev->class->locks_after, entry) { | 987 | list_for_each_entry(entry, &prev->class->locks_after, entry) { |
987 | if (entry->class == next->class) | 988 | if (entry->class == next->class) { |
989 | if (distance == 1) | ||
990 | entry->distance = 1; | ||
988 | return 2; | 991 | return 2; |
992 | } | ||
989 | } | 993 | } |
990 | 994 | ||
991 | /* | 995 | /* |
@@ -993,12 +997,13 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev, | |||
993 | * to the previous lock's dependency list: | 997 | * to the previous lock's dependency list: |
994 | */ | 998 | */ |
995 | ret = add_lock_to_list(prev->class, next->class, | 999 | ret = add_lock_to_list(prev->class, next->class, |
996 | &prev->class->locks_after, next->acquire_ip); | 1000 | &prev->class->locks_after, next->acquire_ip, distance); |
1001 | |||
997 | if (!ret) | 1002 | if (!ret) |
998 | return 0; | 1003 | return 0; |
999 | 1004 | ||
1000 | ret = add_lock_to_list(next->class, prev->class, | 1005 | ret = add_lock_to_list(next->class, prev->class, |
1001 | &next->class->locks_before, next->acquire_ip); | 1006 | &next->class->locks_before, next->acquire_ip, distance); |
1002 | if (!ret) | 1007 | if (!ret) |
1003 | return 0; | 1008 | return 0; |
1004 | 1009 | ||
@@ -1046,13 +1051,14 @@ check_prevs_add(struct task_struct *curr, struct held_lock *next) | |||
1046 | goto out_bug; | 1051 | goto out_bug; |
1047 | 1052 | ||
1048 | for (;;) { | 1053 | for (;;) { |
1054 | int distance = curr->lockdep_depth - depth + 1; | ||
1049 | hlock = curr->held_locks + depth-1; | 1055 | hlock = curr->held_locks + depth-1; |
1050 | /* | 1056 | /* |
1051 | * Only non-recursive-read entries get new dependencies | 1057 | * Only non-recursive-read entries get new dependencies |
1052 | * added: | 1058 | * added: |
1053 | */ | 1059 | */ |
1054 | if (hlock->read != 2) { | 1060 | if (hlock->read != 2) { |
1055 | if (!check_prev_add(curr, hlock, next)) | 1061 | if (!check_prev_add(curr, hlock, next, distance)) |
1056 | return 0; | 1062 | return 0; |
1057 | /* | 1063 | /* |
1058 | * Stop after the first non-trylock entry, | 1064 | * Stop after the first non-trylock entry, |
@@ -2779,4 +2785,3 @@ void debug_show_held_locks(struct task_struct *task) | |||
2779 | } | 2785 | } |
2780 | 2786 | ||
2781 | EXPORT_SYMBOL_GPL(debug_show_held_locks); | 2787 | EXPORT_SYMBOL_GPL(debug_show_held_locks); |
2782 | |||
diff --git a/kernel/lockdep_proc.c b/kernel/lockdep_proc.c index b554b40a4aa6..57a547a2da3f 100644 --- a/kernel/lockdep_proc.c +++ b/kernel/lockdep_proc.c | |||
@@ -77,12 +77,29 @@ static unsigned long count_backward_deps(struct lock_class *class) | |||
77 | return ret; | 77 | return ret; |
78 | } | 78 | } |
79 | 79 | ||
80 | static void print_name(struct seq_file *m, struct lock_class *class) | ||
81 | { | ||
82 | char str[128]; | ||
83 | const char *name = class->name; | ||
84 | |||
85 | if (!name) { | ||
86 | name = __get_key_name(class->key, str); | ||
87 | seq_printf(m, "%s", name); | ||
88 | } else{ | ||
89 | seq_printf(m, "%s", name); | ||
90 | if (class->name_version > 1) | ||
91 | seq_printf(m, "#%d", class->name_version); | ||
92 | if (class->subclass) | ||
93 | seq_printf(m, "/%d", class->subclass); | ||
94 | } | ||
95 | } | ||
96 | |||
80 | static int l_show(struct seq_file *m, void *v) | 97 | static int l_show(struct seq_file *m, void *v) |
81 | { | 98 | { |
82 | unsigned long nr_forward_deps, nr_backward_deps; | 99 | unsigned long nr_forward_deps, nr_backward_deps; |
83 | struct lock_class *class = m->private; | 100 | struct lock_class *class = m->private; |
84 | char str[128], c1, c2, c3, c4; | 101 | struct lock_list *entry; |
85 | const char *name; | 102 | char c1, c2, c3, c4; |
86 | 103 | ||
87 | seq_printf(m, "%p", class->key); | 104 | seq_printf(m, "%p", class->key); |
88 | #ifdef CONFIG_DEBUG_LOCKDEP | 105 | #ifdef CONFIG_DEBUG_LOCKDEP |
@@ -97,16 +114,16 @@ static int l_show(struct seq_file *m, void *v) | |||
97 | get_usage_chars(class, &c1, &c2, &c3, &c4); | 114 | get_usage_chars(class, &c1, &c2, &c3, &c4); |
98 | seq_printf(m, " %c%c%c%c", c1, c2, c3, c4); | 115 | seq_printf(m, " %c%c%c%c", c1, c2, c3, c4); |
99 | 116 | ||
100 | name = class->name; | 117 | seq_printf(m, ": "); |
101 | if (!name) { | 118 | print_name(m, class); |
102 | name = __get_key_name(class->key, str); | 119 | seq_puts(m, "\n"); |
103 | seq_printf(m, ": %s", name); | 120 | |
104 | } else{ | 121 | list_for_each_entry(entry, &class->locks_after, entry) { |
105 | seq_printf(m, ": %s", name); | 122 | if (entry->distance == 1) { |
106 | if (class->name_version > 1) | 123 | seq_printf(m, " -> [%p] ", entry->class); |
107 | seq_printf(m, "#%d", class->name_version); | 124 | print_name(m, entry->class); |
108 | if (class->subclass) | 125 | seq_puts(m, "\n"); |
109 | seq_printf(m, "/%d", class->subclass); | 126 | } |
110 | } | 127 | } |
111 | seq_puts(m, "\n"); | 128 | seq_puts(m, "\n"); |
112 | 129 | ||