aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/drbd
diff options
context:
space:
mode:
authorLars Ellenberg <lars.ellenberg@linbit.com>2014-05-02 07:19:51 -0400
committerPhilipp Reisner <philipp.reisner@linbit.com>2014-07-10 12:35:16 -0400
commit4d3d5aa83aa45f1c7c9644b30e3a67e42c26695f (patch)
tree1789c8cdcc14a08208234c5131713db6a1640a4a /drivers/block/drbd
parent4ce4926683b820c5c85b8033891dbfb53cc8754f (diff)
drbd: debugfs: add basic hierarchy
Add new debugfs hierarchy /sys/kernel/debug/ drbd/ resources/ $resource_name/connections/peer/$volume_number/ $resource_name/volumes/$volume_number/ minors/$minor_number -> ../resources/$resource_name/volumes/$volume_number/ Followup commits will populate this hierarchy with files containing statistics, diagnostic information and some attribute data. 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/Makefile1
-rw-r--r--drivers/block/drbd/drbd_debugfs.c191
-rw-r--r--drivers/block/drbd/drbd_debugfs.h39
-rw-r--r--drivers/block/drbd/drbd_int.h30
-rw-r--r--drivers/block/drbd/drbd_main.c22
5 files changed, 278 insertions, 5 deletions
diff --git a/drivers/block/drbd/Makefile b/drivers/block/drbd/Makefile
index 8b450338075e..4464e353c1e8 100644
--- a/drivers/block/drbd/Makefile
+++ b/drivers/block/drbd/Makefile
@@ -3,5 +3,6 @@ drbd-y += drbd_worker.o drbd_receiver.o drbd_req.o drbd_actlog.o
3drbd-y += drbd_main.o drbd_strings.o drbd_nl.o 3drbd-y += drbd_main.o drbd_strings.o drbd_nl.o
4drbd-y += drbd_interval.o drbd_state.o 4drbd-y += drbd_interval.o drbd_state.o
5drbd-y += drbd_nla.o 5drbd-y += drbd_nla.o
6drbd-$(CONFIG_DEBUG_FS) += drbd_debugfs.o
6 7
7obj-$(CONFIG_BLK_DEV_DRBD) += drbd.o 8obj-$(CONFIG_BLK_DEV_DRBD) += drbd.o
diff --git a/drivers/block/drbd/drbd_debugfs.c b/drivers/block/drbd/drbd_debugfs.c
new file mode 100644
index 000000000000..9b120c3d9703
--- /dev/null
+++ b/drivers/block/drbd/drbd_debugfs.c
@@ -0,0 +1,191 @@
1#define pr_fmt(fmt) "drbd debugfs: " fmt
2#include <linux/kernel.h>
3#include <linux/module.h>
4#include <linux/debugfs.h>
5#include <linux/stat.h>
6#include <linux/list.h>
7
8#include "drbd_int.h"
9#include "drbd_req.h"
10#include "drbd_debugfs.h"
11
12static struct dentry *drbd_debugfs_root;
13static struct dentry *drbd_debugfs_resources;
14static struct dentry *drbd_debugfs_minors;
15
16void drbd_debugfs_resource_add(struct drbd_resource *resource)
17{
18 struct dentry *dentry;
19 if (!drbd_debugfs_resources)
20 return;
21
22 dentry = debugfs_create_dir(resource->name, drbd_debugfs_resources);
23 if (IS_ERR_OR_NULL(dentry))
24 goto fail;
25 resource->debugfs_res = dentry;
26
27 dentry = debugfs_create_dir("volumes", resource->debugfs_res);
28 if (IS_ERR_OR_NULL(dentry))
29 goto fail;
30 resource->debugfs_res_volumes = dentry;
31
32 dentry = debugfs_create_dir("connections", resource->debugfs_res);
33 if (IS_ERR_OR_NULL(dentry))
34 goto fail;
35 resource->debugfs_res_connections = dentry;
36
37 return;
38
39fail:
40 drbd_debugfs_resource_cleanup(resource);
41 drbd_err(resource, "failed to create debugfs dentry\n");
42}
43
44static void drbd_debugfs_remove(struct dentry **dp)
45{
46 debugfs_remove(*dp);
47 *dp = NULL;
48}
49
50void drbd_debugfs_resource_cleanup(struct drbd_resource *resource)
51{
52 /* it is ok to call debugfs_remove(NULL) */
53 drbd_debugfs_remove(&resource->debugfs_res_in_flight_summary);
54 drbd_debugfs_remove(&resource->debugfs_res_connections);
55 drbd_debugfs_remove(&resource->debugfs_res_volumes);
56 drbd_debugfs_remove(&resource->debugfs_res);
57}
58
59void drbd_debugfs_connection_add(struct drbd_connection *connection)
60{
61 struct dentry *conns_dir = connection->resource->debugfs_res_connections;
62 struct dentry *dentry;
63 if (!conns_dir)
64 return;
65
66 /* Once we enable mutliple peers,
67 * these connections will have descriptive names.
68 * For now, it is just the one connection to the (only) "peer". */
69 dentry = debugfs_create_dir("peer", conns_dir);
70 if (IS_ERR_OR_NULL(dentry))
71 goto fail;
72 connection->debugfs_conn = dentry;
73 return;
74
75fail:
76 drbd_debugfs_connection_cleanup(connection);
77 drbd_err(connection, "failed to create debugfs dentry\n");
78}
79
80void drbd_debugfs_connection_cleanup(struct drbd_connection *connection)
81{
82 drbd_debugfs_remove(&connection->debugfs_conn_callback_history);
83 drbd_debugfs_remove(&connection->debugfs_conn_oldest_requests);
84 drbd_debugfs_remove(&connection->debugfs_conn);
85}
86
87void drbd_debugfs_device_add(struct drbd_device *device)
88{
89 struct dentry *vols_dir = device->resource->debugfs_res_volumes;
90 char minor_buf[8]; /* MINORMASK, MINORBITS == 20; */
91 char vnr_buf[8]; /* volume number vnr is even 16 bit only; */
92 char *slink_name = NULL;
93
94 struct dentry *dentry;
95 if (!vols_dir || !drbd_debugfs_minors)
96 return;
97
98 snprintf(vnr_buf, sizeof(vnr_buf), "%u", device->vnr);
99 dentry = debugfs_create_dir(vnr_buf, vols_dir);
100 if (IS_ERR_OR_NULL(dentry))
101 goto fail;
102 device->debugfs_vol = dentry;
103
104 snprintf(minor_buf, sizeof(minor_buf), "%u", device->minor);
105 slink_name = kasprintf(GFP_KERNEL, "../resources/%s/volumes/%u",
106 device->resource->name, device->vnr);
107 if (!slink_name)
108 goto fail;
109 dentry = debugfs_create_symlink(minor_buf, drbd_debugfs_minors, slink_name);
110 if (IS_ERR_OR_NULL(dentry))
111 goto fail;
112 device->debugfs_minor = dentry;
113 kfree(slink_name);
114
115fail:
116 drbd_debugfs_device_cleanup(device);
117 drbd_err(device, "failed to create debugfs entries\n");
118}
119
120void drbd_debugfs_device_cleanup(struct drbd_device *device)
121{
122 drbd_debugfs_remove(&device->debugfs_minor);
123 drbd_debugfs_remove(&device->debugfs_vol_oldest_requests);
124 drbd_debugfs_remove(&device->debugfs_vol_act_log_extents);
125 drbd_debugfs_remove(&device->debugfs_vol_resync_extents);
126 drbd_debugfs_remove(&device->debugfs_vol_data_gen_id);
127 drbd_debugfs_remove(&device->debugfs_vol);
128}
129
130void drbd_debugfs_peer_device_add(struct drbd_peer_device *peer_device)
131{
132 struct dentry *conn_dir = peer_device->connection->debugfs_conn;
133 struct dentry *dentry;
134 char vnr_buf[8];
135
136 if (!conn_dir)
137 return;
138
139 snprintf(vnr_buf, sizeof(vnr_buf), "%u", peer_device->device->vnr);
140 dentry = debugfs_create_dir(vnr_buf, conn_dir);
141 if (IS_ERR_OR_NULL(dentry))
142 goto fail;
143 peer_device->debugfs_peer_dev = dentry;
144 return;
145
146fail:
147 drbd_debugfs_peer_device_cleanup(peer_device);
148 drbd_err(peer_device, "failed to create debugfs entries\n");
149}
150
151void drbd_debugfs_peer_device_cleanup(struct drbd_peer_device *peer_device)
152{
153 drbd_debugfs_remove(&peer_device->debugfs_peer_dev);
154}
155
156/* not __exit, may be indirectly called
157 * from the module-load-failure path as well. */
158void drbd_debugfs_cleanup(void)
159{
160 drbd_debugfs_remove(&drbd_debugfs_resources);
161 drbd_debugfs_remove(&drbd_debugfs_minors);
162 drbd_debugfs_remove(&drbd_debugfs_root);
163}
164
165int __init drbd_debugfs_init(void)
166{
167 struct dentry *dentry;
168
169 dentry = debugfs_create_dir("drbd", NULL);
170 if (IS_ERR_OR_NULL(dentry))
171 goto fail;
172 drbd_debugfs_root = dentry;
173
174 dentry = debugfs_create_dir("resources", drbd_debugfs_root);
175 if (IS_ERR_OR_NULL(dentry))
176 goto fail;
177 drbd_debugfs_resources = dentry;
178
179 dentry = debugfs_create_dir("minors", drbd_debugfs_root);
180 if (IS_ERR_OR_NULL(dentry))
181 goto fail;
182 drbd_debugfs_minors = dentry;
183 return 0;
184
185fail:
186 drbd_debugfs_cleanup();
187 if (dentry)
188 return PTR_ERR(dentry);
189 else
190 return -EINVAL;
191}
diff --git a/drivers/block/drbd/drbd_debugfs.h b/drivers/block/drbd/drbd_debugfs.h
new file mode 100644
index 000000000000..8bee21340dce
--- /dev/null
+++ b/drivers/block/drbd/drbd_debugfs.h
@@ -0,0 +1,39 @@
1#include <linux/kernel.h>
2#include <linux/module.h>
3#include <linux/debugfs.h>
4
5#include "drbd_int.h"
6
7#ifdef CONFIG_DEBUG_FS
8int __init drbd_debugfs_init(void);
9void drbd_debugfs_cleanup(void);
10
11void drbd_debugfs_resource_add(struct drbd_resource *resource);
12void drbd_debugfs_resource_cleanup(struct drbd_resource *resource);
13
14void drbd_debugfs_connection_add(struct drbd_connection *connection);
15void drbd_debugfs_connection_cleanup(struct drbd_connection *connection);
16
17void drbd_debugfs_device_add(struct drbd_device *device);
18void drbd_debugfs_device_cleanup(struct drbd_device *device);
19
20void drbd_debugfs_peer_device_add(struct drbd_peer_device *peer_device);
21void drbd_debugfs_peer_device_cleanup(struct drbd_peer_device *peer_device);
22#else
23
24static inline int __init drbd_debugfs_init(void) { return -ENODEV; }
25static inline void drbd_debugfs_cleanup(void) { }
26
27static inline void drbd_debugfs_resource_add(struct drbd_resource *resource) { }
28static inline void drbd_debugfs_resource_cleanup(struct drbd_resource *resource) { }
29
30static inline void drbd_debugfs_connection_add(struct drbd_connection *connection) { }
31static inline void drbd_debugfs_connection_cleanup(struct drbd_connection *connection) { }
32
33static inline void drbd_debugfs_device_add(struct drbd_device *device) { }
34static inline void drbd_debugfs_device_cleanup(struct drbd_device *device) { }
35
36static inline void drbd_debugfs_peer_device_add(struct drbd_peer_device *peer_device) { }
37static inline void drbd_debugfs_peer_device_cleanup(struct drbd_peer_device *peer_device) { }
38
39#endif
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h
index 40c816ce8d75..20f2b38e97b9 100644
--- a/drivers/block/drbd/drbd_int.h
+++ b/drivers/block/drbd/drbd_int.h
@@ -670,6 +670,12 @@ enum {
670 670
671struct drbd_resource { 671struct drbd_resource {
672 char *name; 672 char *name;
673#ifdef CONFIG_DEBUG_FS
674 struct dentry *debugfs_res;
675 struct dentry *debugfs_res_volumes;
676 struct dentry *debugfs_res_connections;
677 struct dentry *debugfs_res_in_flight_summary;
678#endif
673 struct kref kref; 679 struct kref kref;
674 struct idr devices; /* volume number to device mapping */ 680 struct idr devices; /* volume number to device mapping */
675 struct list_head connections; 681 struct list_head connections;
@@ -691,6 +697,11 @@ struct drbd_resource {
691struct drbd_connection { 697struct drbd_connection {
692 struct list_head connections; 698 struct list_head connections;
693 struct drbd_resource *resource; 699 struct drbd_resource *resource;
700#ifdef CONFIG_DEBUG_FS
701 struct dentry *debugfs_conn;
702 struct dentry *debugfs_conn_callback_history;
703 struct dentry *debugfs_conn_oldest_requests;
704#endif
694 struct kref kref; 705 struct kref kref;
695 struct idr peer_devices; /* volume number to peer device mapping */ 706 struct idr peer_devices; /* volume number to peer device mapping */
696 enum drbd_conns cstate; /* Only C_STANDALONE to C_WF_REPORT_PARAMS */ 707 enum drbd_conns cstate; /* Only C_STANDALONE to C_WF_REPORT_PARAMS */
@@ -772,13 +783,29 @@ struct drbd_peer_device {
772 struct list_head peer_devices; 783 struct list_head peer_devices;
773 struct drbd_device *device; 784 struct drbd_device *device;
774 struct drbd_connection *connection; 785 struct drbd_connection *connection;
786#ifdef CONFIG_DEBUG_FS
787 struct dentry *debugfs_peer_dev;
788#endif
775}; 789};
776 790
777struct drbd_device { 791struct drbd_device {
778 struct drbd_resource *resource; 792 struct drbd_resource *resource;
779 struct list_head peer_devices; 793 struct list_head peer_devices;
780 struct list_head pending_bitmap_io; 794 struct list_head pending_bitmap_io;
781 int vnr; /* volume number within the connection */ 795
796 unsigned long flush_jif;
797#ifdef CONFIG_DEBUG_FS
798 struct dentry *debugfs_minor;
799 struct dentry *debugfs_vol;
800 struct dentry *debugfs_vol_oldest_requests;
801 struct dentry *debugfs_vol_act_log_extents;
802 struct dentry *debugfs_vol_resync_extents;
803 struct dentry *debugfs_vol_data_gen_id;
804#endif
805
806 unsigned int vnr; /* volume number within the connection */
807 unsigned int minor; /* device minor number */
808
782 struct kref kref; 809 struct kref kref;
783 810
784 /* things that are stored as / read from meta data on disk */ 811 /* things that are stored as / read from meta data on disk */
@@ -895,7 +922,6 @@ struct drbd_device {
895 atomic_t packet_seq; 922 atomic_t packet_seq;
896 unsigned int peer_seq; 923 unsigned int peer_seq;
897 spinlock_t peer_seq_lock; 924 spinlock_t peer_seq_lock;
898 unsigned int minor;
899 unsigned long comm_bm_set; /* communicated number of set bits. */ 925 unsigned long comm_bm_set; /* communicated number of set bits. */
900 struct bm_io_work bm_io_work; 926 struct bm_io_work bm_io_work;
901 u64 ed_uuid; /* UUID of the exposed data */ 927 u64 ed_uuid; /* UUID of the exposed data */
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c
index 922d631c10b3..01de57ec0110 100644
--- a/drivers/block/drbd/drbd_main.c
+++ b/drivers/block/drbd/drbd_main.c
@@ -57,8 +57,8 @@
57#include "drbd_int.h" 57#include "drbd_int.h"
58#include "drbd_protocol.h" 58#include "drbd_protocol.h"
59#include "drbd_req.h" /* only for _req_mod in tl_release and tl_clear */ 59#include "drbd_req.h" /* only for _req_mod in tl_release and tl_clear */
60
61#include "drbd_vli.h" 60#include "drbd_vli.h"
61#include "drbd_debugfs.h"
62 62
63static DEFINE_MUTEX(drbd_main_mutex); 63static DEFINE_MUTEX(drbd_main_mutex);
64static int drbd_open(struct block_device *bdev, fmode_t mode); 64static int drbd_open(struct block_device *bdev, fmode_t mode);
@@ -2308,8 +2308,10 @@ void drbd_free_resource(struct drbd_resource *resource)
2308 2308
2309 for_each_connection_safe(connection, tmp, resource) { 2309 for_each_connection_safe(connection, tmp, resource) {
2310 list_del(&connection->connections); 2310 list_del(&connection->connections);
2311 drbd_debugfs_connection_cleanup(connection);
2311 kref_put(&connection->kref, drbd_destroy_connection); 2312 kref_put(&connection->kref, drbd_destroy_connection);
2312 } 2313 }
2314 drbd_debugfs_resource_cleanup(resource);
2313 kref_put(&resource->kref, drbd_destroy_resource); 2315 kref_put(&resource->kref, drbd_destroy_resource);
2314} 2316}
2315 2317
@@ -2334,6 +2336,7 @@ static void drbd_cleanup(void)
2334 destroy_workqueue(retry.wq); 2336 destroy_workqueue(retry.wq);
2335 2337
2336 drbd_genl_unregister(); 2338 drbd_genl_unregister();
2339 drbd_debugfs_cleanup();
2337 2340
2338 idr_for_each_entry(&drbd_devices, device, i) 2341 idr_for_each_entry(&drbd_devices, device, i)
2339 drbd_delete_device(device); 2342 drbd_delete_device(device);
@@ -2583,6 +2586,7 @@ struct drbd_resource *drbd_create_resource(const char *name)
2583 mutex_init(&resource->conf_update); 2586 mutex_init(&resource->conf_update);
2584 mutex_init(&resource->adm_mutex); 2587 mutex_init(&resource->adm_mutex);
2585 spin_lock_init(&resource->req_lock); 2588 spin_lock_init(&resource->req_lock);
2589 drbd_debugfs_resource_add(resource);
2586 return resource; 2590 return resource;
2587 2591
2588fail_free_name: 2592fail_free_name:
@@ -2593,7 +2597,7 @@ fail:
2593 return NULL; 2597 return NULL;
2594} 2598}
2595 2599
2596/* caller must be under genl_lock() */ 2600/* caller must be under adm_mutex */
2597struct drbd_connection *conn_create(const char *name, struct res_opts *res_opts) 2601struct drbd_connection *conn_create(const char *name, struct res_opts *res_opts)
2598{ 2602{
2599 struct drbd_resource *resource; 2603 struct drbd_resource *resource;
@@ -2651,6 +2655,7 @@ struct drbd_connection *conn_create(const char *name, struct res_opts *res_opts)
2651 2655
2652 kref_get(&resource->kref); 2656 kref_get(&resource->kref);
2653 list_add_tail_rcu(&connection->connections, &resource->connections); 2657 list_add_tail_rcu(&connection->connections, &resource->connections);
2658 drbd_debugfs_connection_add(connection);
2654 return connection; 2659 return connection;
2655 2660
2656fail_resource: 2661fail_resource:
@@ -2829,7 +2834,10 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig
2829 for_each_peer_device(peer_device, device) 2834 for_each_peer_device(peer_device, device)
2830 drbd_connected(peer_device); 2835 drbd_connected(peer_device);
2831 } 2836 }
2832 2837 /* move to create_peer_device() */
2838 for_each_peer_device(peer_device, device)
2839 drbd_debugfs_peer_device_add(peer_device);
2840 drbd_debugfs_device_add(device);
2833 return NO_ERROR; 2841 return NO_ERROR;
2834 2842
2835out_idr_remove_vol: 2843out_idr_remove_vol:
@@ -2868,8 +2876,13 @@ void drbd_delete_device(struct drbd_device *device)
2868{ 2876{
2869 struct drbd_resource *resource = device->resource; 2877 struct drbd_resource *resource = device->resource;
2870 struct drbd_connection *connection; 2878 struct drbd_connection *connection;
2879 struct drbd_peer_device *peer_device;
2871 int refs = 3; 2880 int refs = 3;
2872 2881
2882 /* move to free_peer_device() */
2883 for_each_peer_device(peer_device, device)
2884 drbd_debugfs_peer_device_cleanup(peer_device);
2885 drbd_debugfs_device_cleanup(device);
2873 for_each_connection(connection, resource) { 2886 for_each_connection(connection, resource) {
2874 idr_remove(&connection->peer_devices, device->vnr); 2887 idr_remove(&connection->peer_devices, device->vnr);
2875 refs++; 2888 refs++;
@@ -2938,6 +2951,9 @@ static int __init drbd_init(void)
2938 spin_lock_init(&retry.lock); 2951 spin_lock_init(&retry.lock);
2939 INIT_LIST_HEAD(&retry.writes); 2952 INIT_LIST_HEAD(&retry.writes);
2940 2953
2954 if (drbd_debugfs_init())
2955 pr_notice("failed to initialize debugfs -- will not be available\n");
2956
2941 pr_info("initialized. " 2957 pr_info("initialized. "
2942 "Version: " REL_VERSION " (api:%d/proto:%d-%d)\n", 2958 "Version: " REL_VERSION " (api:%d/proto:%d-%d)\n",
2943 API_VERSION, PRO_VERSION_MIN, PRO_VERSION_MAX); 2959 API_VERSION, PRO_VERSION_MIN, PRO_VERSION_MAX);