Whamcloud - gitweb
LU-1419 lnet: Add support for Cray's Gemini interconnect
[fs/lustre-release.git] / lustre / kernel_patches / patches / lockdep_chains-2.6.18-vanilla.patch
1 commit 443cd507ce7f78c6f8742b72736585c031d5a921
2 Author: Huang, Ying <ying.huang@intel.com>
3 Date:   Fri Jun 20 16:39:21 2008 +0800
4
5     lockdep: add lock_class information to lock_chain and output it
6     
7     This patch records array of lock_class into lock_chain, and export
8     lock_chain information via /proc/lockdep_chains.
9     
10     It is based on x86/master branch of git-x86 tree, and has been tested
11     on x86_64 platform.
12     
13     Signed-off-by: Huang Ying <ying.huang@intel.com>
14     Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
15     Signed-off-by: Ingo Molnar <mingo@elte.hu>
16
17 diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h
18 index 4c4d236..b26fbc7 100644
19 --- a/include/linux/lockdep.h
20 +++ b/include/linux/lockdep.h
21 @@ -182,6 +182,9 @@ struct lock_list {
22   * We record lock dependency chains, so that we can cache them:
23   */
24  struct lock_chain {
25 +       u8                              irq_context;
26 +       u8                              depth;
27 +       u16                             base;
28         struct list_head                entry;
29         u64                             chain_key;
30  };
31 diff --git a/kernel/lockdep.c b/kernel/lockdep.c
32 index 81a4e4a..a796f1f 100644
33 --- a/kernel/lockdep.c
34 +++ b/kernel/lockdep.c
35 @@ -1458,7 +1458,14 @@ out_bug:
36  }
37  
38  unsigned long nr_lock_chains;
39 -static struct lock_chain lock_chains[MAX_LOCKDEP_CHAINS];
40 +struct lock_chain lock_chains[MAX_LOCKDEP_CHAINS];
41 +atomic_t nr_chain_hlocks;
42 +static u16 chain_hlocks[MAX_LOCKDEP_CHAIN_HLOCKS];
43 +
44 +struct lock_class *lock_chain_get_class(struct lock_chain *chain, int i)
45 +{
46 +       return lock_classes + chain_hlocks[chain->base + i];
47 +}
48  
49  /*
50   * Look up a dependency chain. If the key is not present yet then
51 @@ -1466,9 +1473,14 @@ static struct lock_chain lock_chains[MAX_LOCKDEP_CHAINS];
52   * validated. If the key is already hashed, return 0.
53   */
54 -static inline int lookup_chain_cache(u64 chain_key)
55 +static inline int lookup_chain_cache(struct task_struct *curr,
56 +                                    struct held_lock *hlock,
57 +                                    u64 chain_key)
58  {
59 +       struct lock_class *class = hlock->class;
60         struct list_head *hash_head = chainhashentry(chain_key);
61         struct lock_chain *chain;
62 +       struct held_lock *hlock_curr, *hlock_next;
63 +       int i, j, n;
64  
65         if (DEBUG_LOCKS_WARN_ON(!irqs_disabled()))
66                 return 0;
67 @@ -1517,6 +1529,26 @@ cache_hit:
68         }
69         chain = lock_chains + nr_lock_chains++;
70         chain->chain_key = chain_key;
71 +       chain->irq_context = hlock->irq_context;
72 +       /* Find the first held_lock of current chain */
73 +       hlock_next = hlock;
74 +       for (i = curr->lockdep_depth - 1; i >= 0; i--) {
75 +               hlock_curr = curr->held_locks + i;
76 +               if (hlock_curr->irq_context != hlock_next->irq_context)
77 +                       break;
78 +               hlock_next = hlock;
79 +       }
80 +       i++;
81 +       chain->depth = curr->lockdep_depth + 1 - i;
82 +       n = atomic_add_return(chain->depth, &nr_chain_hlocks);
83 +       if (unlikely(n < MAX_LOCKDEP_CHAIN_HLOCKS)) {
84 +               chain->base = n - chain->depth;
85 +               for (j = 0; j < chain->depth - 1; j++, i++) {
86 +                       int lock_id = curr->held_locks[i].class - lock_classes;
87 +                       chain_hlocks[chain->base + j] = lock_id;
88 +               }
89 +               chain_hlocks[chain->base + j] = class - lock_classes;
90 +       }
91         list_add_tail_rcu(&chain->entry, hash_head);
92         debug_atomic_inc(&chain_lookup_misses);
93         inc_chains();
94 @@ -1538,7 +1570,7 @@ static int validate_chain(struct task_struct *curr, struct lockdep_map *lock,
95          * (If lookup_chain_cache() returns with 1 it acquires
96          * hash_lock for us)
97          */
98 -       if (!trylock && (check == 2) && lookup_chain_cache(chain_key)) {
99 +       if (!trylock && (check == 2) && lookup_chain_cache(curr, hlock, chain_key)) {
100                 /*
101                  * Check whether last held lock:
102                  *
103 diff --git a/kernel/lockdep_internals.h b/kernel/lockdep_internals.h
104 index 8ce09bc..db09b17 100644
105 --- a/kernel/lockdep_internals.h
106 +++ b/kernel/lockdep_internals.h
107 @@ -23,6 +23,8 @@
108  #define MAX_LOCKDEP_CHAINS_BITS        14
109  #define MAX_LOCKDEP_CHAINS     (1UL << MAX_LOCKDEP_CHAINS_BITS)
110  
111 +#define MAX_LOCKDEP_CHAIN_HLOCKS (MAX_LOCKDEP_CHAINS*5)
112 +
113  /*
114   * Stack-trace: tightly packed array of stack backtrace
115   * addresses. Protected by the hash_lock.
116 @@ -30,15 +32,19 @@
117  #define MAX_STACK_TRACE_ENTRIES        262144UL
118  
119  extern struct list_head all_lock_classes;
120 +extern struct lock_chain lock_chains[];
121  
122  extern void
123  get_usage_chars(struct lock_class *class, char *c1, char *c2, char *c3, char *c4);
124  
125  extern const char * __get_key_name(struct lockdep_subclass_key *key, char *str);
126  
127 +struct lock_class *lock_chain_get_class(struct lock_chain *chain, int i);
128 +
129  extern unsigned long nr_lock_classes;
130  extern unsigned long nr_list_entries;
131  extern unsigned long nr_lock_chains;
132 +extern atomic_t nr_chain_hlocks;
133  extern unsigned long nr_stack_trace_entries;
134  
135  extern unsigned int nr_hardirq_chains;
136 diff --git a/kernel/lockdep_proc.c b/kernel/lockdep_proc.c
137 index 688c5f1..14d052c 100644
138 --- a/kernel/lockdep_proc.c
139 +++ b/kernel/lockdep_proc.c
140 @@ -178,6 +178,110 @@ static const struct file_operations proc_lockdep_operations = {
141         .release        = seq_release,
142  };
143  
144 +static void print_name(struct seq_file *m, struct lock_class *class)
145 +{
146 +       char str[128];
147 +       const char *name = class->name;
148 +
149 +       if (!name) {
150 +               name = __get_key_name(class->key, str);
151 +               seq_printf(m, "%s", name);
152 +       } else{
153 +               seq_printf(m, "%s", name);
154 +               if (class->name_version > 1)
155 +                       seq_printf(m, "#%d", class->name_version);
156 +               if (class->subclass)
157 +                       seq_printf(m, "/%d", class->subclass);
158 +       }
159 +}
160 +
161 +static void *lc_next(struct seq_file *m, void *v, loff_t *pos)
162 +{
163 +       struct lock_chain *chain;
164 +
165 +       (*pos)++;
166 +
167 +       if (v == SEQ_START_TOKEN)
168 +               chain = m->private;
169 +       else {
170 +               chain = v;
171 +
172 +               if (*pos < nr_lock_chains)
173 +                       chain = lock_chains + *pos;
174 +               else
175 +                       chain = NULL;
176 +       }
177 +
178 +       return chain;
179 +}
180 +
181 +static void *lc_start(struct seq_file *m, loff_t *pos)
182 +{
183 +       if (*pos == 0)
184 +               return SEQ_START_TOKEN;
185 +
186 +       if (*pos < nr_lock_chains)
187 +               return lock_chains + *pos;
188 +
189 +       return NULL;
190 +}
191 +
192 +static void lc_stop(struct seq_file *m, void *v)
193 +{
194 +}
195 +
196 +static int lc_show(struct seq_file *m, void *v)
197 +{
198 +       struct lock_chain *chain = v;
199 +       struct lock_class *class;
200 +       int i;
201 +
202 +       if (v == SEQ_START_TOKEN) {
203 +               seq_printf(m, "all lock chains:\n");
204 +               return 0;
205 +       }
206 +
207 +       seq_printf(m, "irq_context: %d\n", chain->irq_context);
208 +
209 +       for (i = 0; i < chain->depth; i++) {
210 +               class = lock_chain_get_class(chain, i);
211 +               seq_printf(m, "[%p] ", class->key);
212 +               print_name(m, class);
213 +               seq_puts(m, "\n");
214 +       }
215 +       seq_puts(m, "\n");
216 +
217 +       return 0;
218 +}
219 +
220 +static const struct seq_operations lockdep_chains_ops = {
221 +       .start  = lc_start,
222 +       .next   = lc_next,
223 +       .stop   = lc_stop,
224 +       .show   = lc_show,
225 +};
226 +
227 +static int lockdep_chains_open(struct inode *inode, struct file *file)
228 +{
229 +       int res = seq_open(file, &lockdep_chains_ops);
230 +       if (!res) {
231 +               struct seq_file *m = file->private_data;
232 +
233 +               if (nr_lock_chains)
234 +                       m->private = lock_chains;
235 +               else
236 +                       m->private = NULL;
237 +       }
238 +       return res;
239 +}
240 +
241 +static const struct file_operations proc_lockdep_chains_operations = {
242 +       .open           = lockdep_chains_open,
243 +       .read           = seq_read,
244 +       .llseek         = seq_lseek,
245 +       .release        = seq_release,
246 +};
247 +
248  static void lockdep_stats_debug_show(struct seq_file *m)
249  {
250  #ifdef CONFIG_DEBUG_LOCKDEP
251 @@ -294,5 +381,7 @@ static int lockdep_stats_show(struct seq_file *m, void *v)
252  
253         seq_printf(m, " dependency chains:             %11lu [max: %lu]\n",
254                         nr_lock_chains, MAX_LOCKDEP_CHAINS);
255 +       seq_printf(m, " dependency chain hlocks:       %11d [max: %lu]\n",
256 +                       atomic_read(&nr_chain_hlocks), MAX_LOCKDEP_CHAIN_HLOCKS);
257  
258  #ifdef CONFIG_TRACE_IRQFLAGS
259 @@ -661,6 +750,9 @@ static const struct file_operations proc_lock_stat_operations = {
260         entry = create_proc_entry("lockdep", S_IRUSR, NULL);
261         if (entry)
262                 entry->proc_fops = &proc_lockdep_operations;
263 +       entry = create_proc_entry("lockdep_chains", S_IRUSR, NULL);
264 +   if (entry)
265 +               entry->proc_fops = &proc_lockdep_chains_operations;
266  
267         entry = create_proc_entry("lockdep_stats", S_IRUSR, NULL);
268         if (entry)
269