diff options
| author | Lars Ellenberg <lars.ellenberg@linbit.com> | 2014-05-08 07:39:35 -0400 |
|---|---|---|
| committer | Philipp Reisner <philipp.reisner@linbit.com> | 2014-07-10 12:35:19 -0400 |
| commit | 54e6fc38e888a54b016e1e04e1eceea78ddf7ace (patch) | |
| tree | b4908bb91f765a1f117df38379ff37cbcf8b451c /drivers/block/drbd | |
| parent | 944410e97cfcec38369eeb5f77d0e8da91d68afb (diff) | |
drbd: debugfs: add per volume oldest_requests
Show oldest requests
* pending master bio completion and,
* if different, local disk bio completion.
Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
Diffstat (limited to 'drivers/block/drbd')
| -rw-r--r-- | drivers/block/drbd/drbd_debugfs.c | 153 |
1 files changed, 148 insertions, 5 deletions
diff --git a/drivers/block/drbd/drbd_debugfs.c b/drivers/block/drbd/drbd_debugfs.c index 230d9e1fc85c..45b52056f88d 100644 --- a/drivers/block/drbd/drbd_debugfs.c +++ b/drivers/block/drbd/drbd_debugfs.c | |||
| @@ -434,12 +434,10 @@ static int drbd_single_open(struct file *file, int (*show)(struct seq_file *, vo | |||
| 434 | goto out; | 434 | goto out; |
| 435 | /* serialize with d_delete() */ | 435 | /* serialize with d_delete() */ |
| 436 | mutex_lock(&parent->d_inode->i_mutex); | 436 | mutex_lock(&parent->d_inode->i_mutex); |
| 437 | if (!debugfs_positive(file->f_dentry)) | ||
| 438 | goto out_unlock; | ||
| 439 | /* Make sure the object is still alive */ | 437 | /* Make sure the object is still alive */ |
| 440 | if (kref_get_unless_zero(kref)) | 438 | if (debugfs_positive(file->f_dentry) |
| 439 | && kref_get_unless_zero(kref)) | ||
| 441 | ret = 0; | 440 | ret = 0; |
| 442 | out_unlock: | ||
| 443 | mutex_unlock(&parent->d_inode->i_mutex); | 441 | mutex_unlock(&parent->d_inode->i_mutex); |
| 444 | if (!ret) { | 442 | if (!ret) { |
| 445 | ret = single_open(file, show, data); | 443 | ret = single_open(file, show, data); |
| @@ -592,6 +590,53 @@ static const struct file_operations connection_callback_history_fops = { | |||
| 592 | .release = callback_history_release, | 590 | .release = callback_history_release, |
| 593 | }; | 591 | }; |
| 594 | 592 | ||
| 593 | static int connection_oldest_requests_show(struct seq_file *m, void *ignored) | ||
| 594 | { | ||
| 595 | struct drbd_connection *connection = m->private; | ||
| 596 | unsigned long now = jiffies; | ||
| 597 | struct drbd_request *r1, *r2; | ||
| 598 | |||
| 599 | /* BUMP me if you change the file format/content/presentation */ | ||
| 600 | seq_printf(m, "v: %u\n\n", 0); | ||
| 601 | |||
| 602 | spin_lock_irq(&connection->resource->req_lock); | ||
| 603 | r1 = connection->req_next; | ||
| 604 | if (r1) | ||
| 605 | seq_print_minor_vnr_req(m, r1, now); | ||
| 606 | r2 = connection->req_ack_pending; | ||
| 607 | if (r2 && r2 != r1) { | ||
| 608 | r1 = r2; | ||
| 609 | seq_print_minor_vnr_req(m, r1, now); | ||
| 610 | } | ||
| 611 | r2 = connection->req_not_net_done; | ||
| 612 | if (r2 && r2 != r1) | ||
| 613 | seq_print_minor_vnr_req(m, r2, now); | ||
| 614 | spin_unlock_irq(&connection->resource->req_lock); | ||
| 615 | return 0; | ||
| 616 | } | ||
| 617 | |||
| 618 | static int connection_oldest_requests_open(struct inode *inode, struct file *file) | ||
| 619 | { | ||
| 620 | struct drbd_connection *connection = inode->i_private; | ||
| 621 | return drbd_single_open(file, connection_oldest_requests_show, connection, | ||
| 622 | &connection->kref, drbd_destroy_connection); | ||
| 623 | } | ||
| 624 | |||
| 625 | static int connection_oldest_requests_release(struct inode *inode, struct file *file) | ||
| 626 | { | ||
| 627 | struct drbd_connection *connection = inode->i_private; | ||
| 628 | kref_put(&connection->kref, drbd_destroy_connection); | ||
| 629 | return single_release(inode, file); | ||
| 630 | } | ||
| 631 | |||
| 632 | static const struct file_operations connection_oldest_requests_fops = { | ||
| 633 | .owner = THIS_MODULE, | ||
| 634 | .open = connection_oldest_requests_open, | ||
| 635 | .read = seq_read, | ||
| 636 | .llseek = seq_lseek, | ||
| 637 | .release = connection_oldest_requests_release, | ||
| 638 | }; | ||
| 639 | |||
| 595 | void drbd_debugfs_connection_add(struct drbd_connection *connection) | 640 | void drbd_debugfs_connection_add(struct drbd_connection *connection) |
| 596 | { | 641 | { |
| 597 | struct dentry *conns_dir = connection->resource->debugfs_res_connections; | 642 | struct dentry *conns_dir = connection->resource->debugfs_res_connections; |
| @@ -627,6 +672,89 @@ void drbd_debugfs_connection_cleanup(struct drbd_connection *connection) | |||
| 627 | drbd_debugfs_remove(&connection->debugfs_conn); | 672 | drbd_debugfs_remove(&connection->debugfs_conn); |
| 628 | } | 673 | } |
| 629 | 674 | ||
| 675 | static void resync_dump_detail(struct seq_file *m, struct lc_element *e) | ||
| 676 | { | ||
| 677 | struct bm_extent *bme = lc_entry(e, struct bm_extent, lce); | ||
| 678 | |||
| 679 | seq_printf(m, "%5d %s %s %s\n", bme->rs_left, | ||
| 680 | test_bit(BME_NO_WRITES, &bme->flags) ? "NO_WRITES" : "---------", | ||
| 681 | test_bit(BME_LOCKED, &bme->flags) ? "LOCKED" : "------", | ||
| 682 | test_bit(BME_PRIORITY, &bme->flags) ? "PRIORITY" : "--------" | ||
| 683 | ); | ||
| 684 | } | ||
| 685 | |||
| 686 | static int device_resync_extents_show(struct seq_file *m, void *ignored) | ||
| 687 | { | ||
| 688 | struct drbd_device *device = m->private; | ||
| 689 | if (get_ldev_if_state(device, D_FAILED)) { | ||
| 690 | lc_seq_printf_stats(m, device->resync); | ||
| 691 | lc_seq_dump_details(m, device->resync, "rs_left flags", resync_dump_detail); | ||
| 692 | put_ldev(device); | ||
| 693 | } | ||
| 694 | return 0; | ||
| 695 | } | ||
| 696 | |||
| 697 | static int device_act_log_extents_show(struct seq_file *m, void *ignored) | ||
| 698 | { | ||
| 699 | struct drbd_device *device = m->private; | ||
| 700 | if (get_ldev_if_state(device, D_FAILED)) { | ||
| 701 | lc_seq_printf_stats(m, device->act_log); | ||
| 702 | lc_seq_dump_details(m, device->act_log, "", NULL); | ||
| 703 | put_ldev(device); | ||
| 704 | } | ||
| 705 | return 0; | ||
| 706 | } | ||
| 707 | |||
| 708 | static int device_oldest_requests_show(struct seq_file *m, void *ignored) | ||
| 709 | { | ||
| 710 | struct drbd_device *device = m->private; | ||
| 711 | struct drbd_resource *resource = device->resource; | ||
| 712 | unsigned long now = jiffies; | ||
| 713 | struct drbd_request *r1, *r2; | ||
| 714 | int i; | ||
| 715 | |||
| 716 | seq_puts(m, RQ_HDR); | ||
| 717 | spin_lock_irq(&resource->req_lock); | ||
| 718 | /* WRITE, then READ */ | ||
| 719 | for (i = 1; i >= 0; --i) { | ||
| 720 | r1 = list_first_entry_or_null(&device->pending_master_completion[i], | ||
| 721 | struct drbd_request, req_pending_master_completion); | ||
| 722 | r2 = list_first_entry_or_null(&device->pending_completion[i], | ||
| 723 | struct drbd_request, req_pending_local); | ||
| 724 | if (r1) | ||
| 725 | seq_print_one_request(m, r1, now); | ||
| 726 | if (r2 && r2 != r1) | ||
| 727 | seq_print_one_request(m, r2, now); | ||
| 728 | } | ||
| 729 | spin_unlock_irq(&resource->req_lock); | ||
| 730 | return 0; | ||
| 731 | } | ||
| 732 | |||
| 733 | #define drbd_debugfs_device_attr(name) \ | ||
| 734 | static int device_ ## name ## _open(struct inode *inode, struct file *file) \ | ||
| 735 | { \ | ||
| 736 | struct drbd_device *device = inode->i_private; \ | ||
| 737 | return drbd_single_open(file, device_ ## name ## _show, device, \ | ||
| 738 | &device->kref, drbd_destroy_device); \ | ||
| 739 | } \ | ||
| 740 | static int device_ ## name ## _release(struct inode *inode, struct file *file) \ | ||
| 741 | { \ | ||
| 742 | struct drbd_device *device = inode->i_private; \ | ||
| 743 | kref_put(&device->kref, drbd_destroy_device); \ | ||
| 744 | return single_release(inode, file); \ | ||
| 745 | } \ | ||
| 746 | static const struct file_operations device_ ## name ## _fops = { \ | ||
| 747 | .owner = THIS_MODULE, \ | ||
| 748 | .open = device_ ## name ## _open, \ | ||
| 749 | .read = seq_read, \ | ||
| 750 | .llseek = seq_lseek, \ | ||
| 751 | .release = device_ ## name ## _release, \ | ||
| 752 | }; | ||
| 753 | |||
| 754 | drbd_debugfs_device_attr(oldest_requests) | ||
| 755 | drbd_debugfs_device_attr(act_log_extents) | ||
| 756 | drbd_debugfs_device_attr(resync_extents) | ||
| 757 | |||
| 630 | void drbd_debugfs_device_add(struct drbd_device *device) | 758 | void drbd_debugfs_device_add(struct drbd_device *device) |
| 631 | { | 759 | { |
| 632 | struct dentry *vols_dir = device->resource->debugfs_res_volumes; | 760 | struct dentry *vols_dir = device->resource->debugfs_res_volumes; |
| @@ -650,10 +778,25 @@ void drbd_debugfs_device_add(struct drbd_device *device) | |||
| 650 | if (!slink_name) | 778 | if (!slink_name) |
| 651 | goto fail; | 779 | goto fail; |
| 652 | dentry = debugfs_create_symlink(minor_buf, drbd_debugfs_minors, slink_name); | 780 | dentry = debugfs_create_symlink(minor_buf, drbd_debugfs_minors, slink_name); |
| 781 | kfree(slink_name); | ||
| 782 | slink_name = NULL; | ||
| 653 | if (IS_ERR_OR_NULL(dentry)) | 783 | if (IS_ERR_OR_NULL(dentry)) |
| 654 | goto fail; | 784 | goto fail; |
| 655 | device->debugfs_minor = dentry; | 785 | device->debugfs_minor = dentry; |
| 656 | kfree(slink_name); | 786 | |
| 787 | #define DCF(name) do { \ | ||
| 788 | dentry = debugfs_create_file(#name, S_IRUSR|S_IRGRP, \ | ||
| 789 | device->debugfs_vol, device, \ | ||
| 790 | &device_ ## name ## _fops); \ | ||
| 791 | if (IS_ERR_OR_NULL(dentry)) \ | ||
| 792 | goto fail; \ | ||
| 793 | device->debugfs_vol_ ## name = dentry; \ | ||
| 794 | } while (0) | ||
| 795 | |||
| 796 | DCF(oldest_requests); | ||
| 797 | DCF(act_log_extents); | ||
| 798 | DCF(resync_extents); | ||
| 799 | return; | ||
| 657 | 800 | ||
| 658 | fail: | 801 | fail: |
| 659 | drbd_debugfs_device_cleanup(device); | 802 | drbd_debugfs_device_cleanup(device); |
