diff options
author | Markus Pargmann <mpa@pengutronix.de> | 2015-08-17 02:20:06 -0400 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2015-08-17 10:22:56 -0400 |
commit | 30d53d9c11b6c2f71253a2be582969d7e6fa7f10 (patch) | |
tree | fb982a8aa6d4b2e7cd84fef7a7064b736ebee894 /drivers/block/nbd.c | |
parent | 6521d39a64b3f9c3acb0fd25a34cfaf9a40e548e (diff) |
nbd: Add debugfs entries
Add some debugfs files that help to understand the internal state of
NBD. This exports the different sizes, flags, tasks and so on.
Signed-off-by: Markus Pargmann <mpa@pengutronix.de>
Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'drivers/block/nbd.c')
-rw-r--r-- | drivers/block/nbd.c | 178 |
1 files changed, 177 insertions, 1 deletions
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index eeefa5cac520..6dd8305840bb 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/net.h> | 33 | #include <linux/net.h> |
34 | #include <linux/kthread.h> | 34 | #include <linux/kthread.h> |
35 | #include <linux/types.h> | 35 | #include <linux/types.h> |
36 | #include <linux/debugfs.h> | ||
36 | 37 | ||
37 | #include <asm/uaccess.h> | 38 | #include <asm/uaccess.h> |
38 | #include <asm/types.h> | 39 | #include <asm/types.h> |
@@ -61,8 +62,18 @@ struct nbd_device { | |||
61 | struct timer_list timeout_timer; | 62 | struct timer_list timeout_timer; |
62 | struct task_struct *task_recv; | 63 | struct task_struct *task_recv; |
63 | struct task_struct *task_send; | 64 | struct task_struct *task_send; |
65 | |||
66 | #if IS_ENABLED(CONFIG_DEBUG_FS) | ||
67 | struct dentry *dbg_dir; | ||
68 | #endif | ||
64 | }; | 69 | }; |
65 | 70 | ||
71 | #if IS_ENABLED(CONFIG_DEBUG_FS) | ||
72 | static struct dentry *nbd_dbg_dir; | ||
73 | #endif | ||
74 | |||
75 | #define nbd_name(nbd) ((nbd)->disk->disk_name) | ||
76 | |||
66 | #define NBD_MAGIC 0x68797548 | 77 | #define NBD_MAGIC 0x68797548 |
67 | 78 | ||
68 | static unsigned int nbds_max = 16; | 79 | static unsigned int nbds_max = 16; |
@@ -609,6 +620,9 @@ static void do_nbd_request(struct request_queue *q) | |||
609 | } | 620 | } |
610 | } | 621 | } |
611 | 622 | ||
623 | static int nbd_dev_dbg_init(struct nbd_device *nbd); | ||
624 | static void nbd_dev_dbg_close(struct nbd_device *nbd); | ||
625 | |||
612 | /* Must be called with tx_lock held */ | 626 | /* Must be called with tx_lock held */ |
613 | 627 | ||
614 | static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd, | 628 | static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd, |
@@ -725,13 +739,15 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd, | |||
725 | blk_queue_flush(nbd->disk->queue, 0); | 739 | blk_queue_flush(nbd->disk->queue, 0); |
726 | 740 | ||
727 | thread = kthread_run(nbd_thread, nbd, "%s", | 741 | thread = kthread_run(nbd_thread, nbd, "%s", |
728 | nbd->disk->disk_name); | 742 | nbd_name(nbd)); |
729 | if (IS_ERR(thread)) { | 743 | if (IS_ERR(thread)) { |
730 | mutex_lock(&nbd->tx_lock); | 744 | mutex_lock(&nbd->tx_lock); |
731 | return PTR_ERR(thread); | 745 | return PTR_ERR(thread); |
732 | } | 746 | } |
733 | 747 | ||
748 | nbd_dev_dbg_init(nbd); | ||
734 | error = nbd_do_it(nbd); | 749 | error = nbd_do_it(nbd); |
750 | nbd_dev_dbg_close(nbd); | ||
735 | kthread_stop(thread); | 751 | kthread_stop(thread); |
736 | 752 | ||
737 | mutex_lock(&nbd->tx_lock); | 753 | mutex_lock(&nbd->tx_lock); |
@@ -797,6 +813,161 @@ static const struct block_device_operations nbd_fops = | |||
797 | .ioctl = nbd_ioctl, | 813 | .ioctl = nbd_ioctl, |
798 | }; | 814 | }; |
799 | 815 | ||
816 | #if IS_ENABLED(CONFIG_DEBUG_FS) | ||
817 | |||
818 | static int nbd_dbg_tasks_show(struct seq_file *s, void *unused) | ||
819 | { | ||
820 | struct nbd_device *nbd = s->private; | ||
821 | |||
822 | if (nbd->task_recv) | ||
823 | seq_printf(s, "recv: %d\n", task_pid_nr(nbd->task_recv)); | ||
824 | if (nbd->task_send) | ||
825 | seq_printf(s, "send: %d\n", task_pid_nr(nbd->task_send)); | ||
826 | |||
827 | return 0; | ||
828 | } | ||
829 | |||
830 | static int nbd_dbg_tasks_open(struct inode *inode, struct file *file) | ||
831 | { | ||
832 | return single_open(file, nbd_dbg_tasks_show, inode->i_private); | ||
833 | } | ||
834 | |||
835 | static const struct file_operations nbd_dbg_tasks_ops = { | ||
836 | .open = nbd_dbg_tasks_open, | ||
837 | .read = seq_read, | ||
838 | .llseek = seq_lseek, | ||
839 | .release = single_release, | ||
840 | }; | ||
841 | |||
842 | static int nbd_dbg_flags_show(struct seq_file *s, void *unused) | ||
843 | { | ||
844 | struct nbd_device *nbd = s->private; | ||
845 | u32 flags = nbd->flags; | ||
846 | |||
847 | seq_printf(s, "Hex: 0x%08x\n\n", flags); | ||
848 | |||
849 | seq_puts(s, "Known flags:\n"); | ||
850 | |||
851 | if (flags & NBD_FLAG_HAS_FLAGS) | ||
852 | seq_puts(s, "NBD_FLAG_HAS_FLAGS\n"); | ||
853 | if (flags & NBD_FLAG_READ_ONLY) | ||
854 | seq_puts(s, "NBD_FLAG_READ_ONLY\n"); | ||
855 | if (flags & NBD_FLAG_SEND_FLUSH) | ||
856 | seq_puts(s, "NBD_FLAG_SEND_FLUSH\n"); | ||
857 | if (flags & NBD_FLAG_SEND_TRIM) | ||
858 | seq_puts(s, "NBD_FLAG_SEND_TRIM\n"); | ||
859 | |||
860 | return 0; | ||
861 | } | ||
862 | |||
863 | static int nbd_dbg_flags_open(struct inode *inode, struct file *file) | ||
864 | { | ||
865 | return single_open(file, nbd_dbg_flags_show, inode->i_private); | ||
866 | } | ||
867 | |||
868 | static const struct file_operations nbd_dbg_flags_ops = { | ||
869 | .open = nbd_dbg_flags_open, | ||
870 | .read = seq_read, | ||
871 | .llseek = seq_lseek, | ||
872 | .release = single_release, | ||
873 | }; | ||
874 | |||
875 | static int nbd_dev_dbg_init(struct nbd_device *nbd) | ||
876 | { | ||
877 | struct dentry *dir; | ||
878 | struct dentry *f; | ||
879 | |||
880 | dir = debugfs_create_dir(nbd_name(nbd), nbd_dbg_dir); | ||
881 | if (IS_ERR_OR_NULL(dir)) { | ||
882 | dev_err(nbd_to_dev(nbd), "Failed to create debugfs dir for '%s' (%ld)\n", | ||
883 | nbd_name(nbd), PTR_ERR(dir)); | ||
884 | return PTR_ERR(dir); | ||
885 | } | ||
886 | nbd->dbg_dir = dir; | ||
887 | |||
888 | f = debugfs_create_file("tasks", 0444, dir, nbd, &nbd_dbg_tasks_ops); | ||
889 | if (IS_ERR_OR_NULL(f)) { | ||
890 | dev_err(nbd_to_dev(nbd), "Failed to create debugfs file 'tasks', %ld\n", | ||
891 | PTR_ERR(f)); | ||
892 | return PTR_ERR(f); | ||
893 | } | ||
894 | |||
895 | f = debugfs_create_u64("size_bytes", 0444, dir, &nbd->bytesize); | ||
896 | if (IS_ERR_OR_NULL(f)) { | ||
897 | dev_err(nbd_to_dev(nbd), "Failed to create debugfs file 'size_bytes', %ld\n", | ||
898 | PTR_ERR(f)); | ||
899 | return PTR_ERR(f); | ||
900 | } | ||
901 | |||
902 | f = debugfs_create_u32("timeout", 0444, dir, &nbd->xmit_timeout); | ||
903 | if (IS_ERR_OR_NULL(f)) { | ||
904 | dev_err(nbd_to_dev(nbd), "Failed to create debugfs file 'timeout', %ld\n", | ||
905 | PTR_ERR(f)); | ||
906 | return PTR_ERR(f); | ||
907 | } | ||
908 | |||
909 | f = debugfs_create_u32("blocksize", 0444, dir, &nbd->blksize); | ||
910 | if (IS_ERR_OR_NULL(f)) { | ||
911 | dev_err(nbd_to_dev(nbd), "Failed to create debugfs file 'blocksize', %ld\n", | ||
912 | PTR_ERR(f)); | ||
913 | return PTR_ERR(f); | ||
914 | } | ||
915 | |||
916 | f = debugfs_create_file("flags", 0444, dir, &nbd, &nbd_dbg_flags_ops); | ||
917 | if (IS_ERR_OR_NULL(f)) { | ||
918 | dev_err(nbd_to_dev(nbd), "Failed to create debugfs file 'flags', %ld\n", | ||
919 | PTR_ERR(f)); | ||
920 | return PTR_ERR(f); | ||
921 | } | ||
922 | |||
923 | return 0; | ||
924 | } | ||
925 | |||
926 | static void nbd_dev_dbg_close(struct nbd_device *nbd) | ||
927 | { | ||
928 | debugfs_remove_recursive(nbd->dbg_dir); | ||
929 | } | ||
930 | |||
931 | static int nbd_dbg_init(void) | ||
932 | { | ||
933 | struct dentry *dbg_dir; | ||
934 | |||
935 | dbg_dir = debugfs_create_dir("nbd", NULL); | ||
936 | if (IS_ERR(dbg_dir)) | ||
937 | return PTR_ERR(dbg_dir); | ||
938 | |||
939 | nbd_dbg_dir = dbg_dir; | ||
940 | |||
941 | return 0; | ||
942 | } | ||
943 | |||
944 | static void nbd_dbg_close(void) | ||
945 | { | ||
946 | debugfs_remove_recursive(nbd_dbg_dir); | ||
947 | } | ||
948 | |||
949 | #else /* IS_ENABLED(CONFIG_DEBUG_FS) */ | ||
950 | |||
951 | static int nbd_dev_dbg_init(struct nbd_device *nbd) | ||
952 | { | ||
953 | return 0; | ||
954 | } | ||
955 | |||
956 | static void nbd_dev_dbg_close(struct nbd_device *nbd) | ||
957 | { | ||
958 | } | ||
959 | |||
960 | static int nbd_dbg_init(void) | ||
961 | { | ||
962 | return 0; | ||
963 | } | ||
964 | |||
965 | static void nbd_dbg_close(void) | ||
966 | { | ||
967 | } | ||
968 | |||
969 | #endif | ||
970 | |||
800 | /* | 971 | /* |
801 | * And here should be modules and kernel interface | 972 | * And here should be modules and kernel interface |
802 | * (Just smiley confuses emacs :-) | 973 | * (Just smiley confuses emacs :-) |
@@ -874,6 +1045,8 @@ static int __init nbd_init(void) | |||
874 | 1045 | ||
875 | printk(KERN_INFO "nbd: registered device at major %d\n", NBD_MAJOR); | 1046 | printk(KERN_INFO "nbd: registered device at major %d\n", NBD_MAJOR); |
876 | 1047 | ||
1048 | nbd_dbg_init(); | ||
1049 | |||
877 | for (i = 0; i < nbds_max; i++) { | 1050 | for (i = 0; i < nbds_max; i++) { |
878 | struct gendisk *disk = nbd_dev[i].disk; | 1051 | struct gendisk *disk = nbd_dev[i].disk; |
879 | nbd_dev[i].magic = NBD_MAGIC; | 1052 | nbd_dev[i].magic = NBD_MAGIC; |
@@ -910,6 +1083,9 @@ out: | |||
910 | static void __exit nbd_cleanup(void) | 1083 | static void __exit nbd_cleanup(void) |
911 | { | 1084 | { |
912 | int i; | 1085 | int i; |
1086 | |||
1087 | nbd_dbg_close(); | ||
1088 | |||
913 | for (i = 0; i < nbds_max; i++) { | 1089 | for (i = 0; i < nbds_max; i++) { |
914 | struct gendisk *disk = nbd_dev[i].disk; | 1090 | struct gendisk *disk = nbd_dev[i].disk; |
915 | nbd_dev[i].magic = 0; | 1091 | nbd_dev[i].magic = 0; |