xref: /openbmc/linux/drivers/block/drbd/drbd_debugfs.c (revision db1866ffeed2e142208a801f7598326b92ebf7c5)
14d3d5aa8SLars Ellenberg #define pr_fmt(fmt) "drbd debugfs: " fmt
24d3d5aa8SLars Ellenberg #include <linux/kernel.h>
34d3d5aa8SLars Ellenberg #include <linux/module.h>
44d3d5aa8SLars Ellenberg #include <linux/debugfs.h>
5*db1866ffSLars Ellenberg #include <linux/seq_file.h>
64d3d5aa8SLars Ellenberg #include <linux/stat.h>
7*db1866ffSLars Ellenberg #include <linux/jiffies.h>
84d3d5aa8SLars Ellenberg #include <linux/list.h>
94d3d5aa8SLars Ellenberg 
104d3d5aa8SLars Ellenberg #include "drbd_int.h"
114d3d5aa8SLars Ellenberg #include "drbd_req.h"
124d3d5aa8SLars Ellenberg #include "drbd_debugfs.h"
134d3d5aa8SLars Ellenberg 
144d3d5aa8SLars Ellenberg static struct dentry *drbd_debugfs_root;
154d3d5aa8SLars Ellenberg static struct dentry *drbd_debugfs_resources;
164d3d5aa8SLars Ellenberg static struct dentry *drbd_debugfs_minors;
174d3d5aa8SLars Ellenberg 
18*db1866ffSLars Ellenberg static void seq_print_age_or_dash(struct seq_file *m, bool valid, unsigned long dt)
19*db1866ffSLars Ellenberg {
20*db1866ffSLars Ellenberg 	if (valid)
21*db1866ffSLars Ellenberg 		seq_printf(m, "\t%d", jiffies_to_msecs(dt));
22*db1866ffSLars Ellenberg 	else
23*db1866ffSLars Ellenberg 		seq_printf(m, "\t-");
24*db1866ffSLars Ellenberg }
25*db1866ffSLars Ellenberg 
26*db1866ffSLars Ellenberg static void seq_print_rq_state_bit(struct seq_file *m,
27*db1866ffSLars Ellenberg 	bool is_set, char *sep, const char *name)
28*db1866ffSLars Ellenberg {
29*db1866ffSLars Ellenberg 	if (!is_set)
30*db1866ffSLars Ellenberg 		return;
31*db1866ffSLars Ellenberg 	seq_putc(m, *sep);
32*db1866ffSLars Ellenberg 	seq_puts(m, name);
33*db1866ffSLars Ellenberg 	*sep = '|';
34*db1866ffSLars Ellenberg }
35*db1866ffSLars Ellenberg 
36*db1866ffSLars Ellenberg /* pretty print enum drbd_req_state_bits req->rq_state */
37*db1866ffSLars Ellenberg static void seq_print_request_state(struct seq_file *m, struct drbd_request *req)
38*db1866ffSLars Ellenberg {
39*db1866ffSLars Ellenberg 	unsigned int s = req->rq_state;
40*db1866ffSLars Ellenberg 	char sep = ' ';
41*db1866ffSLars Ellenberg 	seq_printf(m, "\t0x%08x", s);
42*db1866ffSLars Ellenberg 	seq_printf(m, "\tmaster: %s", req->master_bio ? "pending" : "completed");
43*db1866ffSLars Ellenberg 
44*db1866ffSLars Ellenberg 	/* RQ_WRITE ignored, already reported */
45*db1866ffSLars Ellenberg 	seq_puts(m, "\tlocal:");
46*db1866ffSLars Ellenberg 	seq_print_rq_state_bit(m, s & RQ_IN_ACT_LOG, &sep, "in-AL");
47*db1866ffSLars Ellenberg 	seq_print_rq_state_bit(m, s & RQ_POSTPONED, &sep, "postponed");
48*db1866ffSLars Ellenberg 	seq_print_rq_state_bit(m, s & RQ_COMPLETION_SUSP, &sep, "suspended");
49*db1866ffSLars Ellenberg 	sep = ' ';
50*db1866ffSLars Ellenberg 	seq_print_rq_state_bit(m, s & RQ_LOCAL_PENDING, &sep, "pending");
51*db1866ffSLars Ellenberg 	seq_print_rq_state_bit(m, s & RQ_LOCAL_COMPLETED, &sep, "completed");
52*db1866ffSLars Ellenberg 	seq_print_rq_state_bit(m, s & RQ_LOCAL_ABORTED, &sep, "aborted");
53*db1866ffSLars Ellenberg 	seq_print_rq_state_bit(m, s & RQ_LOCAL_OK, &sep, "ok");
54*db1866ffSLars Ellenberg 	if (sep == ' ')
55*db1866ffSLars Ellenberg 		seq_puts(m, " -");
56*db1866ffSLars Ellenberg 
57*db1866ffSLars Ellenberg 	/* for_each_connection ... */
58*db1866ffSLars Ellenberg 	seq_printf(m, "\tnet:");
59*db1866ffSLars Ellenberg 	sep = ' ';
60*db1866ffSLars Ellenberg 	seq_print_rq_state_bit(m, s & RQ_NET_PENDING, &sep, "pending");
61*db1866ffSLars Ellenberg 	seq_print_rq_state_bit(m, s & RQ_NET_QUEUED, &sep, "queued");
62*db1866ffSLars Ellenberg 	seq_print_rq_state_bit(m, s & RQ_NET_SENT, &sep, "sent");
63*db1866ffSLars Ellenberg 	seq_print_rq_state_bit(m, s & RQ_NET_DONE, &sep, "done");
64*db1866ffSLars Ellenberg 	seq_print_rq_state_bit(m, s & RQ_NET_SIS, &sep, "sis");
65*db1866ffSLars Ellenberg 	seq_print_rq_state_bit(m, s & RQ_NET_OK, &sep, "ok");
66*db1866ffSLars Ellenberg 	if (sep == ' ')
67*db1866ffSLars Ellenberg 		seq_puts(m, " -");
68*db1866ffSLars Ellenberg 
69*db1866ffSLars Ellenberg 	seq_printf(m, " :");
70*db1866ffSLars Ellenberg 	sep = ' ';
71*db1866ffSLars Ellenberg 	seq_print_rq_state_bit(m, s & RQ_EXP_RECEIVE_ACK, &sep, "B");
72*db1866ffSLars Ellenberg 	seq_print_rq_state_bit(m, s & RQ_EXP_WRITE_ACK, &sep, "C");
73*db1866ffSLars Ellenberg 	seq_print_rq_state_bit(m, s & RQ_EXP_BARR_ACK, &sep, "barr");
74*db1866ffSLars Ellenberg 	if (sep == ' ')
75*db1866ffSLars Ellenberg 		seq_puts(m, " -");
76*db1866ffSLars Ellenberg 	seq_printf(m, "\n");
77*db1866ffSLars Ellenberg }
78*db1866ffSLars Ellenberg 
79*db1866ffSLars Ellenberg static void seq_print_one_request(struct seq_file *m, struct drbd_request *req, unsigned long now)
80*db1866ffSLars Ellenberg {
81*db1866ffSLars Ellenberg 	/* change anything here, fixup header below! */
82*db1866ffSLars Ellenberg 	unsigned int s = req->rq_state;
83*db1866ffSLars Ellenberg 
84*db1866ffSLars Ellenberg #define RQ_HDR_1 "epoch\tsector\tsize\trw"
85*db1866ffSLars Ellenberg 	seq_printf(m, "0x%x\t%llu\t%u\t%s",
86*db1866ffSLars Ellenberg 		req->epoch,
87*db1866ffSLars Ellenberg 		(unsigned long long)req->i.sector, req->i.size >> 9,
88*db1866ffSLars Ellenberg 		(s & RQ_WRITE) ? "W" : "R");
89*db1866ffSLars Ellenberg 
90*db1866ffSLars Ellenberg #define RQ_HDR_2 "\tstart\tin AL\tsubmit"
91*db1866ffSLars Ellenberg 	seq_printf(m, "\t%d", jiffies_to_msecs(now - req->start_jif));
92*db1866ffSLars Ellenberg 	seq_print_age_or_dash(m, s & RQ_IN_ACT_LOG, now - req->in_actlog_jif);
93*db1866ffSLars Ellenberg 	seq_print_age_or_dash(m, s & RQ_LOCAL_PENDING, now - req->pre_submit_jif);
94*db1866ffSLars Ellenberg 
95*db1866ffSLars Ellenberg #define RQ_HDR_3 "\tsent\tacked\tdone"
96*db1866ffSLars Ellenberg 	seq_print_age_or_dash(m, s & RQ_NET_SENT, now - req->pre_send_jif);
97*db1866ffSLars Ellenberg 	seq_print_age_or_dash(m, (s & RQ_NET_SENT) && !(s & RQ_NET_PENDING), now - req->acked_jif);
98*db1866ffSLars Ellenberg 	seq_print_age_or_dash(m, s & RQ_NET_DONE, now - req->net_done_jif);
99*db1866ffSLars Ellenberg 
100*db1866ffSLars Ellenberg #define RQ_HDR_4 "\tstate\n"
101*db1866ffSLars Ellenberg 	seq_print_request_state(m, req);
102*db1866ffSLars Ellenberg }
103*db1866ffSLars Ellenberg #define RQ_HDR RQ_HDR_1 RQ_HDR_2 RQ_HDR_3 RQ_HDR_4
104*db1866ffSLars Ellenberg 
105*db1866ffSLars Ellenberg static void seq_print_minor_vnr_req(struct seq_file *m, struct drbd_request *req, unsigned long now)
106*db1866ffSLars Ellenberg {
107*db1866ffSLars Ellenberg 	seq_printf(m, "%u\t%u\t", req->device->minor, req->device->vnr);
108*db1866ffSLars Ellenberg 	seq_print_one_request(m, req, now);
109*db1866ffSLars Ellenberg }
110*db1866ffSLars Ellenberg 
111*db1866ffSLars Ellenberg static void seq_print_resource_transfer_log_summary(struct seq_file *m,
112*db1866ffSLars Ellenberg 	struct drbd_resource *resource,
113*db1866ffSLars Ellenberg 	struct drbd_connection *connection,
114*db1866ffSLars Ellenberg 	unsigned long now)
115*db1866ffSLars Ellenberg {
116*db1866ffSLars Ellenberg 	struct drbd_request *req;
117*db1866ffSLars Ellenberg 	unsigned int count = 0;
118*db1866ffSLars Ellenberg 	unsigned int show_state = 0;
119*db1866ffSLars Ellenberg 
120*db1866ffSLars Ellenberg 	seq_puts(m, "n\tdevice\tvnr\t" RQ_HDR);
121*db1866ffSLars Ellenberg 	spin_lock_irq(&resource->req_lock);
122*db1866ffSLars Ellenberg 	list_for_each_entry(req, &connection->transfer_log, tl_requests) {
123*db1866ffSLars Ellenberg 		unsigned int tmp = 0;
124*db1866ffSLars Ellenberg 		unsigned int s;
125*db1866ffSLars Ellenberg 		++count;
126*db1866ffSLars Ellenberg 
127*db1866ffSLars Ellenberg 		/* don't disable irq "forever" */
128*db1866ffSLars Ellenberg 		if (!(count & 0x1ff)) {
129*db1866ffSLars Ellenberg 			struct drbd_request *req_next;
130*db1866ffSLars Ellenberg 			kref_get(&req->kref);
131*db1866ffSLars Ellenberg 			spin_unlock_irq(&resource->req_lock);
132*db1866ffSLars Ellenberg 			cond_resched();
133*db1866ffSLars Ellenberg 			spin_lock_irq(&resource->req_lock);
134*db1866ffSLars Ellenberg 			req_next = list_next_entry(req, tl_requests);
135*db1866ffSLars Ellenberg 			if (kref_put(&req->kref, drbd_req_destroy))
136*db1866ffSLars Ellenberg 				req = req_next;
137*db1866ffSLars Ellenberg 			if (&req->tl_requests == &connection->transfer_log)
138*db1866ffSLars Ellenberg 				break;
139*db1866ffSLars Ellenberg 		}
140*db1866ffSLars Ellenberg 
141*db1866ffSLars Ellenberg 		s = req->rq_state;
142*db1866ffSLars Ellenberg 
143*db1866ffSLars Ellenberg 		/* This is meant to summarize timing issues, to be able to tell
144*db1866ffSLars Ellenberg 		 * local disk problems from network problems.
145*db1866ffSLars Ellenberg 		 * Skip requests, if we have shown an even older request with
146*db1866ffSLars Ellenberg 		 * similar aspects already.  */
147*db1866ffSLars Ellenberg 		if (req->master_bio == NULL)
148*db1866ffSLars Ellenberg 			tmp |= 1;
149*db1866ffSLars Ellenberg 		if ((s & RQ_LOCAL_MASK) && (s & RQ_LOCAL_PENDING))
150*db1866ffSLars Ellenberg 			tmp |= 2;
151*db1866ffSLars Ellenberg 		if (s & RQ_NET_MASK) {
152*db1866ffSLars Ellenberg 			if (!(s & RQ_NET_SENT))
153*db1866ffSLars Ellenberg 				tmp |= 4;
154*db1866ffSLars Ellenberg 			if (s & RQ_NET_PENDING)
155*db1866ffSLars Ellenberg 				tmp |= 8;
156*db1866ffSLars Ellenberg 			if (!(s & RQ_NET_DONE))
157*db1866ffSLars Ellenberg 				tmp |= 16;
158*db1866ffSLars Ellenberg 		}
159*db1866ffSLars Ellenberg 		if ((tmp & show_state) == tmp)
160*db1866ffSLars Ellenberg 			continue;
161*db1866ffSLars Ellenberg 		show_state |= tmp;
162*db1866ffSLars Ellenberg 		seq_printf(m, "%u\t", count);
163*db1866ffSLars Ellenberg 		seq_print_minor_vnr_req(m, req, now);
164*db1866ffSLars Ellenberg 		if (show_state == 0x1f)
165*db1866ffSLars Ellenberg 			break;
166*db1866ffSLars Ellenberg 	}
167*db1866ffSLars Ellenberg 	spin_unlock_irq(&resource->req_lock);
168*db1866ffSLars Ellenberg }
169*db1866ffSLars Ellenberg 
170*db1866ffSLars Ellenberg /* TODO: transfer_log and friends should be moved to resource */
171*db1866ffSLars Ellenberg static int in_flight_summary_show(struct seq_file *m, void *pos)
172*db1866ffSLars Ellenberg {
173*db1866ffSLars Ellenberg 	struct drbd_resource *resource = m->private;
174*db1866ffSLars Ellenberg 	struct drbd_connection *connection;
175*db1866ffSLars Ellenberg 	unsigned long jif = jiffies;
176*db1866ffSLars Ellenberg 
177*db1866ffSLars Ellenberg 	connection = first_connection(resource);
178*db1866ffSLars Ellenberg 	/* This does not happen, actually.
179*db1866ffSLars Ellenberg 	 * But be robust and prepare for future code changes. */
180*db1866ffSLars Ellenberg 	if (!connection)
181*db1866ffSLars Ellenberg 		return 0;
182*db1866ffSLars Ellenberg 
183*db1866ffSLars Ellenberg 	seq_puts(m, "oldest application requests\n");
184*db1866ffSLars Ellenberg 	seq_print_resource_transfer_log_summary(m, resource, connection, jif);
185*db1866ffSLars Ellenberg 	seq_putc(m, '\n');
186*db1866ffSLars Ellenberg 
187*db1866ffSLars Ellenberg 	jif = jiffies - jif;
188*db1866ffSLars Ellenberg 	if (jif)
189*db1866ffSLars Ellenberg 		seq_printf(m, "generated in %d ms\n", jiffies_to_msecs(jif));
190*db1866ffSLars Ellenberg 	return 0;
191*db1866ffSLars Ellenberg }
192*db1866ffSLars Ellenberg 
193*db1866ffSLars Ellenberg static int in_flight_summary_open(struct inode *inode, struct file *file)
194*db1866ffSLars Ellenberg {
195*db1866ffSLars Ellenberg 	return single_open(file, in_flight_summary_show, inode->i_private);
196*db1866ffSLars Ellenberg }
197*db1866ffSLars Ellenberg 
198*db1866ffSLars Ellenberg static const struct file_operations in_flight_summary_fops = {
199*db1866ffSLars Ellenberg 	.owner		= THIS_MODULE,
200*db1866ffSLars Ellenberg 	.open		= in_flight_summary_open,
201*db1866ffSLars Ellenberg 	.read		= seq_read,
202*db1866ffSLars Ellenberg 	.llseek		= seq_lseek,
203*db1866ffSLars Ellenberg 	.release	= single_release,
204*db1866ffSLars Ellenberg };
205*db1866ffSLars Ellenberg 
2064d3d5aa8SLars Ellenberg void drbd_debugfs_resource_add(struct drbd_resource *resource)
2074d3d5aa8SLars Ellenberg {
2084d3d5aa8SLars Ellenberg 	struct dentry *dentry;
2094d3d5aa8SLars Ellenberg 	if (!drbd_debugfs_resources)
2104d3d5aa8SLars Ellenberg 		return;
2114d3d5aa8SLars Ellenberg 
2124d3d5aa8SLars Ellenberg 	dentry = debugfs_create_dir(resource->name, drbd_debugfs_resources);
2134d3d5aa8SLars Ellenberg 	if (IS_ERR_OR_NULL(dentry))
2144d3d5aa8SLars Ellenberg 		goto fail;
2154d3d5aa8SLars Ellenberg 	resource->debugfs_res = dentry;
2164d3d5aa8SLars Ellenberg 
2174d3d5aa8SLars Ellenberg 	dentry = debugfs_create_dir("volumes", resource->debugfs_res);
2184d3d5aa8SLars Ellenberg 	if (IS_ERR_OR_NULL(dentry))
2194d3d5aa8SLars Ellenberg 		goto fail;
2204d3d5aa8SLars Ellenberg 	resource->debugfs_res_volumes = dentry;
2214d3d5aa8SLars Ellenberg 
2224d3d5aa8SLars Ellenberg 	dentry = debugfs_create_dir("connections", resource->debugfs_res);
2234d3d5aa8SLars Ellenberg 	if (IS_ERR_OR_NULL(dentry))
2244d3d5aa8SLars Ellenberg 		goto fail;
2254d3d5aa8SLars Ellenberg 	resource->debugfs_res_connections = dentry;
2264d3d5aa8SLars Ellenberg 
227*db1866ffSLars Ellenberg 	dentry = debugfs_create_file("in_flight_summary", S_IRUSR|S_IRGRP,
228*db1866ffSLars Ellenberg 			resource->debugfs_res, resource,
229*db1866ffSLars Ellenberg 			&in_flight_summary_fops);
230*db1866ffSLars Ellenberg 	if (IS_ERR_OR_NULL(dentry))
231*db1866ffSLars Ellenberg 		goto fail;
232*db1866ffSLars Ellenberg 	resource->debugfs_res_in_flight_summary = dentry;
2334d3d5aa8SLars Ellenberg 	return;
2344d3d5aa8SLars Ellenberg 
2354d3d5aa8SLars Ellenberg fail:
2364d3d5aa8SLars Ellenberg 	drbd_debugfs_resource_cleanup(resource);
2374d3d5aa8SLars Ellenberg 	drbd_err(resource, "failed to create debugfs dentry\n");
2384d3d5aa8SLars Ellenberg }
2394d3d5aa8SLars Ellenberg 
2404d3d5aa8SLars Ellenberg static void drbd_debugfs_remove(struct dentry **dp)
2414d3d5aa8SLars Ellenberg {
2424d3d5aa8SLars Ellenberg 	debugfs_remove(*dp);
2434d3d5aa8SLars Ellenberg 	*dp = NULL;
2444d3d5aa8SLars Ellenberg }
2454d3d5aa8SLars Ellenberg 
2464d3d5aa8SLars Ellenberg void drbd_debugfs_resource_cleanup(struct drbd_resource *resource)
2474d3d5aa8SLars Ellenberg {
2484d3d5aa8SLars Ellenberg 	/* it is ok to call debugfs_remove(NULL) */
2494d3d5aa8SLars Ellenberg 	drbd_debugfs_remove(&resource->debugfs_res_in_flight_summary);
2504d3d5aa8SLars Ellenberg 	drbd_debugfs_remove(&resource->debugfs_res_connections);
2514d3d5aa8SLars Ellenberg 	drbd_debugfs_remove(&resource->debugfs_res_volumes);
2524d3d5aa8SLars Ellenberg 	drbd_debugfs_remove(&resource->debugfs_res);
2534d3d5aa8SLars Ellenberg }
2544d3d5aa8SLars Ellenberg 
2554d3d5aa8SLars Ellenberg void drbd_debugfs_connection_add(struct drbd_connection *connection)
2564d3d5aa8SLars Ellenberg {
2574d3d5aa8SLars Ellenberg 	struct dentry *conns_dir = connection->resource->debugfs_res_connections;
2584d3d5aa8SLars Ellenberg 	struct dentry *dentry;
2594d3d5aa8SLars Ellenberg 	if (!conns_dir)
2604d3d5aa8SLars Ellenberg 		return;
2614d3d5aa8SLars Ellenberg 
2624d3d5aa8SLars Ellenberg 	/* Once we enable mutliple peers,
2634d3d5aa8SLars Ellenberg 	 * these connections will have descriptive names.
2644d3d5aa8SLars Ellenberg 	 * For now, it is just the one connection to the (only) "peer". */
2654d3d5aa8SLars Ellenberg 	dentry = debugfs_create_dir("peer", conns_dir);
2664d3d5aa8SLars Ellenberg 	if (IS_ERR_OR_NULL(dentry))
2674d3d5aa8SLars Ellenberg 		goto fail;
2684d3d5aa8SLars Ellenberg 	connection->debugfs_conn = dentry;
2694d3d5aa8SLars Ellenberg 	return;
2704d3d5aa8SLars Ellenberg 
2714d3d5aa8SLars Ellenberg fail:
2724d3d5aa8SLars Ellenberg 	drbd_debugfs_connection_cleanup(connection);
2734d3d5aa8SLars Ellenberg 	drbd_err(connection, "failed to create debugfs dentry\n");
2744d3d5aa8SLars Ellenberg }
2754d3d5aa8SLars Ellenberg 
2764d3d5aa8SLars Ellenberg void drbd_debugfs_connection_cleanup(struct drbd_connection *connection)
2774d3d5aa8SLars Ellenberg {
2784d3d5aa8SLars Ellenberg 	drbd_debugfs_remove(&connection->debugfs_conn_callback_history);
2794d3d5aa8SLars Ellenberg 	drbd_debugfs_remove(&connection->debugfs_conn_oldest_requests);
2804d3d5aa8SLars Ellenberg 	drbd_debugfs_remove(&connection->debugfs_conn);
2814d3d5aa8SLars Ellenberg }
2824d3d5aa8SLars Ellenberg 
2834d3d5aa8SLars Ellenberg void drbd_debugfs_device_add(struct drbd_device *device)
2844d3d5aa8SLars Ellenberg {
2854d3d5aa8SLars Ellenberg 	struct dentry *vols_dir = device->resource->debugfs_res_volumes;
2864d3d5aa8SLars Ellenberg 	char minor_buf[8]; /* MINORMASK, MINORBITS == 20; */
2874d3d5aa8SLars Ellenberg 	char vnr_buf[8];   /* volume number vnr is even 16 bit only; */
2884d3d5aa8SLars Ellenberg 	char *slink_name = NULL;
2894d3d5aa8SLars Ellenberg 
2904d3d5aa8SLars Ellenberg 	struct dentry *dentry;
2914d3d5aa8SLars Ellenberg 	if (!vols_dir || !drbd_debugfs_minors)
2924d3d5aa8SLars Ellenberg 		return;
2934d3d5aa8SLars Ellenberg 
2944d3d5aa8SLars Ellenberg 	snprintf(vnr_buf, sizeof(vnr_buf), "%u", device->vnr);
2954d3d5aa8SLars Ellenberg 	dentry = debugfs_create_dir(vnr_buf, vols_dir);
2964d3d5aa8SLars Ellenberg 	if (IS_ERR_OR_NULL(dentry))
2974d3d5aa8SLars Ellenberg 		goto fail;
2984d3d5aa8SLars Ellenberg 	device->debugfs_vol = dentry;
2994d3d5aa8SLars Ellenberg 
3004d3d5aa8SLars Ellenberg 	snprintf(minor_buf, sizeof(minor_buf), "%u", device->minor);
3014d3d5aa8SLars Ellenberg 	slink_name = kasprintf(GFP_KERNEL, "../resources/%s/volumes/%u",
3024d3d5aa8SLars Ellenberg 			device->resource->name, device->vnr);
3034d3d5aa8SLars Ellenberg 	if (!slink_name)
3044d3d5aa8SLars Ellenberg 		goto fail;
3054d3d5aa8SLars Ellenberg 	dentry = debugfs_create_symlink(minor_buf, drbd_debugfs_minors, slink_name);
3064d3d5aa8SLars Ellenberg 	if (IS_ERR_OR_NULL(dentry))
3074d3d5aa8SLars Ellenberg 		goto fail;
3084d3d5aa8SLars Ellenberg 	device->debugfs_minor = dentry;
3094d3d5aa8SLars Ellenberg 	kfree(slink_name);
3104d3d5aa8SLars Ellenberg 
3114d3d5aa8SLars Ellenberg fail:
3124d3d5aa8SLars Ellenberg 	drbd_debugfs_device_cleanup(device);
3134d3d5aa8SLars Ellenberg 	drbd_err(device, "failed to create debugfs entries\n");
3144d3d5aa8SLars Ellenberg }
3154d3d5aa8SLars Ellenberg 
3164d3d5aa8SLars Ellenberg void drbd_debugfs_device_cleanup(struct drbd_device *device)
3174d3d5aa8SLars Ellenberg {
3184d3d5aa8SLars Ellenberg 	drbd_debugfs_remove(&device->debugfs_minor);
3194d3d5aa8SLars Ellenberg 	drbd_debugfs_remove(&device->debugfs_vol_oldest_requests);
3204d3d5aa8SLars Ellenberg 	drbd_debugfs_remove(&device->debugfs_vol_act_log_extents);
3214d3d5aa8SLars Ellenberg 	drbd_debugfs_remove(&device->debugfs_vol_resync_extents);
3224d3d5aa8SLars Ellenberg 	drbd_debugfs_remove(&device->debugfs_vol_data_gen_id);
3234d3d5aa8SLars Ellenberg 	drbd_debugfs_remove(&device->debugfs_vol);
3244d3d5aa8SLars Ellenberg }
3254d3d5aa8SLars Ellenberg 
3264d3d5aa8SLars Ellenberg void drbd_debugfs_peer_device_add(struct drbd_peer_device *peer_device)
3274d3d5aa8SLars Ellenberg {
3284d3d5aa8SLars Ellenberg 	struct dentry *conn_dir = peer_device->connection->debugfs_conn;
3294d3d5aa8SLars Ellenberg 	struct dentry *dentry;
3304d3d5aa8SLars Ellenberg 	char vnr_buf[8];
3314d3d5aa8SLars Ellenberg 
3324d3d5aa8SLars Ellenberg 	if (!conn_dir)
3334d3d5aa8SLars Ellenberg 		return;
3344d3d5aa8SLars Ellenberg 
3354d3d5aa8SLars Ellenberg 	snprintf(vnr_buf, sizeof(vnr_buf), "%u", peer_device->device->vnr);
3364d3d5aa8SLars Ellenberg 	dentry = debugfs_create_dir(vnr_buf, conn_dir);
3374d3d5aa8SLars Ellenberg 	if (IS_ERR_OR_NULL(dentry))
3384d3d5aa8SLars Ellenberg 		goto fail;
3394d3d5aa8SLars Ellenberg 	peer_device->debugfs_peer_dev = dentry;
3404d3d5aa8SLars Ellenberg 	return;
3414d3d5aa8SLars Ellenberg 
3424d3d5aa8SLars Ellenberg fail:
3434d3d5aa8SLars Ellenberg 	drbd_debugfs_peer_device_cleanup(peer_device);
3444d3d5aa8SLars Ellenberg 	drbd_err(peer_device, "failed to create debugfs entries\n");
3454d3d5aa8SLars Ellenberg }
3464d3d5aa8SLars Ellenberg 
3474d3d5aa8SLars Ellenberg void drbd_debugfs_peer_device_cleanup(struct drbd_peer_device *peer_device)
3484d3d5aa8SLars Ellenberg {
3494d3d5aa8SLars Ellenberg 	drbd_debugfs_remove(&peer_device->debugfs_peer_dev);
3504d3d5aa8SLars Ellenberg }
3514d3d5aa8SLars Ellenberg 
3524d3d5aa8SLars Ellenberg /* not __exit, may be indirectly called
3534d3d5aa8SLars Ellenberg  * from the module-load-failure path as well. */
3544d3d5aa8SLars Ellenberg void drbd_debugfs_cleanup(void)
3554d3d5aa8SLars Ellenberg {
3564d3d5aa8SLars Ellenberg 	drbd_debugfs_remove(&drbd_debugfs_resources);
3574d3d5aa8SLars Ellenberg 	drbd_debugfs_remove(&drbd_debugfs_minors);
3584d3d5aa8SLars Ellenberg 	drbd_debugfs_remove(&drbd_debugfs_root);
3594d3d5aa8SLars Ellenberg }
3604d3d5aa8SLars Ellenberg 
3614d3d5aa8SLars Ellenberg int __init drbd_debugfs_init(void)
3624d3d5aa8SLars Ellenberg {
3634d3d5aa8SLars Ellenberg 	struct dentry *dentry;
3644d3d5aa8SLars Ellenberg 
3654d3d5aa8SLars Ellenberg 	dentry = debugfs_create_dir("drbd", NULL);
3664d3d5aa8SLars Ellenberg 	if (IS_ERR_OR_NULL(dentry))
3674d3d5aa8SLars Ellenberg 		goto fail;
3684d3d5aa8SLars Ellenberg 	drbd_debugfs_root = dentry;
3694d3d5aa8SLars Ellenberg 
3704d3d5aa8SLars Ellenberg 	dentry = debugfs_create_dir("resources", drbd_debugfs_root);
3714d3d5aa8SLars Ellenberg 	if (IS_ERR_OR_NULL(dentry))
3724d3d5aa8SLars Ellenberg 		goto fail;
3734d3d5aa8SLars Ellenberg 	drbd_debugfs_resources = dentry;
3744d3d5aa8SLars Ellenberg 
3754d3d5aa8SLars Ellenberg 	dentry = debugfs_create_dir("minors", drbd_debugfs_root);
3764d3d5aa8SLars Ellenberg 	if (IS_ERR_OR_NULL(dentry))
3774d3d5aa8SLars Ellenberg 		goto fail;
3784d3d5aa8SLars Ellenberg 	drbd_debugfs_minors = dentry;
3794d3d5aa8SLars Ellenberg 	return 0;
3804d3d5aa8SLars Ellenberg 
3814d3d5aa8SLars Ellenberg fail:
3824d3d5aa8SLars Ellenberg 	drbd_debugfs_cleanup();
3834d3d5aa8SLars Ellenberg 	if (dentry)
3844d3d5aa8SLars Ellenberg 		return PTR_ERR(dentry);
3854d3d5aa8SLars Ellenberg 	else
3864d3d5aa8SLars Ellenberg 		return -EINVAL;
3874d3d5aa8SLars Ellenberg }
388