diff options
author | David Teigland <teigland@redhat.com> | 2008-12-16 15:53:23 -0500 |
---|---|---|
committer | David Teigland <teigland@redhat.com> | 2008-12-23 11:18:51 -0500 |
commit | d022509d1c54be4918e7fc8f1195ee8c392e9a57 (patch) | |
tree | be27db04228d30674c21f6b550b78c5fb4bd2672 /fs/dlm/debug_fs.c | |
parent | e3a84ad495d1fddb542e0922160f0194a1361950 (diff) |
dlm: add new debugfs entry
The new debugfs entry dumps all rsb and lkb structures, and includes
a lot more information than has been available before. This includes
the new timestamps added by a previous patch for debugging callback
issues.
Signed-off-by: David Teigland <teigland@redhat.com>
Diffstat (limited to 'fs/dlm/debug_fs.c')
-rw-r--r-- | fs/dlm/debug_fs.c | 296 |
1 files changed, 246 insertions, 50 deletions
diff --git a/fs/dlm/debug_fs.c b/fs/dlm/debug_fs.c index 19e4f9eb44e1..2f107d1a6a45 100644 --- a/fs/dlm/debug_fs.c +++ b/fs/dlm/debug_fs.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | ******************************************************************************* | 2 | ******************************************************************************* |
3 | ** | 3 | ** |
4 | ** Copyright (C) 2005 Red Hat, Inc. All rights reserved. | 4 | ** Copyright (C) 2005-2008 Red Hat, Inc. All rights reserved. |
5 | ** | 5 | ** |
6 | ** This copyrighted material is made available to anyone wishing to use, | 6 | ** This copyrighted material is made available to anyone wishing to use, |
7 | ** modify, copy, or redistribute it subject to the terms and conditions | 7 | ** modify, copy, or redistribute it subject to the terms and conditions |
@@ -27,7 +27,7 @@ static struct dentry *dlm_root; | |||
27 | 27 | ||
28 | struct rsb_iter { | 28 | struct rsb_iter { |
29 | int entry; | 29 | int entry; |
30 | int locks; | 30 | int format; |
31 | int header; | 31 | int header; |
32 | struct dlm_ls *ls; | 32 | struct dlm_ls *ls; |
33 | struct list_head *next; | 33 | struct list_head *next; |
@@ -60,8 +60,8 @@ static char *print_lockmode(int mode) | |||
60 | } | 60 | } |
61 | } | 61 | } |
62 | 62 | ||
63 | static void print_resource_lock(struct seq_file *s, struct dlm_lkb *lkb, | 63 | static void print_format1_lock(struct seq_file *s, struct dlm_lkb *lkb, |
64 | struct dlm_rsb *res) | 64 | struct dlm_rsb *res) |
65 | { | 65 | { |
66 | seq_printf(s, "%08x %s", lkb->lkb_id, print_lockmode(lkb->lkb_grmode)); | 66 | seq_printf(s, "%08x %s", lkb->lkb_id, print_lockmode(lkb->lkb_grmode)); |
67 | 67 | ||
@@ -83,7 +83,7 @@ static void print_resource_lock(struct seq_file *s, struct dlm_lkb *lkb, | |||
83 | seq_printf(s, "\n"); | 83 | seq_printf(s, "\n"); |
84 | } | 84 | } |
85 | 85 | ||
86 | static int print_resource(struct dlm_rsb *res, struct seq_file *s) | 86 | static int print_format1(struct dlm_rsb *res, struct seq_file *s) |
87 | { | 87 | { |
88 | struct dlm_lkb *lkb; | 88 | struct dlm_lkb *lkb; |
89 | int i, lvblen = res->res_ls->ls_lvblen, recover_list, root_list; | 89 | int i, lvblen = res->res_ls->ls_lvblen, recover_list, root_list; |
@@ -134,15 +134,15 @@ static int print_resource(struct dlm_rsb *res, struct seq_file *s) | |||
134 | /* Print the locks attached to this resource */ | 134 | /* Print the locks attached to this resource */ |
135 | seq_printf(s, "Granted Queue\n"); | 135 | seq_printf(s, "Granted Queue\n"); |
136 | list_for_each_entry(lkb, &res->res_grantqueue, lkb_statequeue) | 136 | list_for_each_entry(lkb, &res->res_grantqueue, lkb_statequeue) |
137 | print_resource_lock(s, lkb, res); | 137 | print_format1_lock(s, lkb, res); |
138 | 138 | ||
139 | seq_printf(s, "Conversion Queue\n"); | 139 | seq_printf(s, "Conversion Queue\n"); |
140 | list_for_each_entry(lkb, &res->res_convertqueue, lkb_statequeue) | 140 | list_for_each_entry(lkb, &res->res_convertqueue, lkb_statequeue) |
141 | print_resource_lock(s, lkb, res); | 141 | print_format1_lock(s, lkb, res); |
142 | 142 | ||
143 | seq_printf(s, "Waiting Queue\n"); | 143 | seq_printf(s, "Waiting Queue\n"); |
144 | list_for_each_entry(lkb, &res->res_waitqueue, lkb_statequeue) | 144 | list_for_each_entry(lkb, &res->res_waitqueue, lkb_statequeue) |
145 | print_resource_lock(s, lkb, res); | 145 | print_format1_lock(s, lkb, res); |
146 | 146 | ||
147 | if (list_empty(&res->res_lookup)) | 147 | if (list_empty(&res->res_lookup)) |
148 | goto out; | 148 | goto out; |
@@ -160,7 +160,8 @@ static int print_resource(struct dlm_rsb *res, struct seq_file *s) | |||
160 | return 0; | 160 | return 0; |
161 | } | 161 | } |
162 | 162 | ||
163 | static void print_lock(struct seq_file *s, struct dlm_lkb *lkb, struct dlm_rsb *r) | 163 | static void print_format2_lock(struct seq_file *s, struct dlm_lkb *lkb, |
164 | struct dlm_rsb *r) | ||
164 | { | 165 | { |
165 | u64 xid = 0; | 166 | u64 xid = 0; |
166 | u64 us; | 167 | u64 us; |
@@ -193,20 +194,108 @@ static void print_lock(struct seq_file *s, struct dlm_lkb *lkb, struct dlm_rsb * | |||
193 | r->res_name); | 194 | r->res_name); |
194 | } | 195 | } |
195 | 196 | ||
196 | static int print_locks(struct dlm_rsb *r, struct seq_file *s) | 197 | static int print_format2(struct dlm_rsb *r, struct seq_file *s) |
197 | { | 198 | { |
198 | struct dlm_lkb *lkb; | 199 | struct dlm_lkb *lkb; |
199 | 200 | ||
200 | lock_rsb(r); | 201 | lock_rsb(r); |
201 | 202 | ||
202 | list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) | 203 | list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) |
203 | print_lock(s, lkb, r); | 204 | print_format2_lock(s, lkb, r); |
204 | 205 | ||
205 | list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) | 206 | list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) |
206 | print_lock(s, lkb, r); | 207 | print_format2_lock(s, lkb, r); |
207 | 208 | ||
208 | list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue) | 209 | list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue) |
209 | print_lock(s, lkb, r); | 210 | print_format2_lock(s, lkb, r); |
211 | |||
212 | unlock_rsb(r); | ||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | static void print_format3_lock(struct seq_file *s, struct dlm_lkb *lkb, | ||
217 | int rsb_lookup) | ||
218 | { | ||
219 | u64 xid = 0; | ||
220 | |||
221 | if (lkb->lkb_flags & DLM_IFL_USER) { | ||
222 | if (lkb->lkb_ua) | ||
223 | xid = lkb->lkb_ua->xid; | ||
224 | } | ||
225 | |||
226 | seq_printf(s, "lkb %x %d %x %u %llu %x %x %d %d %d %d %d %d %u %llu %llu\n", | ||
227 | lkb->lkb_id, | ||
228 | lkb->lkb_nodeid, | ||
229 | lkb->lkb_remid, | ||
230 | lkb->lkb_ownpid, | ||
231 | (unsigned long long)xid, | ||
232 | lkb->lkb_exflags, | ||
233 | lkb->lkb_flags, | ||
234 | lkb->lkb_status, | ||
235 | lkb->lkb_grmode, | ||
236 | lkb->lkb_rqmode, | ||
237 | lkb->lkb_highbast, | ||
238 | rsb_lookup, | ||
239 | lkb->lkb_wait_type, | ||
240 | lkb->lkb_lvbseq, | ||
241 | (unsigned long long)ktime_to_ns(lkb->lkb_timestamp), | ||
242 | (unsigned long long)ktime_to_ns(lkb->lkb_time_bast)); | ||
243 | } | ||
244 | |||
245 | static int print_format3(struct dlm_rsb *r, struct seq_file *s) | ||
246 | { | ||
247 | struct dlm_lkb *lkb; | ||
248 | int i, lvblen = r->res_ls->ls_lvblen; | ||
249 | int print_name = 1; | ||
250 | |||
251 | lock_rsb(r); | ||
252 | |||
253 | seq_printf(s, "rsb %p %d %x %lx %d %d %u %d ", | ||
254 | r, | ||
255 | r->res_nodeid, | ||
256 | r->res_first_lkid, | ||
257 | r->res_flags, | ||
258 | !list_empty(&r->res_root_list), | ||
259 | !list_empty(&r->res_recover_list), | ||
260 | r->res_recover_locks_count, | ||
261 | r->res_length); | ||
262 | |||
263 | for (i = 0; i < r->res_length; i++) { | ||
264 | if (!isascii(r->res_name[i]) || !isprint(r->res_name[i])) | ||
265 | print_name = 0; | ||
266 | } | ||
267 | |||
268 | seq_printf(s, "%s", print_name ? "str " : "hex"); | ||
269 | |||
270 | for (i = 0; i < r->res_length; i++) { | ||
271 | if (print_name) | ||
272 | seq_printf(s, "%c", r->res_name[i]); | ||
273 | else | ||
274 | seq_printf(s, " %02x", (unsigned char)r->res_name[i]); | ||
275 | } | ||
276 | seq_printf(s, "\n"); | ||
277 | |||
278 | if (!r->res_lvbptr) | ||
279 | goto do_locks; | ||
280 | |||
281 | seq_printf(s, "lvb %u %d", r->res_lvbseq, lvblen); | ||
282 | |||
283 | for (i = 0; i < lvblen; i++) | ||
284 | seq_printf(s, " %02x", (unsigned char)r->res_lvbptr[i]); | ||
285 | seq_printf(s, "\n"); | ||
286 | |||
287 | do_locks: | ||
288 | list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) | ||
289 | print_format3_lock(s, lkb, 0); | ||
290 | |||
291 | list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) | ||
292 | print_format3_lock(s, lkb, 0); | ||
293 | |||
294 | list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue) | ||
295 | print_format3_lock(s, lkb, 0); | ||
296 | |||
297 | list_for_each_entry(lkb, &r->res_lookup, lkb_rsb_lookup) | ||
298 | print_format3_lock(s, lkb, 1); | ||
210 | 299 | ||
211 | unlock_rsb(r); | 300 | unlock_rsb(r); |
212 | return 0; | 301 | return 0; |
@@ -231,7 +320,7 @@ static int rsb_iter_next(struct rsb_iter *ri) | |||
231 | break; | 320 | break; |
232 | } | 321 | } |
233 | read_unlock(&ls->ls_rsbtbl[i].lock); | 322 | read_unlock(&ls->ls_rsbtbl[i].lock); |
234 | } | 323 | } |
235 | ri->entry = i; | 324 | ri->entry = i; |
236 | 325 | ||
237 | if (ri->entry >= ls->ls_rsbtbl_size) | 326 | if (ri->entry >= ls->ls_rsbtbl_size) |
@@ -248,7 +337,7 @@ static int rsb_iter_next(struct rsb_iter *ri) | |||
248 | read_unlock(&ls->ls_rsbtbl[i].lock); | 337 | read_unlock(&ls->ls_rsbtbl[i].lock); |
249 | dlm_put_rsb(old); | 338 | dlm_put_rsb(old); |
250 | goto top; | 339 | goto top; |
251 | } | 340 | } |
252 | ri->rsb = list_entry(ri->next, struct dlm_rsb, res_hashchain); | 341 | ri->rsb = list_entry(ri->next, struct dlm_rsb, res_hashchain); |
253 | dlm_hold_rsb(ri->rsb); | 342 | dlm_hold_rsb(ri->rsb); |
254 | read_unlock(&ls->ls_rsbtbl[i].lock); | 343 | read_unlock(&ls->ls_rsbtbl[i].lock); |
@@ -274,6 +363,7 @@ static struct rsb_iter *rsb_iter_init(struct dlm_ls *ls) | |||
274 | ri->ls = ls; | 363 | ri->ls = ls; |
275 | ri->entry = 0; | 364 | ri->entry = 0; |
276 | ri->next = NULL; | 365 | ri->next = NULL; |
366 | ri->format = 1; | ||
277 | 367 | ||
278 | if (rsb_iter_next(ri)) { | 368 | if (rsb_iter_next(ri)) { |
279 | rsb_iter_free(ri); | 369 | rsb_iter_free(ri); |
@@ -325,16 +415,26 @@ static int rsb_seq_show(struct seq_file *file, void *iter_ptr) | |||
325 | { | 415 | { |
326 | struct rsb_iter *ri = iter_ptr; | 416 | struct rsb_iter *ri = iter_ptr; |
327 | 417 | ||
328 | if (ri->locks) { | 418 | switch (ri->format) { |
419 | case 1: | ||
420 | print_format1(ri->rsb, file); | ||
421 | break; | ||
422 | case 2: | ||
329 | if (ri->header) { | 423 | if (ri->header) { |
330 | seq_printf(file, "id nodeid remid pid xid exflags flags " | 424 | seq_printf(file, "id nodeid remid pid xid exflags " |
331 | "sts grmode rqmode time_ms r_nodeid " | 425 | "flags sts grmode rqmode time_ms " |
332 | "r_len r_name\n"); | 426 | "r_nodeid r_len r_name\n"); |
333 | ri->header = 0; | 427 | ri->header = 0; |
334 | } | 428 | } |
335 | print_locks(ri->rsb, file); | 429 | print_format2(ri->rsb, file); |
336 | } else { | 430 | break; |
337 | print_resource(ri->rsb, file); | 431 | case 3: |
432 | if (ri->header) { | ||
433 | seq_printf(file, "version rsb 1.1 lvb 1.1 lkb 1.1\n"); | ||
434 | ri->header = 0; | ||
435 | } | ||
436 | print_format3(ri->rsb, file); | ||
437 | break; | ||
338 | } | 438 | } |
339 | 439 | ||
340 | return 0; | 440 | return 0; |
@@ -385,7 +485,7 @@ static struct rsb_iter *locks_iter_init(struct dlm_ls *ls, loff_t *pos) | |||
385 | ri->ls = ls; | 485 | ri->ls = ls; |
386 | ri->entry = 0; | 486 | ri->entry = 0; |
387 | ri->next = NULL; | 487 | ri->next = NULL; |
388 | ri->locks = 1; | 488 | ri->format = 2; |
389 | 489 | ||
390 | if (*pos == 0) | 490 | if (*pos == 0) |
391 | ri->header = 1; | 491 | ri->header = 1; |
@@ -448,6 +548,84 @@ static const struct file_operations locks_fops = { | |||
448 | }; | 548 | }; |
449 | 549 | ||
450 | /* | 550 | /* |
551 | * Dump all rsb/lvb/lkb state in compact listing, more complete than _locks | ||
552 | * This can replace both formats 1 and 2 eventually. | ||
553 | */ | ||
554 | |||
555 | static struct rsb_iter *all_iter_init(struct dlm_ls *ls, loff_t *pos) | ||
556 | { | ||
557 | struct rsb_iter *ri; | ||
558 | |||
559 | ri = kzalloc(sizeof *ri, GFP_KERNEL); | ||
560 | if (!ri) | ||
561 | return NULL; | ||
562 | |||
563 | ri->ls = ls; | ||
564 | ri->entry = 0; | ||
565 | ri->next = NULL; | ||
566 | ri->format = 3; | ||
567 | |||
568 | if (*pos == 0) | ||
569 | ri->header = 1; | ||
570 | |||
571 | if (rsb_iter_next(ri)) { | ||
572 | rsb_iter_free(ri); | ||
573 | return NULL; | ||
574 | } | ||
575 | |||
576 | return ri; | ||
577 | } | ||
578 | |||
579 | static void *all_seq_start(struct seq_file *file, loff_t *pos) | ||
580 | { | ||
581 | struct rsb_iter *ri; | ||
582 | loff_t n = *pos; | ||
583 | |||
584 | ri = all_iter_init(file->private, pos); | ||
585 | if (!ri) | ||
586 | return NULL; | ||
587 | |||
588 | while (n--) { | ||
589 | if (rsb_iter_next(ri)) { | ||
590 | rsb_iter_free(ri); | ||
591 | return NULL; | ||
592 | } | ||
593 | } | ||
594 | |||
595 | return ri; | ||
596 | } | ||
597 | |||
598 | static struct seq_operations all_seq_ops = { | ||
599 | .start = all_seq_start, | ||
600 | .next = rsb_seq_next, | ||
601 | .stop = rsb_seq_stop, | ||
602 | .show = rsb_seq_show, | ||
603 | }; | ||
604 | |||
605 | static int all_open(struct inode *inode, struct file *file) | ||
606 | { | ||
607 | struct seq_file *seq; | ||
608 | int ret; | ||
609 | |||
610 | ret = seq_open(file, &all_seq_ops); | ||
611 | if (ret) | ||
612 | return ret; | ||
613 | |||
614 | seq = file->private_data; | ||
615 | seq->private = inode->i_private; | ||
616 | |||
617 | return 0; | ||
618 | } | ||
619 | |||
620 | static const struct file_operations all_fops = { | ||
621 | .owner = THIS_MODULE, | ||
622 | .open = all_open, | ||
623 | .read = seq_read, | ||
624 | .llseek = seq_lseek, | ||
625 | .release = seq_release | ||
626 | }; | ||
627 | |||
628 | /* | ||
451 | * dump lkb's on the ls_waiters list | 629 | * dump lkb's on the ls_waiters list |
452 | */ | 630 | */ |
453 | 631 | ||
@@ -489,30 +667,33 @@ static const struct file_operations waiters_fops = { | |||
489 | .read = waiters_read | 667 | .read = waiters_read |
490 | }; | 668 | }; |
491 | 669 | ||
670 | void dlm_delete_debug_file(struct dlm_ls *ls) | ||
671 | { | ||
672 | if (ls->ls_debug_rsb_dentry) | ||
673 | debugfs_remove(ls->ls_debug_rsb_dentry); | ||
674 | if (ls->ls_debug_waiters_dentry) | ||
675 | debugfs_remove(ls->ls_debug_waiters_dentry); | ||
676 | if (ls->ls_debug_locks_dentry) | ||
677 | debugfs_remove(ls->ls_debug_locks_dentry); | ||
678 | if (ls->ls_debug_all_dentry) | ||
679 | debugfs_remove(ls->ls_debug_all_dentry); | ||
680 | } | ||
681 | |||
492 | int dlm_create_debug_file(struct dlm_ls *ls) | 682 | int dlm_create_debug_file(struct dlm_ls *ls) |
493 | { | 683 | { |
494 | char name[DLM_LOCKSPACE_LEN+8]; | 684 | char name[DLM_LOCKSPACE_LEN+8]; |
495 | 685 | ||
686 | /* format 1 */ | ||
687 | |||
496 | ls->ls_debug_rsb_dentry = debugfs_create_file(ls->ls_name, | 688 | ls->ls_debug_rsb_dentry = debugfs_create_file(ls->ls_name, |
497 | S_IFREG | S_IRUGO, | 689 | S_IFREG | S_IRUGO, |
498 | dlm_root, | 690 | dlm_root, |
499 | ls, | 691 | ls, |
500 | &rsb_fops); | 692 | &rsb_fops); |
501 | if (!ls->ls_debug_rsb_dentry) | 693 | if (!ls->ls_debug_rsb_dentry) |
502 | return -ENOMEM; | 694 | goto fail; |
503 | 695 | ||
504 | memset(name, 0, sizeof(name)); | 696 | /* format 2 */ |
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 | 697 | ||
517 | memset(name, 0, sizeof(name)); | 698 | memset(name, 0, sizeof(name)); |
518 | snprintf(name, DLM_LOCKSPACE_LEN+8, "%s_locks", ls->ls_name); | 699 | snprintf(name, DLM_LOCKSPACE_LEN+8, "%s_locks", ls->ls_name); |
@@ -522,23 +703,38 @@ int dlm_create_debug_file(struct dlm_ls *ls) | |||
522 | dlm_root, | 703 | dlm_root, |
523 | ls, | 704 | ls, |
524 | &locks_fops); | 705 | &locks_fops); |
525 | if (!ls->ls_debug_locks_dentry) { | 706 | if (!ls->ls_debug_locks_dentry) |
526 | debugfs_remove(ls->ls_debug_waiters_dentry); | 707 | goto fail; |
527 | debugfs_remove(ls->ls_debug_rsb_dentry); | 708 | |
528 | return -ENOMEM; | 709 | /* format 3 */ |
529 | } | 710 | |
711 | memset(name, 0, sizeof(name)); | ||
712 | snprintf(name, DLM_LOCKSPACE_LEN+8, "%s_all", ls->ls_name); | ||
713 | |||
714 | ls->ls_debug_all_dentry = debugfs_create_file(name, | ||
715 | S_IFREG | S_IRUGO, | ||
716 | dlm_root, | ||
717 | ls, | ||
718 | &all_fops); | ||
719 | if (!ls->ls_debug_all_dentry) | ||
720 | goto fail; | ||
721 | |||
722 | memset(name, 0, sizeof(name)); | ||
723 | snprintf(name, DLM_LOCKSPACE_LEN+8, "%s_waiters", ls->ls_name); | ||
724 | |||
725 | ls->ls_debug_waiters_dentry = debugfs_create_file(name, | ||
726 | S_IFREG | S_IRUGO, | ||
727 | dlm_root, | ||
728 | ls, | ||
729 | &waiters_fops); | ||
730 | if (!ls->ls_debug_waiters_dentry) | ||
731 | goto fail; | ||
530 | 732 | ||
531 | return 0; | 733 | return 0; |
532 | } | ||
533 | 734 | ||
534 | void dlm_delete_debug_file(struct dlm_ls *ls) | 735 | fail: |
535 | { | 736 | dlm_delete_debug_file(ls); |
536 | if (ls->ls_debug_rsb_dentry) | 737 | return -ENOMEM; |
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 | } | 738 | } |
543 | 739 | ||
544 | int __init dlm_register_debugfs(void) | 740 | int __init dlm_register_debugfs(void) |