aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason Baron <jbaron@redhat.com>2007-02-10 04:44:59 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-11 13:51:26 -0500
commit068135e63518314d4efd711142f674ad0841599e (patch)
treedbf8193b0e8f3b6c0e735b48c1f8201a6df207ac
parent381a229209aa6f7f72375797b7bcfcfe2ae6fcbb (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>
-rw-r--r--include/linux/lockdep.h1
-rw-r--r--kernel/lockdep.c19
-rw-r--r--kernel/lockdep_proc.c41
3 files changed, 42 insertions, 19 deletions
diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h
index ea097dddc44f..7e1160dde5e7 100644
--- a/include/linux/lockdep.h
+++ b/include/linux/lockdep.h
@@ -132,6 +132,7 @@ struct lock_list {
132 struct list_head entry; 132 struct list_head entry;
133 struct lock_class *class; 133 struct lock_class *class;
134 struct stack_trace trace; 134 struct stack_trace trace;
135 int distance;
135}; 136};
136 137
137/* 138/*
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 */
492static int add_lock_to_list(struct lock_class *class, struct lock_class *this, 492static 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 */
907static int 908static int
908check_prev_add(struct task_struct *curr, struct held_lock *prev, 909check_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
2781EXPORT_SYMBOL_GPL(debug_show_held_locks); 2787EXPORT_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
80static 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
80static int l_show(struct seq_file *m, void *v) 97static 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