aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Ellenberg <lars.ellenberg@linbit.com>2014-05-08 07:39:35 -0400
committerPhilipp Reisner <philipp.reisner@linbit.com>2014-07-10 12:35:19 -0400
commit54e6fc38e888a54b016e1e04e1eceea78ddf7ace (patch)
treeb4908bb91f765a1f117df38379ff37cbcf8b451c
parent944410e97cfcec38369eeb5f77d0e8da91d68afb (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>
-rw-r--r--drivers/block/drbd/drbd_debugfs.c153
-rw-r--r--lib/lru_cache.c21
2 files changed, 160 insertions, 14 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;
442out_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
593static 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
618static 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
625static 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
632static 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
595void drbd_debugfs_connection_add(struct drbd_connection *connection) 640void 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
675static 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
686static 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
697static 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
708static 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) \
734static 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} \
740static 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} \
746static 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
754drbd_debugfs_device_attr(oldest_requests)
755drbd_debugfs_device_attr(act_log_extents)
756drbd_debugfs_device_attr(resync_extents)
757
630void drbd_debugfs_device_add(struct drbd_device *device) 758void 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
658fail: 801fail:
659 drbd_debugfs_device_cleanup(device); 802 drbd_debugfs_device_cleanup(device);
diff --git a/lib/lru_cache.c b/lib/lru_cache.c
index 6111cd19762d..852c81e3ba9a 100644
--- a/lib/lru_cache.c
+++ b/lib/lru_cache.c
@@ -643,9 +643,10 @@ void lc_set(struct lru_cache *lc, unsigned int enr, int index)
643 * lc_dump - Dump a complete LRU cache to seq in textual form. 643 * lc_dump - Dump a complete LRU cache to seq in textual form.
644 * @lc: the lru cache to operate on 644 * @lc: the lru cache to operate on
645 * @seq: the &struct seq_file pointer to seq_printf into 645 * @seq: the &struct seq_file pointer to seq_printf into
646 * @utext: user supplied "heading" or other info 646 * @utext: user supplied additional "heading" or other info
647 * @detail: function pointer the user may provide to dump further details 647 * @detail: function pointer the user may provide to dump further details
648 * of the object the lc_element is embedded in. 648 * of the object the lc_element is embedded in. May be NULL.
649 * Note: a leading space ' ' and trailing newline '\n' is implied.
649 */ 650 */
650void lc_seq_dump_details(struct seq_file *seq, struct lru_cache *lc, char *utext, 651void lc_seq_dump_details(struct seq_file *seq, struct lru_cache *lc, char *utext,
651 void (*detail) (struct seq_file *, struct lc_element *)) 652 void (*detail) (struct seq_file *, struct lc_element *))
@@ -654,16 +655,18 @@ void lc_seq_dump_details(struct seq_file *seq, struct lru_cache *lc, char *utext
654 struct lc_element *e; 655 struct lc_element *e;
655 int i; 656 int i;
656 657
657 seq_printf(seq, "\tnn: lc_number refcnt %s\n ", utext); 658 seq_printf(seq, "\tnn: lc_number (new nr) refcnt %s\n ", utext);
658 for (i = 0; i < nr_elements; i++) { 659 for (i = 0; i < nr_elements; i++) {
659 e = lc_element_by_index(lc, i); 660 e = lc_element_by_index(lc, i);
660 if (e->lc_number == LC_FREE) { 661 if (e->lc_number != e->lc_new_number)
661 seq_printf(seq, "\t%2d: FREE\n", i); 662 seq_printf(seq, "\t%5d: %6d %8d %6d ",
662 } else { 663 i, e->lc_number, e->lc_new_number, e->refcnt);
663 seq_printf(seq, "\t%2d: %4u %4u ", i, 664 else
664 e->lc_number, e->refcnt); 665 seq_printf(seq, "\t%5d: %6d %-8s %6d ",
666 i, e->lc_number, "-\"-", e->refcnt);
667 if (detail)
665 detail(seq, e); 668 detail(seq, e);
666 } 669 seq_putc(seq, '\n');
667 } 670 }
668} 671}
669 672