Merge branch 'timers-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6] / fs / dlm / debug_fs.c
1 /******************************************************************************
2 *******************************************************************************
3 **
4 **  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
5 **
6 **  This copyrighted material is made available to anyone wishing to use,
7 **  modify, copy, or redistribute it subject to the terms and conditions
8 **  of the GNU General Public License v.2.
9 **
10 *******************************************************************************
11 ******************************************************************************/
12
13 #include <linux/pagemap.h>
14 #include <linux/seq_file.h>
15 #include <linux/module.h>
16 #include <linux/ctype.h>
17 #include <linux/debugfs.h>
18
19 #include "dlm_internal.h"
20 #include "lock.h"
21
22 #define DLM_DEBUG_BUF_LEN 4096
23 static char debug_buf[DLM_DEBUG_BUF_LEN];
24 static struct mutex debug_buf_lock;
25
26 static struct dentry *dlm_root;
27
28 struct rsb_iter {
29         int entry;
30         int locks;
31         int header;
32         struct dlm_ls *ls;
33         struct list_head *next;
34         struct dlm_rsb *rsb;
35 };
36
37 /*
38  * dump all rsb's in the lockspace hash table
39  */
40
41 static char *print_lockmode(int mode)
42 {
43         switch (mode) {
44         case DLM_LOCK_IV:
45                 return "--";
46         case DLM_LOCK_NL:
47                 return "NL";
48         case DLM_LOCK_CR:
49                 return "CR";
50         case DLM_LOCK_CW:
51                 return "CW";
52         case DLM_LOCK_PR:
53                 return "PR";
54         case DLM_LOCK_PW:
55                 return "PW";
56         case DLM_LOCK_EX:
57                 return "EX";
58         default:
59                 return "??";
60         }
61 }
62
63 static void print_resource_lock(struct seq_file *s, struct dlm_lkb *lkb,
64                                 struct dlm_rsb *res)
65 {
66         seq_printf(s, "%08x %s", lkb->lkb_id, print_lockmode(lkb->lkb_grmode));
67
68         if (lkb->lkb_status == DLM_LKSTS_CONVERT
69             || lkb->lkb_status == DLM_LKSTS_WAITING)
70                 seq_printf(s, " (%s)", print_lockmode(lkb->lkb_rqmode));
71
72         if (lkb->lkb_nodeid) {
73                 if (lkb->lkb_nodeid != res->res_nodeid)
74                         seq_printf(s, " Remote: %3d %08x", lkb->lkb_nodeid,
75                                    lkb->lkb_remid);
76                 else
77                         seq_printf(s, " Master:     %08x", lkb->lkb_remid);
78         }
79
80         if (lkb->lkb_wait_type)
81                 seq_printf(s, " wait_type: %d", lkb->lkb_wait_type);
82
83         seq_printf(s, "\n");
84 }
85
86 static int print_resource(struct dlm_rsb *res, struct seq_file *s)
87 {
88         struct dlm_lkb *lkb;
89         int i, lvblen = res->res_ls->ls_lvblen, recover_list, root_list;
90
91         lock_rsb(res);
92
93         seq_printf(s, "\nResource %p Name (len=%d) \"", res, res->res_length);
94         for (i = 0; i < res->res_length; i++) {
95                 if (isprint(res->res_name[i]))
96                         seq_printf(s, "%c", res->res_name[i]);
97                 else
98                         seq_printf(s, "%c", '.');
99         }
100         if (res->res_nodeid > 0)
101                 seq_printf(s, "\"  \nLocal Copy, Master is node %d\n",
102                            res->res_nodeid);
103         else if (res->res_nodeid == 0)
104                 seq_printf(s, "\"  \nMaster Copy\n");
105         else if (res->res_nodeid == -1)
106                 seq_printf(s, "\"  \nLooking up master (lkid %x)\n",
107                            res->res_first_lkid);
108         else
109                 seq_printf(s, "\"  \nInvalid master %d\n", res->res_nodeid);
110
111         /* Print the LVB: */
112         if (res->res_lvbptr) {
113                 seq_printf(s, "LVB: ");
114                 for (i = 0; i < lvblen; i++) {
115                         if (i == lvblen / 2)
116                                 seq_printf(s, "\n     ");
117                         seq_printf(s, "%02x ",
118                                    (unsigned char) res->res_lvbptr[i]);
119                 }
120                 if (rsb_flag(res, RSB_VALNOTVALID))
121                         seq_printf(s, " (INVALID)");
122                 seq_printf(s, "\n");
123         }
124
125         root_list = !list_empty(&res->res_root_list);
126         recover_list = !list_empty(&res->res_recover_list);
127
128         if (root_list || recover_list) {
129                 seq_printf(s, "Recovery: root %d recover %d flags %lx "
130                            "count %d\n", root_list, recover_list,
131                            res->res_flags, res->res_recover_locks_count);
132         }
133
134         /* Print the locks attached to this resource */
135         seq_printf(s, "Granted Queue\n");
136         list_for_each_entry(lkb, &res->res_grantqueue, lkb_statequeue)
137                 print_resource_lock(s, lkb, res);
138
139         seq_printf(s, "Conversion Queue\n");
140         list_for_each_entry(lkb, &res->res_convertqueue, lkb_statequeue)
141                 print_resource_lock(s, lkb, res);
142
143         seq_printf(s, "Waiting Queue\n");
144         list_for_each_entry(lkb, &res->res_waitqueue, lkb_statequeue)
145                 print_resource_lock(s, lkb, res);
146
147         if (list_empty(&res->res_lookup))
148                 goto out;
149
150         seq_printf(s, "Lookup Queue\n");
151         list_for_each_entry(lkb, &res->res_lookup, lkb_rsb_lookup) {
152                 seq_printf(s, "%08x %s", lkb->lkb_id,
153                            print_lockmode(lkb->lkb_rqmode));
154                 if (lkb->lkb_wait_type)
155                         seq_printf(s, " wait_type: %d", lkb->lkb_wait_type);
156                 seq_printf(s, "\n");
157         }
158  out:
159         unlock_rsb(res);
160         return 0;
161 }
162
163 static void print_lock(struct seq_file *s, struct dlm_lkb *lkb, struct dlm_rsb *r)
164 {
165         unsigned int waiting = 0;
166         uint64_t xid = 0;
167
168         if (lkb->lkb_flags & DLM_IFL_USER) {
169                 if (lkb->lkb_ua)
170                         xid = lkb->lkb_ua->xid;
171         }
172
173         if (lkb->lkb_timestamp)
174                 waiting = jiffies_to_msecs(jiffies - lkb->lkb_timestamp);
175
176         /* id nodeid remid pid xid exflags flags sts grmode rqmode time_ms
177            r_nodeid r_len r_name */
178
179         seq_printf(s, "%x %d %x %u %llu %x %x %d %d %d %u %u %d \"%s\"\n",
180                    lkb->lkb_id,
181                    lkb->lkb_nodeid,
182                    lkb->lkb_remid,
183                    lkb->lkb_ownpid,
184                    (unsigned long long)xid,
185                    lkb->lkb_exflags,
186                    lkb->lkb_flags,
187                    lkb->lkb_status,
188                    lkb->lkb_grmode,
189                    lkb->lkb_rqmode,
190                    waiting,
191                    r->res_nodeid,
192                    r->res_length,
193                    r->res_name);
194 }
195
196 static int print_locks(struct dlm_rsb *r, struct seq_file *s)
197 {
198         struct dlm_lkb *lkb;
199
200         lock_rsb(r);
201
202         list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue)
203                 print_lock(s, lkb, r);
204
205         list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue)
206                 print_lock(s, lkb, r);
207
208         list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue)
209                 print_lock(s, lkb, r);
210
211         unlock_rsb(r);
212         return 0;
213 }
214
215 static int rsb_iter_next(struct rsb_iter *ri)
216 {
217         struct dlm_ls *ls = ri->ls;
218         int i;
219
220         if (!ri->next) {
221  top:
222                 /* Find the next non-empty hash bucket */
223                 for (i = ri->entry; i < ls->ls_rsbtbl_size; i++) {
224                         read_lock(&ls->ls_rsbtbl[i].lock);
225                         if (!list_empty(&ls->ls_rsbtbl[i].list)) {
226                                 ri->next = ls->ls_rsbtbl[i].list.next;
227                                 ri->rsb = list_entry(ri->next, struct dlm_rsb,
228                                                         res_hashchain);
229                                 dlm_hold_rsb(ri->rsb);
230                                 read_unlock(&ls->ls_rsbtbl[i].lock);
231                                 break;
232                         }
233                         read_unlock(&ls->ls_rsbtbl[i].lock);
234                 }
235                 ri->entry = i;
236
237                 if (ri->entry >= ls->ls_rsbtbl_size)
238                         return 1;
239         } else {
240                 struct dlm_rsb *old = ri->rsb;
241                 i = ri->entry;
242                 read_lock(&ls->ls_rsbtbl[i].lock);
243                 ri->next = ri->next->next;
244                 if (ri->next->next == ls->ls_rsbtbl[i].list.next) {
245                         /* End of list - move to next bucket */
246                         ri->next = NULL;
247                         ri->entry++;
248                         read_unlock(&ls->ls_rsbtbl[i].lock);
249                         dlm_put_rsb(old);
250                         goto top;
251                 }
252                 ri->rsb = list_entry(ri->next, struct dlm_rsb, res_hashchain);
253                 dlm_hold_rsb(ri->rsb);
254                 read_unlock(&ls->ls_rsbtbl[i].lock);
255                 dlm_put_rsb(old);
256         }
257
258         return 0;
259 }
260
261 static void rsb_iter_free(struct rsb_iter *ri)
262 {
263         kfree(ri);
264 }
265
266 static struct rsb_iter *rsb_iter_init(struct dlm_ls *ls)
267 {
268         struct rsb_iter *ri;
269
270         ri = kzalloc(sizeof *ri, GFP_KERNEL);
271         if (!ri)
272                 return NULL;
273
274         ri->ls = ls;
275         ri->entry = 0;
276         ri->next = NULL;
277
278         if (rsb_iter_next(ri)) {
279                 rsb_iter_free(ri);
280                 return NULL;
281         }
282
283         return ri;
284 }
285
286 static void *rsb_seq_start(struct seq_file *file, loff_t *pos)
287 {
288         struct rsb_iter *ri;
289         loff_t n = *pos;
290
291         ri = rsb_iter_init(file->private);
292         if (!ri)
293                 return NULL;
294
295         while (n--) {
296                 if (rsb_iter_next(ri)) {
297                         rsb_iter_free(ri);
298                         return NULL;
299                 }
300         }
301
302         return ri;
303 }
304
305 static void *rsb_seq_next(struct seq_file *file, void *iter_ptr, loff_t *pos)
306 {
307         struct rsb_iter *ri = iter_ptr;
308
309         (*pos)++;
310
311         if (rsb_iter_next(ri)) {
312                 rsb_iter_free(ri);
313                 return NULL;
314         }
315
316         return ri;
317 }
318
319 static void rsb_seq_stop(struct seq_file *file, void *iter_ptr)
320 {
321         /* nothing for now */
322 }
323
324 static int rsb_seq_show(struct seq_file *file, void *iter_ptr)
325 {
326         struct rsb_iter *ri = iter_ptr;
327
328         if (ri->locks) {
329                 if (ri->header) {
330                         seq_printf(file, "id nodeid remid pid xid exflags flags "
331                                          "sts grmode rqmode time_ms r_nodeid "
332                                          "r_len r_name\n");
333                         ri->header = 0;
334                 }
335                 print_locks(ri->rsb, file);
336         } else {
337                 print_resource(ri->rsb, file);
338         }
339
340         return 0;
341 }
342
343 static struct seq_operations rsb_seq_ops = {
344         .start = rsb_seq_start,
345         .next  = rsb_seq_next,
346         .stop  = rsb_seq_stop,
347         .show  = rsb_seq_show,
348 };
349
350 static int rsb_open(struct inode *inode, struct file *file)
351 {
352         struct seq_file *seq;
353         int ret;
354
355         ret = seq_open(file, &rsb_seq_ops);
356         if (ret)
357                 return ret;
358
359         seq = file->private_data;
360         seq->private = inode->i_private;
361
362         return 0;
363 }
364
365 static const struct file_operations rsb_fops = {
366         .owner   = THIS_MODULE,
367         .open    = rsb_open,
368         .read    = seq_read,
369         .llseek  = seq_lseek,
370         .release = seq_release
371 };
372
373 /*
374  * Dump state in compact per-lock listing
375  */
376
377 static struct rsb_iter *locks_iter_init(struct dlm_ls *ls, loff_t *pos)
378 {
379         struct rsb_iter *ri;
380
381         ri = kzalloc(sizeof *ri, GFP_KERNEL);
382         if (!ri)
383                 return NULL;
384
385         ri->ls = ls;
386         ri->entry = 0;
387         ri->next = NULL;
388         ri->locks = 1;
389
390         if (*pos == 0)
391                 ri->header = 1;
392
393         if (rsb_iter_next(ri)) {
394                 rsb_iter_free(ri);
395                 return NULL;
396         }
397
398         return ri;
399 }
400
401 static void *locks_seq_start(struct seq_file *file, loff_t *pos)
402 {
403         struct rsb_iter *ri;
404         loff_t n = *pos;
405
406         ri = locks_iter_init(file->private, pos);
407         if (!ri)
408                 return NULL;
409
410         while (n--) {
411                 if (rsb_iter_next(ri)) {
412                         rsb_iter_free(ri);
413                         return NULL;
414                 }
415         }
416
417         return ri;
418 }
419
420 static struct seq_operations locks_seq_ops = {
421         .start = locks_seq_start,
422         .next  = rsb_seq_next,
423         .stop  = rsb_seq_stop,
424         .show  = rsb_seq_show,
425 };
426
427 static int locks_open(struct inode *inode, struct file *file)
428 {
429         struct seq_file *seq;
430         int ret;
431
432         ret = seq_open(file, &locks_seq_ops);
433         if (ret)
434                 return ret;
435
436         seq = file->private_data;
437         seq->private = inode->i_private;
438
439         return 0;
440 }
441
442 static const struct file_operations locks_fops = {
443         .owner   = THIS_MODULE,
444         .open    = locks_open,
445         .read    = seq_read,
446         .llseek  = seq_lseek,
447         .release = seq_release
448 };
449
450 /*
451  * dump lkb's on the ls_waiters list
452  */
453
454 static int waiters_open(struct inode *inode, struct file *file)
455 {
456         file->private_data = inode->i_private;
457         return 0;
458 }
459
460 static ssize_t waiters_read(struct file *file, char __user *userbuf,
461                             size_t count, loff_t *ppos)
462 {
463         struct dlm_ls *ls = file->private_data;
464         struct dlm_lkb *lkb;
465         size_t len = DLM_DEBUG_BUF_LEN, pos = 0, ret, rv;
466
467         mutex_lock(&debug_buf_lock);
468         mutex_lock(&ls->ls_waiters_mutex);
469         memset(debug_buf, 0, sizeof(debug_buf));
470
471         list_for_each_entry(lkb, &ls->ls_waiters, lkb_wait_reply) {
472                 ret = snprintf(debug_buf + pos, len - pos, "%x %d %d %s\n",
473                                lkb->lkb_id, lkb->lkb_wait_type,
474                                lkb->lkb_nodeid, lkb->lkb_resource->res_name);
475                 if (ret >= len - pos)
476                         break;
477                 pos += ret;
478         }
479         mutex_unlock(&ls->ls_waiters_mutex);
480
481         rv = simple_read_from_buffer(userbuf, count, ppos, debug_buf, pos);
482         mutex_unlock(&debug_buf_lock);
483         return rv;
484 }
485
486 static const struct file_operations waiters_fops = {
487         .owner   = THIS_MODULE,
488         .open    = waiters_open,
489         .read    = waiters_read
490 };
491
492 int dlm_create_debug_file(struct dlm_ls *ls)
493 {
494         char name[DLM_LOCKSPACE_LEN+8];
495
496         ls->ls_debug_rsb_dentry = debugfs_create_file(ls->ls_name,
497                                                       S_IFREG | S_IRUGO,
498                                                       dlm_root,
499                                                       ls,
500                                                       &rsb_fops);
501         if (!ls->ls_debug_rsb_dentry)
502                 return -ENOMEM;
503
504         memset(name, 0, sizeof(name));
505         snprintf(name, DLM_LOCKSPACE_LEN+8, "%s_waiters", ls->ls_name);
506
507         ls->ls_debug_waiters_dentry = debugfs_create_file(name,
508                                                           S_IFREG | S_IRUGO,
509                                                           dlm_root,
510                                                           ls,
511                                                           &waiters_fops);
512         if (!ls->ls_debug_waiters_dentry) {
513                 debugfs_remove(ls->ls_debug_rsb_dentry);
514                 return -ENOMEM;
515         }
516
517         memset(name, 0, sizeof(name));
518         snprintf(name, DLM_LOCKSPACE_LEN+8, "%s_locks", ls->ls_name);
519
520         ls->ls_debug_locks_dentry = debugfs_create_file(name,
521                                                         S_IFREG | S_IRUGO,
522                                                         dlm_root,
523                                                         ls,
524                                                         &locks_fops);
525         if (!ls->ls_debug_locks_dentry) {
526                 debugfs_remove(ls->ls_debug_waiters_dentry);
527                 debugfs_remove(ls->ls_debug_rsb_dentry);
528                 return -ENOMEM;
529         }
530
531         return 0;
532 }
533
534 void dlm_delete_debug_file(struct dlm_ls *ls)
535 {
536         if (ls->ls_debug_rsb_dentry)
537                 debugfs_remove(ls->ls_debug_rsb_dentry);
538         if (ls->ls_debug_waiters_dentry)
539                 debugfs_remove(ls->ls_debug_waiters_dentry);
540         if (ls->ls_debug_locks_dentry)
541                 debugfs_remove(ls->ls_debug_locks_dentry);
542 }
543
544 int __init dlm_register_debugfs(void)
545 {
546         mutex_init(&debug_buf_lock);
547         dlm_root = debugfs_create_dir("dlm", NULL);
548         return dlm_root ? 0 : -ENOMEM;
549 }
550
551 void dlm_unregister_debugfs(void)
552 {
553         debugfs_remove(dlm_root);
554 }
555