xref: /openbmc/linux/drivers/block/drbd/drbd_debugfs.c (revision 4d3d5aa83aa45f1c7c9644b30e3a67e42c26695f)
1*4d3d5aa8SLars Ellenberg #define pr_fmt(fmt) "drbd debugfs: " fmt
2*4d3d5aa8SLars Ellenberg #include <linux/kernel.h>
3*4d3d5aa8SLars Ellenberg #include <linux/module.h>
4*4d3d5aa8SLars Ellenberg #include <linux/debugfs.h>
5*4d3d5aa8SLars Ellenberg #include <linux/stat.h>
6*4d3d5aa8SLars Ellenberg #include <linux/list.h>
7*4d3d5aa8SLars Ellenberg 
8*4d3d5aa8SLars Ellenberg #include "drbd_int.h"
9*4d3d5aa8SLars Ellenberg #include "drbd_req.h"
10*4d3d5aa8SLars Ellenberg #include "drbd_debugfs.h"
11*4d3d5aa8SLars Ellenberg 
12*4d3d5aa8SLars Ellenberg static struct dentry *drbd_debugfs_root;
13*4d3d5aa8SLars Ellenberg static struct dentry *drbd_debugfs_resources;
14*4d3d5aa8SLars Ellenberg static struct dentry *drbd_debugfs_minors;
15*4d3d5aa8SLars Ellenberg 
16*4d3d5aa8SLars Ellenberg void drbd_debugfs_resource_add(struct drbd_resource *resource)
17*4d3d5aa8SLars Ellenberg {
18*4d3d5aa8SLars Ellenberg 	struct dentry *dentry;
19*4d3d5aa8SLars Ellenberg 	if (!drbd_debugfs_resources)
20*4d3d5aa8SLars Ellenberg 		return;
21*4d3d5aa8SLars Ellenberg 
22*4d3d5aa8SLars Ellenberg 	dentry = debugfs_create_dir(resource->name, drbd_debugfs_resources);
23*4d3d5aa8SLars Ellenberg 	if (IS_ERR_OR_NULL(dentry))
24*4d3d5aa8SLars Ellenberg 		goto fail;
25*4d3d5aa8SLars Ellenberg 	resource->debugfs_res = dentry;
26*4d3d5aa8SLars Ellenberg 
27*4d3d5aa8SLars Ellenberg 	dentry = debugfs_create_dir("volumes", resource->debugfs_res);
28*4d3d5aa8SLars Ellenberg 	if (IS_ERR_OR_NULL(dentry))
29*4d3d5aa8SLars Ellenberg 		goto fail;
30*4d3d5aa8SLars Ellenberg 	resource->debugfs_res_volumes = dentry;
31*4d3d5aa8SLars Ellenberg 
32*4d3d5aa8SLars Ellenberg 	dentry = debugfs_create_dir("connections", resource->debugfs_res);
33*4d3d5aa8SLars Ellenberg 	if (IS_ERR_OR_NULL(dentry))
34*4d3d5aa8SLars Ellenberg 		goto fail;
35*4d3d5aa8SLars Ellenberg 	resource->debugfs_res_connections = dentry;
36*4d3d5aa8SLars Ellenberg 
37*4d3d5aa8SLars Ellenberg 	return;
38*4d3d5aa8SLars Ellenberg 
39*4d3d5aa8SLars Ellenberg fail:
40*4d3d5aa8SLars Ellenberg 	drbd_debugfs_resource_cleanup(resource);
41*4d3d5aa8SLars Ellenberg 	drbd_err(resource, "failed to create debugfs dentry\n");
42*4d3d5aa8SLars Ellenberg }
43*4d3d5aa8SLars Ellenberg 
44*4d3d5aa8SLars Ellenberg static void drbd_debugfs_remove(struct dentry **dp)
45*4d3d5aa8SLars Ellenberg {
46*4d3d5aa8SLars Ellenberg 	debugfs_remove(*dp);
47*4d3d5aa8SLars Ellenberg 	*dp = NULL;
48*4d3d5aa8SLars Ellenberg }
49*4d3d5aa8SLars Ellenberg 
50*4d3d5aa8SLars Ellenberg void drbd_debugfs_resource_cleanup(struct drbd_resource *resource)
51*4d3d5aa8SLars Ellenberg {
52*4d3d5aa8SLars Ellenberg 	/* it is ok to call debugfs_remove(NULL) */
53*4d3d5aa8SLars Ellenberg 	drbd_debugfs_remove(&resource->debugfs_res_in_flight_summary);
54*4d3d5aa8SLars Ellenberg 	drbd_debugfs_remove(&resource->debugfs_res_connections);
55*4d3d5aa8SLars Ellenberg 	drbd_debugfs_remove(&resource->debugfs_res_volumes);
56*4d3d5aa8SLars Ellenberg 	drbd_debugfs_remove(&resource->debugfs_res);
57*4d3d5aa8SLars Ellenberg }
58*4d3d5aa8SLars Ellenberg 
59*4d3d5aa8SLars Ellenberg void drbd_debugfs_connection_add(struct drbd_connection *connection)
60*4d3d5aa8SLars Ellenberg {
61*4d3d5aa8SLars Ellenberg 	struct dentry *conns_dir = connection->resource->debugfs_res_connections;
62*4d3d5aa8SLars Ellenberg 	struct dentry *dentry;
63*4d3d5aa8SLars Ellenberg 	if (!conns_dir)
64*4d3d5aa8SLars Ellenberg 		return;
65*4d3d5aa8SLars Ellenberg 
66*4d3d5aa8SLars Ellenberg 	/* Once we enable mutliple peers,
67*4d3d5aa8SLars Ellenberg 	 * these connections will have descriptive names.
68*4d3d5aa8SLars Ellenberg 	 * For now, it is just the one connection to the (only) "peer". */
69*4d3d5aa8SLars Ellenberg 	dentry = debugfs_create_dir("peer", conns_dir);
70*4d3d5aa8SLars Ellenberg 	if (IS_ERR_OR_NULL(dentry))
71*4d3d5aa8SLars Ellenberg 		goto fail;
72*4d3d5aa8SLars Ellenberg 	connection->debugfs_conn = dentry;
73*4d3d5aa8SLars Ellenberg 	return;
74*4d3d5aa8SLars Ellenberg 
75*4d3d5aa8SLars Ellenberg fail:
76*4d3d5aa8SLars Ellenberg 	drbd_debugfs_connection_cleanup(connection);
77*4d3d5aa8SLars Ellenberg 	drbd_err(connection, "failed to create debugfs dentry\n");
78*4d3d5aa8SLars Ellenberg }
79*4d3d5aa8SLars Ellenberg 
80*4d3d5aa8SLars Ellenberg void drbd_debugfs_connection_cleanup(struct drbd_connection *connection)
81*4d3d5aa8SLars Ellenberg {
82*4d3d5aa8SLars Ellenberg 	drbd_debugfs_remove(&connection->debugfs_conn_callback_history);
83*4d3d5aa8SLars Ellenberg 	drbd_debugfs_remove(&connection->debugfs_conn_oldest_requests);
84*4d3d5aa8SLars Ellenberg 	drbd_debugfs_remove(&connection->debugfs_conn);
85*4d3d5aa8SLars Ellenberg }
86*4d3d5aa8SLars Ellenberg 
87*4d3d5aa8SLars Ellenberg void drbd_debugfs_device_add(struct drbd_device *device)
88*4d3d5aa8SLars Ellenberg {
89*4d3d5aa8SLars Ellenberg 	struct dentry *vols_dir = device->resource->debugfs_res_volumes;
90*4d3d5aa8SLars Ellenberg 	char minor_buf[8]; /* MINORMASK, MINORBITS == 20; */
91*4d3d5aa8SLars Ellenberg 	char vnr_buf[8];   /* volume number vnr is even 16 bit only; */
92*4d3d5aa8SLars Ellenberg 	char *slink_name = NULL;
93*4d3d5aa8SLars Ellenberg 
94*4d3d5aa8SLars Ellenberg 	struct dentry *dentry;
95*4d3d5aa8SLars Ellenberg 	if (!vols_dir || !drbd_debugfs_minors)
96*4d3d5aa8SLars Ellenberg 		return;
97*4d3d5aa8SLars Ellenberg 
98*4d3d5aa8SLars Ellenberg 	snprintf(vnr_buf, sizeof(vnr_buf), "%u", device->vnr);
99*4d3d5aa8SLars Ellenberg 	dentry = debugfs_create_dir(vnr_buf, vols_dir);
100*4d3d5aa8SLars Ellenberg 	if (IS_ERR_OR_NULL(dentry))
101*4d3d5aa8SLars Ellenberg 		goto fail;
102*4d3d5aa8SLars Ellenberg 	device->debugfs_vol = dentry;
103*4d3d5aa8SLars Ellenberg 
104*4d3d5aa8SLars Ellenberg 	snprintf(minor_buf, sizeof(minor_buf), "%u", device->minor);
105*4d3d5aa8SLars Ellenberg 	slink_name = kasprintf(GFP_KERNEL, "../resources/%s/volumes/%u",
106*4d3d5aa8SLars Ellenberg 			device->resource->name, device->vnr);
107*4d3d5aa8SLars Ellenberg 	if (!slink_name)
108*4d3d5aa8SLars Ellenberg 		goto fail;
109*4d3d5aa8SLars Ellenberg 	dentry = debugfs_create_symlink(minor_buf, drbd_debugfs_minors, slink_name);
110*4d3d5aa8SLars Ellenberg 	if (IS_ERR_OR_NULL(dentry))
111*4d3d5aa8SLars Ellenberg 		goto fail;
112*4d3d5aa8SLars Ellenberg 	device->debugfs_minor = dentry;
113*4d3d5aa8SLars Ellenberg 	kfree(slink_name);
114*4d3d5aa8SLars Ellenberg 
115*4d3d5aa8SLars Ellenberg fail:
116*4d3d5aa8SLars Ellenberg 	drbd_debugfs_device_cleanup(device);
117*4d3d5aa8SLars Ellenberg 	drbd_err(device, "failed to create debugfs entries\n");
118*4d3d5aa8SLars Ellenberg }
119*4d3d5aa8SLars Ellenberg 
120*4d3d5aa8SLars Ellenberg void drbd_debugfs_device_cleanup(struct drbd_device *device)
121*4d3d5aa8SLars Ellenberg {
122*4d3d5aa8SLars Ellenberg 	drbd_debugfs_remove(&device->debugfs_minor);
123*4d3d5aa8SLars Ellenberg 	drbd_debugfs_remove(&device->debugfs_vol_oldest_requests);
124*4d3d5aa8SLars Ellenberg 	drbd_debugfs_remove(&device->debugfs_vol_act_log_extents);
125*4d3d5aa8SLars Ellenberg 	drbd_debugfs_remove(&device->debugfs_vol_resync_extents);
126*4d3d5aa8SLars Ellenberg 	drbd_debugfs_remove(&device->debugfs_vol_data_gen_id);
127*4d3d5aa8SLars Ellenberg 	drbd_debugfs_remove(&device->debugfs_vol);
128*4d3d5aa8SLars Ellenberg }
129*4d3d5aa8SLars Ellenberg 
130*4d3d5aa8SLars Ellenberg void drbd_debugfs_peer_device_add(struct drbd_peer_device *peer_device)
131*4d3d5aa8SLars Ellenberg {
132*4d3d5aa8SLars Ellenberg 	struct dentry *conn_dir = peer_device->connection->debugfs_conn;
133*4d3d5aa8SLars Ellenberg 	struct dentry *dentry;
134*4d3d5aa8SLars Ellenberg 	char vnr_buf[8];
135*4d3d5aa8SLars Ellenberg 
136*4d3d5aa8SLars Ellenberg 	if (!conn_dir)
137*4d3d5aa8SLars Ellenberg 		return;
138*4d3d5aa8SLars Ellenberg 
139*4d3d5aa8SLars Ellenberg 	snprintf(vnr_buf, sizeof(vnr_buf), "%u", peer_device->device->vnr);
140*4d3d5aa8SLars Ellenberg 	dentry = debugfs_create_dir(vnr_buf, conn_dir);
141*4d3d5aa8SLars Ellenberg 	if (IS_ERR_OR_NULL(dentry))
142*4d3d5aa8SLars Ellenberg 		goto fail;
143*4d3d5aa8SLars Ellenberg 	peer_device->debugfs_peer_dev = dentry;
144*4d3d5aa8SLars Ellenberg 	return;
145*4d3d5aa8SLars Ellenberg 
146*4d3d5aa8SLars Ellenberg fail:
147*4d3d5aa8SLars Ellenberg 	drbd_debugfs_peer_device_cleanup(peer_device);
148*4d3d5aa8SLars Ellenberg 	drbd_err(peer_device, "failed to create debugfs entries\n");
149*4d3d5aa8SLars Ellenberg }
150*4d3d5aa8SLars Ellenberg 
151*4d3d5aa8SLars Ellenberg void drbd_debugfs_peer_device_cleanup(struct drbd_peer_device *peer_device)
152*4d3d5aa8SLars Ellenberg {
153*4d3d5aa8SLars Ellenberg 	drbd_debugfs_remove(&peer_device->debugfs_peer_dev);
154*4d3d5aa8SLars Ellenberg }
155*4d3d5aa8SLars Ellenberg 
156*4d3d5aa8SLars Ellenberg /* not __exit, may be indirectly called
157*4d3d5aa8SLars Ellenberg  * from the module-load-failure path as well. */
158*4d3d5aa8SLars Ellenberg void drbd_debugfs_cleanup(void)
159*4d3d5aa8SLars Ellenberg {
160*4d3d5aa8SLars Ellenberg 	drbd_debugfs_remove(&drbd_debugfs_resources);
161*4d3d5aa8SLars Ellenberg 	drbd_debugfs_remove(&drbd_debugfs_minors);
162*4d3d5aa8SLars Ellenberg 	drbd_debugfs_remove(&drbd_debugfs_root);
163*4d3d5aa8SLars Ellenberg }
164*4d3d5aa8SLars Ellenberg 
165*4d3d5aa8SLars Ellenberg int __init drbd_debugfs_init(void)
166*4d3d5aa8SLars Ellenberg {
167*4d3d5aa8SLars Ellenberg 	struct dentry *dentry;
168*4d3d5aa8SLars Ellenberg 
169*4d3d5aa8SLars Ellenberg 	dentry = debugfs_create_dir("drbd", NULL);
170*4d3d5aa8SLars Ellenberg 	if (IS_ERR_OR_NULL(dentry))
171*4d3d5aa8SLars Ellenberg 		goto fail;
172*4d3d5aa8SLars Ellenberg 	drbd_debugfs_root = dentry;
173*4d3d5aa8SLars Ellenberg 
174*4d3d5aa8SLars Ellenberg 	dentry = debugfs_create_dir("resources", drbd_debugfs_root);
175*4d3d5aa8SLars Ellenberg 	if (IS_ERR_OR_NULL(dentry))
176*4d3d5aa8SLars Ellenberg 		goto fail;
177*4d3d5aa8SLars Ellenberg 	drbd_debugfs_resources = dentry;
178*4d3d5aa8SLars Ellenberg 
179*4d3d5aa8SLars Ellenberg 	dentry = debugfs_create_dir("minors", drbd_debugfs_root);
180*4d3d5aa8SLars Ellenberg 	if (IS_ERR_OR_NULL(dentry))
181*4d3d5aa8SLars Ellenberg 		goto fail;
182*4d3d5aa8SLars Ellenberg 	drbd_debugfs_minors = dentry;
183*4d3d5aa8SLars Ellenberg 	return 0;
184*4d3d5aa8SLars Ellenberg 
185*4d3d5aa8SLars Ellenberg fail:
186*4d3d5aa8SLars Ellenberg 	drbd_debugfs_cleanup();
187*4d3d5aa8SLars Ellenberg 	if (dentry)
188*4d3d5aa8SLars Ellenberg 		return PTR_ERR(dentry);
189*4d3d5aa8SLars Ellenberg 	else
190*4d3d5aa8SLars Ellenberg 		return -EINVAL;
191*4d3d5aa8SLars Ellenberg }
192