diff options
-rw-r--r-- | fs/ocfs2/dlm/dlmdebug.c | 247 | ||||
-rw-r--r-- | fs/ocfs2/dlm/dlmdebug.h | 8 |
2 files changed, 255 insertions, 0 deletions
diff --git a/fs/ocfs2/dlm/dlmdebug.c b/fs/ocfs2/dlm/dlmdebug.c index e33540380013..cccb1ce33723 100644 --- a/fs/ocfs2/dlm/dlmdebug.c +++ b/fs/ocfs2/dlm/dlmdebug.c | |||
@@ -273,8 +273,35 @@ EXPORT_SYMBOL_GPL(dlm_errname); | |||
273 | 273 | ||
274 | static struct dentry *dlm_debugfs_root = NULL; | 274 | static struct dentry *dlm_debugfs_root = NULL; |
275 | 275 | ||
276 | /* NOTE: This function converts a lockname into a string. It uses knowledge | ||
277 | * of the format of the lockname that should be outside the purview of the dlm. | ||
278 | * We are adding only to make dlm debugging slightly easier. | ||
279 | * | ||
280 | * For more on lockname formats, please refer to dlmglue.c and ocfs2_lockid.h. | ||
281 | */ | ||
282 | static int stringify_lockname(const char *lockname, int locklen, | ||
283 | char *buf, int len) | ||
284 | { | ||
285 | int out = 0; | ||
286 | __be64 inode_blkno_be; | ||
287 | |||
288 | #define OCFS2_DENTRY_LOCK_INO_START 18 | ||
289 | if (*lockname == 'N') { | ||
290 | memcpy((__be64 *)&inode_blkno_be, | ||
291 | (char *)&lockname[OCFS2_DENTRY_LOCK_INO_START], | ||
292 | sizeof(__be64)); | ||
293 | out += snprintf(buf + out, len - out, "%.*s%08x", | ||
294 | OCFS2_DENTRY_LOCK_INO_START - 1, lockname, | ||
295 | (unsigned int)be64_to_cpu(inode_blkno_be)); | ||
296 | } else | ||
297 | out += snprintf(buf + out, len - out, "%.*s", | ||
298 | locklen, lockname); | ||
299 | return out; | ||
300 | } | ||
301 | |||
276 | #define DLM_DEBUGFS_DIR "o2dlm" | 302 | #define DLM_DEBUGFS_DIR "o2dlm" |
277 | #define DLM_DEBUGFS_DLM_STATE "dlm_state" | 303 | #define DLM_DEBUGFS_DLM_STATE "dlm_state" |
304 | #define DLM_DEBUGFS_LOCKING_STATE "locking_state" | ||
278 | 305 | ||
279 | /* begin - utils funcs */ | 306 | /* begin - utils funcs */ |
280 | static void dlm_debug_free(struct kref *kref) | 307 | static void dlm_debug_free(struct kref *kref) |
@@ -368,6 +395,213 @@ static int debug_buffer_release(struct inode *inode, struct file *file) | |||
368 | } | 395 | } |
369 | /* end - util funcs */ | 396 | /* end - util funcs */ |
370 | 397 | ||
398 | /* begin - debug lockres funcs */ | ||
399 | static int dump_lock(struct dlm_lock *lock, int list_type, char *buf, int len) | ||
400 | { | ||
401 | int out; | ||
402 | |||
403 | #define DEBUG_LOCK_VERSION 1 | ||
404 | spin_lock(&lock->spinlock); | ||
405 | out = snprintf(buf, len, "LOCK:%d,%d,%d,%d,%d,%d:%lld,%d,%d,%d,%d,%d," | ||
406 | "%d,%d,%d,%d\n", | ||
407 | DEBUG_LOCK_VERSION, | ||
408 | list_type, lock->ml.type, lock->ml.convert_type, | ||
409 | lock->ml.node, | ||
410 | dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)), | ||
411 | dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)), | ||
412 | !list_empty(&lock->ast_list), | ||
413 | !list_empty(&lock->bast_list), | ||
414 | lock->ast_pending, lock->bast_pending, | ||
415 | lock->convert_pending, lock->lock_pending, | ||
416 | lock->cancel_pending, lock->unlock_pending, | ||
417 | atomic_read(&lock->lock_refs.refcount)); | ||
418 | spin_unlock(&lock->spinlock); | ||
419 | |||
420 | return out; | ||
421 | } | ||
422 | |||
423 | static int dump_lockres(struct dlm_lock_resource *res, char *buf, int len) | ||
424 | { | ||
425 | struct dlm_lock *lock; | ||
426 | int i; | ||
427 | int out = 0; | ||
428 | |||
429 | out += snprintf(buf + out, len - out, "NAME:"); | ||
430 | out += stringify_lockname(res->lockname.name, res->lockname.len, | ||
431 | buf + out, len - out); | ||
432 | out += snprintf(buf + out, len - out, "\n"); | ||
433 | |||
434 | #define DEBUG_LRES_VERSION 1 | ||
435 | out += snprintf(buf + out, len - out, | ||
436 | "LRES:%d,%d,%d,%ld,%d,%d,%d,%d,%d,%d,%d\n", | ||
437 | DEBUG_LRES_VERSION, | ||
438 | res->owner, res->state, res->last_used, | ||
439 | !list_empty(&res->purge), | ||
440 | !list_empty(&res->dirty), | ||
441 | !list_empty(&res->recovering), | ||
442 | res->inflight_locks, res->migration_pending, | ||
443 | atomic_read(&res->asts_reserved), | ||
444 | atomic_read(&res->refs.refcount)); | ||
445 | |||
446 | /* refmap */ | ||
447 | out += snprintf(buf + out, len - out, "RMAP:"); | ||
448 | out += stringify_nodemap(res->refmap, O2NM_MAX_NODES, | ||
449 | buf + out, len - out); | ||
450 | out += snprintf(buf + out, len - out, "\n"); | ||
451 | |||
452 | /* lvb */ | ||
453 | out += snprintf(buf + out, len - out, "LVBX:"); | ||
454 | for (i = 0; i < DLM_LVB_LEN; i++) | ||
455 | out += snprintf(buf + out, len - out, | ||
456 | "%02x", (unsigned char)res->lvb[i]); | ||
457 | out += snprintf(buf + out, len - out, "\n"); | ||
458 | |||
459 | /* granted */ | ||
460 | list_for_each_entry(lock, &res->granted, list) | ||
461 | out += dump_lock(lock, 0, buf + out, len - out); | ||
462 | |||
463 | /* converting */ | ||
464 | list_for_each_entry(lock, &res->converting, list) | ||
465 | out += dump_lock(lock, 1, buf + out, len - out); | ||
466 | |||
467 | /* blocked */ | ||
468 | list_for_each_entry(lock, &res->blocked, list) | ||
469 | out += dump_lock(lock, 2, buf + out, len - out); | ||
470 | |||
471 | out += snprintf(buf + out, len - out, "\n"); | ||
472 | |||
473 | return out; | ||
474 | } | ||
475 | |||
476 | static void *lockres_seq_start(struct seq_file *m, loff_t *pos) | ||
477 | { | ||
478 | struct debug_lockres *dl = m->private; | ||
479 | struct dlm_ctxt *dlm = dl->dl_ctxt; | ||
480 | struct dlm_lock_resource *res = NULL; | ||
481 | |||
482 | spin_lock(&dlm->spinlock); | ||
483 | |||
484 | if (dl->dl_res) { | ||
485 | list_for_each_entry(res, &dl->dl_res->tracking, tracking) { | ||
486 | if (dl->dl_res) { | ||
487 | dlm_lockres_put(dl->dl_res); | ||
488 | dl->dl_res = NULL; | ||
489 | } | ||
490 | if (&res->tracking == &dlm->tracking_list) { | ||
491 | mlog(0, "End of list found, %p\n", res); | ||
492 | dl = NULL; | ||
493 | break; | ||
494 | } | ||
495 | dlm_lockres_get(res); | ||
496 | dl->dl_res = res; | ||
497 | break; | ||
498 | } | ||
499 | } else { | ||
500 | if (!list_empty(&dlm->tracking_list)) { | ||
501 | list_for_each_entry(res, &dlm->tracking_list, tracking) | ||
502 | break; | ||
503 | dlm_lockres_get(res); | ||
504 | dl->dl_res = res; | ||
505 | } else | ||
506 | dl = NULL; | ||
507 | } | ||
508 | |||
509 | if (dl) { | ||
510 | spin_lock(&dl->dl_res->spinlock); | ||
511 | dump_lockres(dl->dl_res, dl->dl_buf, dl->dl_len - 1); | ||
512 | spin_unlock(&dl->dl_res->spinlock); | ||
513 | } | ||
514 | |||
515 | spin_unlock(&dlm->spinlock); | ||
516 | |||
517 | return dl; | ||
518 | } | ||
519 | |||
520 | static void lockres_seq_stop(struct seq_file *m, void *v) | ||
521 | { | ||
522 | } | ||
523 | |||
524 | static void *lockres_seq_next(struct seq_file *m, void *v, loff_t *pos) | ||
525 | { | ||
526 | return NULL; | ||
527 | } | ||
528 | |||
529 | static int lockres_seq_show(struct seq_file *s, void *v) | ||
530 | { | ||
531 | struct debug_lockres *dl = (struct debug_lockres *)v; | ||
532 | |||
533 | seq_printf(s, "%s", dl->dl_buf); | ||
534 | |||
535 | return 0; | ||
536 | } | ||
537 | |||
538 | static struct seq_operations debug_lockres_ops = { | ||
539 | .start = lockres_seq_start, | ||
540 | .stop = lockres_seq_stop, | ||
541 | .next = lockres_seq_next, | ||
542 | .show = lockres_seq_show, | ||
543 | }; | ||
544 | |||
545 | static int debug_lockres_open(struct inode *inode, struct file *file) | ||
546 | { | ||
547 | struct dlm_ctxt *dlm = inode->i_private; | ||
548 | int ret = -ENOMEM; | ||
549 | struct seq_file *seq; | ||
550 | struct debug_lockres *dl = NULL; | ||
551 | |||
552 | dl = kzalloc(sizeof(struct debug_lockres), GFP_KERNEL); | ||
553 | if (!dl) { | ||
554 | mlog_errno(ret); | ||
555 | goto bail; | ||
556 | } | ||
557 | |||
558 | dl->dl_len = PAGE_SIZE; | ||
559 | dl->dl_buf = kmalloc(dl->dl_len, GFP_KERNEL); | ||
560 | if (!dl->dl_buf) { | ||
561 | mlog_errno(ret); | ||
562 | goto bail; | ||
563 | } | ||
564 | |||
565 | ret = seq_open(file, &debug_lockres_ops); | ||
566 | if (ret) { | ||
567 | mlog_errno(ret); | ||
568 | goto bail; | ||
569 | } | ||
570 | |||
571 | seq = (struct seq_file *) file->private_data; | ||
572 | seq->private = dl; | ||
573 | |||
574 | dlm_grab(dlm); | ||
575 | dl->dl_ctxt = dlm; | ||
576 | |||
577 | return 0; | ||
578 | bail: | ||
579 | if (dl) | ||
580 | kfree(dl->dl_buf); | ||
581 | kfree(dl); | ||
582 | return ret; | ||
583 | } | ||
584 | |||
585 | static int debug_lockres_release(struct inode *inode, struct file *file) | ||
586 | { | ||
587 | struct seq_file *seq = (struct seq_file *)file->private_data; | ||
588 | struct debug_lockres *dl = (struct debug_lockres *)seq->private; | ||
589 | |||
590 | if (dl->dl_res) | ||
591 | dlm_lockres_put(dl->dl_res); | ||
592 | dlm_put(dl->dl_ctxt); | ||
593 | kfree(dl->dl_buf); | ||
594 | return seq_release_private(inode, file); | ||
595 | } | ||
596 | |||
597 | static struct file_operations debug_lockres_fops = { | ||
598 | .open = debug_lockres_open, | ||
599 | .release = debug_lockres_release, | ||
600 | .read = seq_read, | ||
601 | .llseek = seq_lseek, | ||
602 | }; | ||
603 | /* end - debug lockres funcs */ | ||
604 | |||
371 | /* begin - debug state funcs */ | 605 | /* begin - debug state funcs */ |
372 | static int debug_state_print(struct dlm_ctxt *dlm, struct debug_buffer *db) | 606 | static int debug_state_print(struct dlm_ctxt *dlm, struct debug_buffer *db) |
373 | { | 607 | { |
@@ -544,6 +778,17 @@ int dlm_debug_init(struct dlm_ctxt *dlm) | |||
544 | goto bail; | 778 | goto bail; |
545 | } | 779 | } |
546 | 780 | ||
781 | /* for dumping lockres */ | ||
782 | dc->debug_lockres_dentry = | ||
783 | debugfs_create_file(DLM_DEBUGFS_LOCKING_STATE, | ||
784 | S_IFREG|S_IRUSR, | ||
785 | dlm->dlm_debugfs_subroot, | ||
786 | dlm, &debug_lockres_fops); | ||
787 | if (!dc->debug_lockres_dentry) { | ||
788 | mlog_errno(-ENOMEM); | ||
789 | goto bail; | ||
790 | } | ||
791 | |||
547 | dlm_debug_get(dc); | 792 | dlm_debug_get(dc); |
548 | return 0; | 793 | return 0; |
549 | 794 | ||
@@ -557,6 +802,8 @@ void dlm_debug_shutdown(struct dlm_ctxt *dlm) | |||
557 | struct dlm_debug_ctxt *dc = dlm->dlm_debug_ctxt; | 802 | struct dlm_debug_ctxt *dc = dlm->dlm_debug_ctxt; |
558 | 803 | ||
559 | if (dc) { | 804 | if (dc) { |
805 | if (dc->debug_lockres_dentry) | ||
806 | debugfs_remove(dc->debug_lockres_dentry); | ||
560 | if (dc->debug_state_dentry) | 807 | if (dc->debug_state_dentry) |
561 | debugfs_remove(dc->debug_state_dentry); | 808 | debugfs_remove(dc->debug_state_dentry); |
562 | dlm_debug_put(dc); | 809 | dlm_debug_put(dc); |
diff --git a/fs/ocfs2/dlm/dlmdebug.h b/fs/ocfs2/dlm/dlmdebug.h index 94cc10a4e19c..7c5b2b0a05ed 100644 --- a/fs/ocfs2/dlm/dlmdebug.h +++ b/fs/ocfs2/dlm/dlmdebug.h | |||
@@ -30,6 +30,7 @@ | |||
30 | struct dlm_debug_ctxt { | 30 | struct dlm_debug_ctxt { |
31 | struct kref debug_refcnt; | 31 | struct kref debug_refcnt; |
32 | struct dentry *debug_state_dentry; | 32 | struct dentry *debug_state_dentry; |
33 | struct dentry *debug_lockres_dentry; | ||
33 | }; | 34 | }; |
34 | 35 | ||
35 | struct debug_buffer { | 36 | struct debug_buffer { |
@@ -37,6 +38,13 @@ struct debug_buffer { | |||
37 | char *buf; | 38 | char *buf; |
38 | }; | 39 | }; |
39 | 40 | ||
41 | struct debug_lockres { | ||
42 | int dl_len; | ||
43 | char *dl_buf; | ||
44 | struct dlm_ctxt *dl_ctxt; | ||
45 | struct dlm_lock_resource *dl_res; | ||
46 | }; | ||
47 | |||
40 | int dlm_debug_init(struct dlm_ctxt *dlm); | 48 | int dlm_debug_init(struct dlm_ctxt *dlm); |
41 | void dlm_debug_shutdown(struct dlm_ctxt *dlm); | 49 | void dlm_debug_shutdown(struct dlm_ctxt *dlm); |
42 | 50 | ||