xref: /OK3568_Linux_fs/kernel/drivers/block/drbd/drbd_debugfs.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun #define pr_fmt(fmt) "drbd debugfs: " fmt
3*4882a593Smuzhiyun #include <linux/kernel.h>
4*4882a593Smuzhiyun #include <linux/module.h>
5*4882a593Smuzhiyun #include <linux/debugfs.h>
6*4882a593Smuzhiyun #include <linux/seq_file.h>
7*4882a593Smuzhiyun #include <linux/stat.h>
8*4882a593Smuzhiyun #include <linux/jiffies.h>
9*4882a593Smuzhiyun #include <linux/list.h>
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include "drbd_int.h"
12*4882a593Smuzhiyun #include "drbd_req.h"
13*4882a593Smuzhiyun #include "drbd_debugfs.h"
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun /**********************************************************************
17*4882a593Smuzhiyun  * Whenever you change the file format, remember to bump the version. *
18*4882a593Smuzhiyun  **********************************************************************/
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun static struct dentry *drbd_debugfs_root;
21*4882a593Smuzhiyun static struct dentry *drbd_debugfs_version;
22*4882a593Smuzhiyun static struct dentry *drbd_debugfs_resources;
23*4882a593Smuzhiyun static struct dentry *drbd_debugfs_minors;
24*4882a593Smuzhiyun 
seq_print_age_or_dash(struct seq_file * m,bool valid,unsigned long dt)25*4882a593Smuzhiyun static void seq_print_age_or_dash(struct seq_file *m, bool valid, unsigned long dt)
26*4882a593Smuzhiyun {
27*4882a593Smuzhiyun 	if (valid)
28*4882a593Smuzhiyun 		seq_printf(m, "\t%d", jiffies_to_msecs(dt));
29*4882a593Smuzhiyun 	else
30*4882a593Smuzhiyun 		seq_printf(m, "\t-");
31*4882a593Smuzhiyun }
32*4882a593Smuzhiyun 
__seq_print_rq_state_bit(struct seq_file * m,bool is_set,char * sep,const char * set_name,const char * unset_name)33*4882a593Smuzhiyun static void __seq_print_rq_state_bit(struct seq_file *m,
34*4882a593Smuzhiyun 	bool is_set, char *sep, const char *set_name, const char *unset_name)
35*4882a593Smuzhiyun {
36*4882a593Smuzhiyun 	if (is_set && set_name) {
37*4882a593Smuzhiyun 		seq_putc(m, *sep);
38*4882a593Smuzhiyun 		seq_puts(m, set_name);
39*4882a593Smuzhiyun 		*sep = '|';
40*4882a593Smuzhiyun 	} else if (!is_set && unset_name) {
41*4882a593Smuzhiyun 		seq_putc(m, *sep);
42*4882a593Smuzhiyun 		seq_puts(m, unset_name);
43*4882a593Smuzhiyun 		*sep = '|';
44*4882a593Smuzhiyun 	}
45*4882a593Smuzhiyun }
46*4882a593Smuzhiyun 
seq_print_rq_state_bit(struct seq_file * m,bool is_set,char * sep,const char * set_name)47*4882a593Smuzhiyun static void seq_print_rq_state_bit(struct seq_file *m,
48*4882a593Smuzhiyun 	bool is_set, char *sep, const char *set_name)
49*4882a593Smuzhiyun {
50*4882a593Smuzhiyun 	__seq_print_rq_state_bit(m, is_set, sep, set_name, NULL);
51*4882a593Smuzhiyun }
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun /* pretty print enum drbd_req_state_bits req->rq_state */
seq_print_request_state(struct seq_file * m,struct drbd_request * req)54*4882a593Smuzhiyun static void seq_print_request_state(struct seq_file *m, struct drbd_request *req)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun 	unsigned int s = req->rq_state;
57*4882a593Smuzhiyun 	char sep = ' ';
58*4882a593Smuzhiyun 	seq_printf(m, "\t0x%08x", s);
59*4882a593Smuzhiyun 	seq_printf(m, "\tmaster: %s", req->master_bio ? "pending" : "completed");
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun 	/* RQ_WRITE ignored, already reported */
62*4882a593Smuzhiyun 	seq_puts(m, "\tlocal:");
63*4882a593Smuzhiyun 	seq_print_rq_state_bit(m, s & RQ_IN_ACT_LOG, &sep, "in-AL");
64*4882a593Smuzhiyun 	seq_print_rq_state_bit(m, s & RQ_POSTPONED, &sep, "postponed");
65*4882a593Smuzhiyun 	seq_print_rq_state_bit(m, s & RQ_COMPLETION_SUSP, &sep, "suspended");
66*4882a593Smuzhiyun 	sep = ' ';
67*4882a593Smuzhiyun 	seq_print_rq_state_bit(m, s & RQ_LOCAL_PENDING, &sep, "pending");
68*4882a593Smuzhiyun 	seq_print_rq_state_bit(m, s & RQ_LOCAL_COMPLETED, &sep, "completed");
69*4882a593Smuzhiyun 	seq_print_rq_state_bit(m, s & RQ_LOCAL_ABORTED, &sep, "aborted");
70*4882a593Smuzhiyun 	seq_print_rq_state_bit(m, s & RQ_LOCAL_OK, &sep, "ok");
71*4882a593Smuzhiyun 	if (sep == ' ')
72*4882a593Smuzhiyun 		seq_puts(m, " -");
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 	/* for_each_connection ... */
75*4882a593Smuzhiyun 	seq_printf(m, "\tnet:");
76*4882a593Smuzhiyun 	sep = ' ';
77*4882a593Smuzhiyun 	seq_print_rq_state_bit(m, s & RQ_NET_PENDING, &sep, "pending");
78*4882a593Smuzhiyun 	seq_print_rq_state_bit(m, s & RQ_NET_QUEUED, &sep, "queued");
79*4882a593Smuzhiyun 	seq_print_rq_state_bit(m, s & RQ_NET_SENT, &sep, "sent");
80*4882a593Smuzhiyun 	seq_print_rq_state_bit(m, s & RQ_NET_DONE, &sep, "done");
81*4882a593Smuzhiyun 	seq_print_rq_state_bit(m, s & RQ_NET_SIS, &sep, "sis");
82*4882a593Smuzhiyun 	seq_print_rq_state_bit(m, s & RQ_NET_OK, &sep, "ok");
83*4882a593Smuzhiyun 	if (sep == ' ')
84*4882a593Smuzhiyun 		seq_puts(m, " -");
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 	seq_printf(m, " :");
87*4882a593Smuzhiyun 	sep = ' ';
88*4882a593Smuzhiyun 	seq_print_rq_state_bit(m, s & RQ_EXP_RECEIVE_ACK, &sep, "B");
89*4882a593Smuzhiyun 	seq_print_rq_state_bit(m, s & RQ_EXP_WRITE_ACK, &sep, "C");
90*4882a593Smuzhiyun 	seq_print_rq_state_bit(m, s & RQ_EXP_BARR_ACK, &sep, "barr");
91*4882a593Smuzhiyun 	if (sep == ' ')
92*4882a593Smuzhiyun 		seq_puts(m, " -");
93*4882a593Smuzhiyun 	seq_printf(m, "\n");
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun 
seq_print_one_request(struct seq_file * m,struct drbd_request * req,unsigned long now)96*4882a593Smuzhiyun static void seq_print_one_request(struct seq_file *m, struct drbd_request *req, unsigned long now)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun 	/* change anything here, fixup header below! */
99*4882a593Smuzhiyun 	unsigned int s = req->rq_state;
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun #define RQ_HDR_1 "epoch\tsector\tsize\trw"
102*4882a593Smuzhiyun 	seq_printf(m, "0x%x\t%llu\t%u\t%s",
103*4882a593Smuzhiyun 		req->epoch,
104*4882a593Smuzhiyun 		(unsigned long long)req->i.sector, req->i.size >> 9,
105*4882a593Smuzhiyun 		(s & RQ_WRITE) ? "W" : "R");
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun #define RQ_HDR_2 "\tstart\tin AL\tsubmit"
108*4882a593Smuzhiyun 	seq_printf(m, "\t%d", jiffies_to_msecs(now - req->start_jif));
109*4882a593Smuzhiyun 	seq_print_age_or_dash(m, s & RQ_IN_ACT_LOG, now - req->in_actlog_jif);
110*4882a593Smuzhiyun 	seq_print_age_or_dash(m, s & RQ_LOCAL_PENDING, now - req->pre_submit_jif);
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun #define RQ_HDR_3 "\tsent\tacked\tdone"
113*4882a593Smuzhiyun 	seq_print_age_or_dash(m, s & RQ_NET_SENT, now - req->pre_send_jif);
114*4882a593Smuzhiyun 	seq_print_age_or_dash(m, (s & RQ_NET_SENT) && !(s & RQ_NET_PENDING), now - req->acked_jif);
115*4882a593Smuzhiyun 	seq_print_age_or_dash(m, s & RQ_NET_DONE, now - req->net_done_jif);
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun #define RQ_HDR_4 "\tstate\n"
118*4882a593Smuzhiyun 	seq_print_request_state(m, req);
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun #define RQ_HDR RQ_HDR_1 RQ_HDR_2 RQ_HDR_3 RQ_HDR_4
121*4882a593Smuzhiyun 
seq_print_minor_vnr_req(struct seq_file * m,struct drbd_request * req,unsigned long now)122*4882a593Smuzhiyun static void seq_print_minor_vnr_req(struct seq_file *m, struct drbd_request *req, unsigned long now)
123*4882a593Smuzhiyun {
124*4882a593Smuzhiyun 	seq_printf(m, "%u\t%u\t", req->device->minor, req->device->vnr);
125*4882a593Smuzhiyun 	seq_print_one_request(m, req, now);
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun 
seq_print_resource_pending_meta_io(struct seq_file * m,struct drbd_resource * resource,unsigned long now)128*4882a593Smuzhiyun static void seq_print_resource_pending_meta_io(struct seq_file *m, struct drbd_resource *resource, unsigned long now)
129*4882a593Smuzhiyun {
130*4882a593Smuzhiyun 	struct drbd_device *device;
131*4882a593Smuzhiyun 	unsigned int i;
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	seq_puts(m, "minor\tvnr\tstart\tsubmit\tintent\n");
134*4882a593Smuzhiyun 	rcu_read_lock();
135*4882a593Smuzhiyun 	idr_for_each_entry(&resource->devices, device, i) {
136*4882a593Smuzhiyun 		struct drbd_md_io tmp;
137*4882a593Smuzhiyun 		/* In theory this is racy,
138*4882a593Smuzhiyun 		 * in the sense that there could have been a
139*4882a593Smuzhiyun 		 * drbd_md_put_buffer(); drbd_md_get_buffer();
140*4882a593Smuzhiyun 		 * between accessing these members here.  */
141*4882a593Smuzhiyun 		tmp = device->md_io;
142*4882a593Smuzhiyun 		if (atomic_read(&tmp.in_use)) {
143*4882a593Smuzhiyun 			seq_printf(m, "%u\t%u\t%d\t",
144*4882a593Smuzhiyun 				device->minor, device->vnr,
145*4882a593Smuzhiyun 				jiffies_to_msecs(now - tmp.start_jif));
146*4882a593Smuzhiyun 			if (time_before(tmp.submit_jif, tmp.start_jif))
147*4882a593Smuzhiyun 				seq_puts(m, "-\t");
148*4882a593Smuzhiyun 			else
149*4882a593Smuzhiyun 				seq_printf(m, "%d\t", jiffies_to_msecs(now - tmp.submit_jif));
150*4882a593Smuzhiyun 			seq_printf(m, "%s\n", tmp.current_use);
151*4882a593Smuzhiyun 		}
152*4882a593Smuzhiyun 	}
153*4882a593Smuzhiyun 	rcu_read_unlock();
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun 
seq_print_waiting_for_AL(struct seq_file * m,struct drbd_resource * resource,unsigned long now)156*4882a593Smuzhiyun static void seq_print_waiting_for_AL(struct seq_file *m, struct drbd_resource *resource, unsigned long now)
157*4882a593Smuzhiyun {
158*4882a593Smuzhiyun 	struct drbd_device *device;
159*4882a593Smuzhiyun 	unsigned int i;
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	seq_puts(m, "minor\tvnr\tage\t#waiting\n");
162*4882a593Smuzhiyun 	rcu_read_lock();
163*4882a593Smuzhiyun 	idr_for_each_entry(&resource->devices, device, i) {
164*4882a593Smuzhiyun 		unsigned long jif;
165*4882a593Smuzhiyun 		struct drbd_request *req;
166*4882a593Smuzhiyun 		int n = atomic_read(&device->ap_actlog_cnt);
167*4882a593Smuzhiyun 		if (n) {
168*4882a593Smuzhiyun 			spin_lock_irq(&device->resource->req_lock);
169*4882a593Smuzhiyun 			req = list_first_entry_or_null(&device->pending_master_completion[1],
170*4882a593Smuzhiyun 				struct drbd_request, req_pending_master_completion);
171*4882a593Smuzhiyun 			/* if the oldest request does not wait for the activity log
172*4882a593Smuzhiyun 			 * it is not interesting for us here */
173*4882a593Smuzhiyun 			if (req && !(req->rq_state & RQ_IN_ACT_LOG))
174*4882a593Smuzhiyun 				jif = req->start_jif;
175*4882a593Smuzhiyun 			else
176*4882a593Smuzhiyun 				req = NULL;
177*4882a593Smuzhiyun 			spin_unlock_irq(&device->resource->req_lock);
178*4882a593Smuzhiyun 		}
179*4882a593Smuzhiyun 		if (n) {
180*4882a593Smuzhiyun 			seq_printf(m, "%u\t%u\t", device->minor, device->vnr);
181*4882a593Smuzhiyun 			if (req)
182*4882a593Smuzhiyun 				seq_printf(m, "%u\t", jiffies_to_msecs(now - jif));
183*4882a593Smuzhiyun 			else
184*4882a593Smuzhiyun 				seq_puts(m, "-\t");
185*4882a593Smuzhiyun 			seq_printf(m, "%u\n", n);
186*4882a593Smuzhiyun 		}
187*4882a593Smuzhiyun 	}
188*4882a593Smuzhiyun 	rcu_read_unlock();
189*4882a593Smuzhiyun }
190*4882a593Smuzhiyun 
seq_print_device_bitmap_io(struct seq_file * m,struct drbd_device * device,unsigned long now)191*4882a593Smuzhiyun static void seq_print_device_bitmap_io(struct seq_file *m, struct drbd_device *device, unsigned long now)
192*4882a593Smuzhiyun {
193*4882a593Smuzhiyun 	struct drbd_bm_aio_ctx *ctx;
194*4882a593Smuzhiyun 	unsigned long start_jif;
195*4882a593Smuzhiyun 	unsigned int in_flight;
196*4882a593Smuzhiyun 	unsigned int flags;
197*4882a593Smuzhiyun 	spin_lock_irq(&device->resource->req_lock);
198*4882a593Smuzhiyun 	ctx = list_first_entry_or_null(&device->pending_bitmap_io, struct drbd_bm_aio_ctx, list);
199*4882a593Smuzhiyun 	if (ctx && ctx->done)
200*4882a593Smuzhiyun 		ctx = NULL;
201*4882a593Smuzhiyun 	if (ctx) {
202*4882a593Smuzhiyun 		start_jif = ctx->start_jif;
203*4882a593Smuzhiyun 		in_flight = atomic_read(&ctx->in_flight);
204*4882a593Smuzhiyun 		flags = ctx->flags;
205*4882a593Smuzhiyun 	}
206*4882a593Smuzhiyun 	spin_unlock_irq(&device->resource->req_lock);
207*4882a593Smuzhiyun 	if (ctx) {
208*4882a593Smuzhiyun 		seq_printf(m, "%u\t%u\t%c\t%u\t%u\n",
209*4882a593Smuzhiyun 			device->minor, device->vnr,
210*4882a593Smuzhiyun 			(flags & BM_AIO_READ) ? 'R' : 'W',
211*4882a593Smuzhiyun 			jiffies_to_msecs(now - start_jif),
212*4882a593Smuzhiyun 			in_flight);
213*4882a593Smuzhiyun 	}
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun 
seq_print_resource_pending_bitmap_io(struct seq_file * m,struct drbd_resource * resource,unsigned long now)216*4882a593Smuzhiyun static void seq_print_resource_pending_bitmap_io(struct seq_file *m, struct drbd_resource *resource, unsigned long now)
217*4882a593Smuzhiyun {
218*4882a593Smuzhiyun 	struct drbd_device *device;
219*4882a593Smuzhiyun 	unsigned int i;
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 	seq_puts(m, "minor\tvnr\trw\tage\t#in-flight\n");
222*4882a593Smuzhiyun 	rcu_read_lock();
223*4882a593Smuzhiyun 	idr_for_each_entry(&resource->devices, device, i) {
224*4882a593Smuzhiyun 		seq_print_device_bitmap_io(m, device, now);
225*4882a593Smuzhiyun 	}
226*4882a593Smuzhiyun 	rcu_read_unlock();
227*4882a593Smuzhiyun }
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun /* pretty print enum peer_req->flags */
seq_print_peer_request_flags(struct seq_file * m,struct drbd_peer_request * peer_req)230*4882a593Smuzhiyun static void seq_print_peer_request_flags(struct seq_file *m, struct drbd_peer_request *peer_req)
231*4882a593Smuzhiyun {
232*4882a593Smuzhiyun 	unsigned long f = peer_req->flags;
233*4882a593Smuzhiyun 	char sep = ' ';
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 	__seq_print_rq_state_bit(m, f & EE_SUBMITTED, &sep, "submitted", "preparing");
236*4882a593Smuzhiyun 	__seq_print_rq_state_bit(m, f & EE_APPLICATION, &sep, "application", "internal");
237*4882a593Smuzhiyun 	seq_print_rq_state_bit(m, f & EE_CALL_AL_COMPLETE_IO, &sep, "in-AL");
238*4882a593Smuzhiyun 	seq_print_rq_state_bit(m, f & EE_SEND_WRITE_ACK, &sep, "C");
239*4882a593Smuzhiyun 	seq_print_rq_state_bit(m, f & EE_MAY_SET_IN_SYNC, &sep, "set-in-sync");
240*4882a593Smuzhiyun 	seq_print_rq_state_bit(m, f & EE_TRIM, &sep, "trim");
241*4882a593Smuzhiyun 	seq_print_rq_state_bit(m, f & EE_ZEROOUT, &sep, "zero-out");
242*4882a593Smuzhiyun 	seq_print_rq_state_bit(m, f & EE_WRITE_SAME, &sep, "write-same");
243*4882a593Smuzhiyun 	seq_putc(m, '\n');
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun 
seq_print_peer_request(struct seq_file * m,struct drbd_device * device,struct list_head * lh,unsigned long now)246*4882a593Smuzhiyun static void seq_print_peer_request(struct seq_file *m,
247*4882a593Smuzhiyun 	struct drbd_device *device, struct list_head *lh,
248*4882a593Smuzhiyun 	unsigned long now)
249*4882a593Smuzhiyun {
250*4882a593Smuzhiyun 	bool reported_preparing = false;
251*4882a593Smuzhiyun 	struct drbd_peer_request *peer_req;
252*4882a593Smuzhiyun 	list_for_each_entry(peer_req, lh, w.list) {
253*4882a593Smuzhiyun 		if (reported_preparing && !(peer_req->flags & EE_SUBMITTED))
254*4882a593Smuzhiyun 			continue;
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 		if (device)
257*4882a593Smuzhiyun 			seq_printf(m, "%u\t%u\t", device->minor, device->vnr);
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 		seq_printf(m, "%llu\t%u\t%c\t%u\t",
260*4882a593Smuzhiyun 			(unsigned long long)peer_req->i.sector, peer_req->i.size >> 9,
261*4882a593Smuzhiyun 			(peer_req->flags & EE_WRITE) ? 'W' : 'R',
262*4882a593Smuzhiyun 			jiffies_to_msecs(now - peer_req->submit_jif));
263*4882a593Smuzhiyun 		seq_print_peer_request_flags(m, peer_req);
264*4882a593Smuzhiyun 		if (peer_req->flags & EE_SUBMITTED)
265*4882a593Smuzhiyun 			break;
266*4882a593Smuzhiyun 		else
267*4882a593Smuzhiyun 			reported_preparing = true;
268*4882a593Smuzhiyun 	}
269*4882a593Smuzhiyun }
270*4882a593Smuzhiyun 
seq_print_device_peer_requests(struct seq_file * m,struct drbd_device * device,unsigned long now)271*4882a593Smuzhiyun static void seq_print_device_peer_requests(struct seq_file *m,
272*4882a593Smuzhiyun 	struct drbd_device *device, unsigned long now)
273*4882a593Smuzhiyun {
274*4882a593Smuzhiyun 	seq_puts(m, "minor\tvnr\tsector\tsize\trw\tage\tflags\n");
275*4882a593Smuzhiyun 	spin_lock_irq(&device->resource->req_lock);
276*4882a593Smuzhiyun 	seq_print_peer_request(m, device, &device->active_ee, now);
277*4882a593Smuzhiyun 	seq_print_peer_request(m, device, &device->read_ee, now);
278*4882a593Smuzhiyun 	seq_print_peer_request(m, device, &device->sync_ee, now);
279*4882a593Smuzhiyun 	spin_unlock_irq(&device->resource->req_lock);
280*4882a593Smuzhiyun 	if (test_bit(FLUSH_PENDING, &device->flags)) {
281*4882a593Smuzhiyun 		seq_printf(m, "%u\t%u\t-\t-\tF\t%u\tflush\n",
282*4882a593Smuzhiyun 			device->minor, device->vnr,
283*4882a593Smuzhiyun 			jiffies_to_msecs(now - device->flush_jif));
284*4882a593Smuzhiyun 	}
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun 
seq_print_resource_pending_peer_requests(struct seq_file * m,struct drbd_resource * resource,unsigned long now)287*4882a593Smuzhiyun static void seq_print_resource_pending_peer_requests(struct seq_file *m,
288*4882a593Smuzhiyun 	struct drbd_resource *resource, unsigned long now)
289*4882a593Smuzhiyun {
290*4882a593Smuzhiyun 	struct drbd_device *device;
291*4882a593Smuzhiyun 	unsigned int i;
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	rcu_read_lock();
294*4882a593Smuzhiyun 	idr_for_each_entry(&resource->devices, device, i) {
295*4882a593Smuzhiyun 		seq_print_device_peer_requests(m, device, now);
296*4882a593Smuzhiyun 	}
297*4882a593Smuzhiyun 	rcu_read_unlock();
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun 
seq_print_resource_transfer_log_summary(struct seq_file * m,struct drbd_resource * resource,struct drbd_connection * connection,unsigned long now)300*4882a593Smuzhiyun static void seq_print_resource_transfer_log_summary(struct seq_file *m,
301*4882a593Smuzhiyun 	struct drbd_resource *resource,
302*4882a593Smuzhiyun 	struct drbd_connection *connection,
303*4882a593Smuzhiyun 	unsigned long now)
304*4882a593Smuzhiyun {
305*4882a593Smuzhiyun 	struct drbd_request *req;
306*4882a593Smuzhiyun 	unsigned int count = 0;
307*4882a593Smuzhiyun 	unsigned int show_state = 0;
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 	seq_puts(m, "n\tdevice\tvnr\t" RQ_HDR);
310*4882a593Smuzhiyun 	spin_lock_irq(&resource->req_lock);
311*4882a593Smuzhiyun 	list_for_each_entry(req, &connection->transfer_log, tl_requests) {
312*4882a593Smuzhiyun 		unsigned int tmp = 0;
313*4882a593Smuzhiyun 		unsigned int s;
314*4882a593Smuzhiyun 		++count;
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun 		/* don't disable irq "forever" */
317*4882a593Smuzhiyun 		if (!(count & 0x1ff)) {
318*4882a593Smuzhiyun 			struct drbd_request *req_next;
319*4882a593Smuzhiyun 			kref_get(&req->kref);
320*4882a593Smuzhiyun 			spin_unlock_irq(&resource->req_lock);
321*4882a593Smuzhiyun 			cond_resched();
322*4882a593Smuzhiyun 			spin_lock_irq(&resource->req_lock);
323*4882a593Smuzhiyun 			req_next = list_next_entry(req, tl_requests);
324*4882a593Smuzhiyun 			if (kref_put(&req->kref, drbd_req_destroy))
325*4882a593Smuzhiyun 				req = req_next;
326*4882a593Smuzhiyun 			if (&req->tl_requests == &connection->transfer_log)
327*4882a593Smuzhiyun 				break;
328*4882a593Smuzhiyun 		}
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 		s = req->rq_state;
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 		/* This is meant to summarize timing issues, to be able to tell
333*4882a593Smuzhiyun 		 * local disk problems from network problems.
334*4882a593Smuzhiyun 		 * Skip requests, if we have shown an even older request with
335*4882a593Smuzhiyun 		 * similar aspects already.  */
336*4882a593Smuzhiyun 		if (req->master_bio == NULL)
337*4882a593Smuzhiyun 			tmp |= 1;
338*4882a593Smuzhiyun 		if ((s & RQ_LOCAL_MASK) && (s & RQ_LOCAL_PENDING))
339*4882a593Smuzhiyun 			tmp |= 2;
340*4882a593Smuzhiyun 		if (s & RQ_NET_MASK) {
341*4882a593Smuzhiyun 			if (!(s & RQ_NET_SENT))
342*4882a593Smuzhiyun 				tmp |= 4;
343*4882a593Smuzhiyun 			if (s & RQ_NET_PENDING)
344*4882a593Smuzhiyun 				tmp |= 8;
345*4882a593Smuzhiyun 			if (!(s & RQ_NET_DONE))
346*4882a593Smuzhiyun 				tmp |= 16;
347*4882a593Smuzhiyun 		}
348*4882a593Smuzhiyun 		if ((tmp & show_state) == tmp)
349*4882a593Smuzhiyun 			continue;
350*4882a593Smuzhiyun 		show_state |= tmp;
351*4882a593Smuzhiyun 		seq_printf(m, "%u\t", count);
352*4882a593Smuzhiyun 		seq_print_minor_vnr_req(m, req, now);
353*4882a593Smuzhiyun 		if (show_state == 0x1f)
354*4882a593Smuzhiyun 			break;
355*4882a593Smuzhiyun 	}
356*4882a593Smuzhiyun 	spin_unlock_irq(&resource->req_lock);
357*4882a593Smuzhiyun }
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun /* TODO: transfer_log and friends should be moved to resource */
in_flight_summary_show(struct seq_file * m,void * pos)360*4882a593Smuzhiyun static int in_flight_summary_show(struct seq_file *m, void *pos)
361*4882a593Smuzhiyun {
362*4882a593Smuzhiyun 	struct drbd_resource *resource = m->private;
363*4882a593Smuzhiyun 	struct drbd_connection *connection;
364*4882a593Smuzhiyun 	unsigned long jif = jiffies;
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	connection = first_connection(resource);
367*4882a593Smuzhiyun 	/* This does not happen, actually.
368*4882a593Smuzhiyun 	 * But be robust and prepare for future code changes. */
369*4882a593Smuzhiyun 	if (!connection || !kref_get_unless_zero(&connection->kref))
370*4882a593Smuzhiyun 		return -ESTALE;
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	/* BUMP me if you change the file format/content/presentation */
373*4882a593Smuzhiyun 	seq_printf(m, "v: %u\n\n", 0);
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 	seq_puts(m, "oldest bitmap IO\n");
376*4882a593Smuzhiyun 	seq_print_resource_pending_bitmap_io(m, resource, jif);
377*4882a593Smuzhiyun 	seq_putc(m, '\n');
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 	seq_puts(m, "meta data IO\n");
380*4882a593Smuzhiyun 	seq_print_resource_pending_meta_io(m, resource, jif);
381*4882a593Smuzhiyun 	seq_putc(m, '\n');
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun 	seq_puts(m, "socket buffer stats\n");
384*4882a593Smuzhiyun 	/* for each connection ... once we have more than one */
385*4882a593Smuzhiyun 	rcu_read_lock();
386*4882a593Smuzhiyun 	if (connection->data.socket) {
387*4882a593Smuzhiyun 		/* open coded SIOCINQ, the "relevant" part */
388*4882a593Smuzhiyun 		struct tcp_sock *tp = tcp_sk(connection->data.socket->sk);
389*4882a593Smuzhiyun 		int answ = tp->rcv_nxt - tp->copied_seq;
390*4882a593Smuzhiyun 		seq_printf(m, "unread receive buffer: %u Byte\n", answ);
391*4882a593Smuzhiyun 		/* open coded SIOCOUTQ, the "relevant" part */
392*4882a593Smuzhiyun 		answ = tp->write_seq - tp->snd_una;
393*4882a593Smuzhiyun 		seq_printf(m, "unacked send buffer: %u Byte\n", answ);
394*4882a593Smuzhiyun 	}
395*4882a593Smuzhiyun 	rcu_read_unlock();
396*4882a593Smuzhiyun 	seq_putc(m, '\n');
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun 	seq_puts(m, "oldest peer requests\n");
399*4882a593Smuzhiyun 	seq_print_resource_pending_peer_requests(m, resource, jif);
400*4882a593Smuzhiyun 	seq_putc(m, '\n');
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun 	seq_puts(m, "application requests waiting for activity log\n");
403*4882a593Smuzhiyun 	seq_print_waiting_for_AL(m, resource, jif);
404*4882a593Smuzhiyun 	seq_putc(m, '\n');
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 	seq_puts(m, "oldest application requests\n");
407*4882a593Smuzhiyun 	seq_print_resource_transfer_log_summary(m, resource, connection, jif);
408*4882a593Smuzhiyun 	seq_putc(m, '\n');
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun 	jif = jiffies - jif;
411*4882a593Smuzhiyun 	if (jif)
412*4882a593Smuzhiyun 		seq_printf(m, "generated in %d ms\n", jiffies_to_msecs(jif));
413*4882a593Smuzhiyun 	kref_put(&connection->kref, drbd_destroy_connection);
414*4882a593Smuzhiyun 	return 0;
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun /* make sure at *open* time that the respective object won't go away. */
drbd_single_open(struct file * file,int (* show)(struct seq_file *,void *),void * data,struct kref * kref,void (* release)(struct kref *))418*4882a593Smuzhiyun static int drbd_single_open(struct file *file, int (*show)(struct seq_file *, void *),
419*4882a593Smuzhiyun 		                void *data, struct kref *kref,
420*4882a593Smuzhiyun 				void (*release)(struct kref *))
421*4882a593Smuzhiyun {
422*4882a593Smuzhiyun 	struct dentry *parent;
423*4882a593Smuzhiyun 	int ret = -ESTALE;
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun 	/* Are we still linked,
426*4882a593Smuzhiyun 	 * or has debugfs_remove() already been called? */
427*4882a593Smuzhiyun 	parent = file->f_path.dentry->d_parent;
428*4882a593Smuzhiyun 	/* serialize with d_delete() */
429*4882a593Smuzhiyun 	inode_lock(d_inode(parent));
430*4882a593Smuzhiyun 	/* Make sure the object is still alive */
431*4882a593Smuzhiyun 	if (simple_positive(file->f_path.dentry)
432*4882a593Smuzhiyun 	&& kref_get_unless_zero(kref))
433*4882a593Smuzhiyun 		ret = 0;
434*4882a593Smuzhiyun 	inode_unlock(d_inode(parent));
435*4882a593Smuzhiyun 	if (!ret) {
436*4882a593Smuzhiyun 		ret = single_open(file, show, data);
437*4882a593Smuzhiyun 		if (ret)
438*4882a593Smuzhiyun 			kref_put(kref, release);
439*4882a593Smuzhiyun 	}
440*4882a593Smuzhiyun 	return ret;
441*4882a593Smuzhiyun }
442*4882a593Smuzhiyun 
in_flight_summary_open(struct inode * inode,struct file * file)443*4882a593Smuzhiyun static int in_flight_summary_open(struct inode *inode, struct file *file)
444*4882a593Smuzhiyun {
445*4882a593Smuzhiyun 	struct drbd_resource *resource = inode->i_private;
446*4882a593Smuzhiyun 	return drbd_single_open(file, in_flight_summary_show, resource,
447*4882a593Smuzhiyun 				&resource->kref, drbd_destroy_resource);
448*4882a593Smuzhiyun }
449*4882a593Smuzhiyun 
in_flight_summary_release(struct inode * inode,struct file * file)450*4882a593Smuzhiyun static int in_flight_summary_release(struct inode *inode, struct file *file)
451*4882a593Smuzhiyun {
452*4882a593Smuzhiyun 	struct drbd_resource *resource = inode->i_private;
453*4882a593Smuzhiyun 	kref_put(&resource->kref, drbd_destroy_resource);
454*4882a593Smuzhiyun 	return single_release(inode, file);
455*4882a593Smuzhiyun }
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun static const struct file_operations in_flight_summary_fops = {
458*4882a593Smuzhiyun 	.owner		= THIS_MODULE,
459*4882a593Smuzhiyun 	.open		= in_flight_summary_open,
460*4882a593Smuzhiyun 	.read		= seq_read,
461*4882a593Smuzhiyun 	.llseek		= seq_lseek,
462*4882a593Smuzhiyun 	.release	= in_flight_summary_release,
463*4882a593Smuzhiyun };
464*4882a593Smuzhiyun 
drbd_debugfs_resource_add(struct drbd_resource * resource)465*4882a593Smuzhiyun void drbd_debugfs_resource_add(struct drbd_resource *resource)
466*4882a593Smuzhiyun {
467*4882a593Smuzhiyun 	struct dentry *dentry;
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun 	dentry = debugfs_create_dir(resource->name, drbd_debugfs_resources);
470*4882a593Smuzhiyun 	resource->debugfs_res = dentry;
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 	dentry = debugfs_create_dir("volumes", resource->debugfs_res);
473*4882a593Smuzhiyun 	resource->debugfs_res_volumes = dentry;
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun 	dentry = debugfs_create_dir("connections", resource->debugfs_res);
476*4882a593Smuzhiyun 	resource->debugfs_res_connections = dentry;
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun 	dentry = debugfs_create_file("in_flight_summary", 0440,
479*4882a593Smuzhiyun 				     resource->debugfs_res, resource,
480*4882a593Smuzhiyun 				     &in_flight_summary_fops);
481*4882a593Smuzhiyun 	resource->debugfs_res_in_flight_summary = dentry;
482*4882a593Smuzhiyun }
483*4882a593Smuzhiyun 
drbd_debugfs_remove(struct dentry ** dp)484*4882a593Smuzhiyun static void drbd_debugfs_remove(struct dentry **dp)
485*4882a593Smuzhiyun {
486*4882a593Smuzhiyun 	debugfs_remove(*dp);
487*4882a593Smuzhiyun 	*dp = NULL;
488*4882a593Smuzhiyun }
489*4882a593Smuzhiyun 
drbd_debugfs_resource_cleanup(struct drbd_resource * resource)490*4882a593Smuzhiyun void drbd_debugfs_resource_cleanup(struct drbd_resource *resource)
491*4882a593Smuzhiyun {
492*4882a593Smuzhiyun 	/* it is ok to call debugfs_remove(NULL) */
493*4882a593Smuzhiyun 	drbd_debugfs_remove(&resource->debugfs_res_in_flight_summary);
494*4882a593Smuzhiyun 	drbd_debugfs_remove(&resource->debugfs_res_connections);
495*4882a593Smuzhiyun 	drbd_debugfs_remove(&resource->debugfs_res_volumes);
496*4882a593Smuzhiyun 	drbd_debugfs_remove(&resource->debugfs_res);
497*4882a593Smuzhiyun }
498*4882a593Smuzhiyun 
seq_print_one_timing_detail(struct seq_file * m,const struct drbd_thread_timing_details * tdp,unsigned long now)499*4882a593Smuzhiyun static void seq_print_one_timing_detail(struct seq_file *m,
500*4882a593Smuzhiyun 	const struct drbd_thread_timing_details *tdp,
501*4882a593Smuzhiyun 	unsigned long now)
502*4882a593Smuzhiyun {
503*4882a593Smuzhiyun 	struct drbd_thread_timing_details td;
504*4882a593Smuzhiyun 	/* No locking...
505*4882a593Smuzhiyun 	 * use temporary assignment to get at consistent data. */
506*4882a593Smuzhiyun 	do {
507*4882a593Smuzhiyun 		td = *tdp;
508*4882a593Smuzhiyun 	} while (td.cb_nr != tdp->cb_nr);
509*4882a593Smuzhiyun 	if (!td.cb_addr)
510*4882a593Smuzhiyun 		return;
511*4882a593Smuzhiyun 	seq_printf(m, "%u\t%d\t%s:%u\t%ps\n",
512*4882a593Smuzhiyun 			td.cb_nr,
513*4882a593Smuzhiyun 			jiffies_to_msecs(now - td.start_jif),
514*4882a593Smuzhiyun 			td.caller_fn, td.line,
515*4882a593Smuzhiyun 			td.cb_addr);
516*4882a593Smuzhiyun }
517*4882a593Smuzhiyun 
seq_print_timing_details(struct seq_file * m,const char * title,unsigned int cb_nr,struct drbd_thread_timing_details * tdp,unsigned long now)518*4882a593Smuzhiyun static void seq_print_timing_details(struct seq_file *m,
519*4882a593Smuzhiyun 		const char *title,
520*4882a593Smuzhiyun 		unsigned int cb_nr, struct drbd_thread_timing_details *tdp, unsigned long now)
521*4882a593Smuzhiyun {
522*4882a593Smuzhiyun 	unsigned int start_idx;
523*4882a593Smuzhiyun 	unsigned int i;
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun 	seq_printf(m, "%s\n", title);
526*4882a593Smuzhiyun 	/* If not much is going on, this will result in natural ordering.
527*4882a593Smuzhiyun 	 * If it is very busy, we will possibly skip events, or even see wrap
528*4882a593Smuzhiyun 	 * arounds, which could only be avoided with locking.
529*4882a593Smuzhiyun 	 */
530*4882a593Smuzhiyun 	start_idx = cb_nr % DRBD_THREAD_DETAILS_HIST;
531*4882a593Smuzhiyun 	for (i = start_idx; i < DRBD_THREAD_DETAILS_HIST; i++)
532*4882a593Smuzhiyun 		seq_print_one_timing_detail(m, tdp+i, now);
533*4882a593Smuzhiyun 	for (i = 0; i < start_idx; i++)
534*4882a593Smuzhiyun 		seq_print_one_timing_detail(m, tdp+i, now);
535*4882a593Smuzhiyun }
536*4882a593Smuzhiyun 
callback_history_show(struct seq_file * m,void * ignored)537*4882a593Smuzhiyun static int callback_history_show(struct seq_file *m, void *ignored)
538*4882a593Smuzhiyun {
539*4882a593Smuzhiyun 	struct drbd_connection *connection = m->private;
540*4882a593Smuzhiyun 	unsigned long jif = jiffies;
541*4882a593Smuzhiyun 
542*4882a593Smuzhiyun 	/* BUMP me if you change the file format/content/presentation */
543*4882a593Smuzhiyun 	seq_printf(m, "v: %u\n\n", 0);
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun 	seq_puts(m, "n\tage\tcallsite\tfn\n");
546*4882a593Smuzhiyun 	seq_print_timing_details(m, "worker", connection->w_cb_nr, connection->w_timing_details, jif);
547*4882a593Smuzhiyun 	seq_print_timing_details(m, "receiver", connection->r_cb_nr, connection->r_timing_details, jif);
548*4882a593Smuzhiyun 	return 0;
549*4882a593Smuzhiyun }
550*4882a593Smuzhiyun 
callback_history_open(struct inode * inode,struct file * file)551*4882a593Smuzhiyun static int callback_history_open(struct inode *inode, struct file *file)
552*4882a593Smuzhiyun {
553*4882a593Smuzhiyun 	struct drbd_connection *connection = inode->i_private;
554*4882a593Smuzhiyun 	return drbd_single_open(file, callback_history_show, connection,
555*4882a593Smuzhiyun 				&connection->kref, drbd_destroy_connection);
556*4882a593Smuzhiyun }
557*4882a593Smuzhiyun 
callback_history_release(struct inode * inode,struct file * file)558*4882a593Smuzhiyun static int callback_history_release(struct inode *inode, struct file *file)
559*4882a593Smuzhiyun {
560*4882a593Smuzhiyun 	struct drbd_connection *connection = inode->i_private;
561*4882a593Smuzhiyun 	kref_put(&connection->kref, drbd_destroy_connection);
562*4882a593Smuzhiyun 	return single_release(inode, file);
563*4882a593Smuzhiyun }
564*4882a593Smuzhiyun 
565*4882a593Smuzhiyun static const struct file_operations connection_callback_history_fops = {
566*4882a593Smuzhiyun 	.owner		= THIS_MODULE,
567*4882a593Smuzhiyun 	.open		= callback_history_open,
568*4882a593Smuzhiyun 	.read		= seq_read,
569*4882a593Smuzhiyun 	.llseek		= seq_lseek,
570*4882a593Smuzhiyun 	.release	= callback_history_release,
571*4882a593Smuzhiyun };
572*4882a593Smuzhiyun 
connection_oldest_requests_show(struct seq_file * m,void * ignored)573*4882a593Smuzhiyun static int connection_oldest_requests_show(struct seq_file *m, void *ignored)
574*4882a593Smuzhiyun {
575*4882a593Smuzhiyun 	struct drbd_connection *connection = m->private;
576*4882a593Smuzhiyun 	unsigned long now = jiffies;
577*4882a593Smuzhiyun 	struct drbd_request *r1, *r2;
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun 	/* BUMP me if you change the file format/content/presentation */
580*4882a593Smuzhiyun 	seq_printf(m, "v: %u\n\n", 0);
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun 	spin_lock_irq(&connection->resource->req_lock);
583*4882a593Smuzhiyun 	r1 = connection->req_next;
584*4882a593Smuzhiyun 	if (r1)
585*4882a593Smuzhiyun 		seq_print_minor_vnr_req(m, r1, now);
586*4882a593Smuzhiyun 	r2 = connection->req_ack_pending;
587*4882a593Smuzhiyun 	if (r2 && r2 != r1) {
588*4882a593Smuzhiyun 		r1 = r2;
589*4882a593Smuzhiyun 		seq_print_minor_vnr_req(m, r1, now);
590*4882a593Smuzhiyun 	}
591*4882a593Smuzhiyun 	r2 = connection->req_not_net_done;
592*4882a593Smuzhiyun 	if (r2 && r2 != r1)
593*4882a593Smuzhiyun 		seq_print_minor_vnr_req(m, r2, now);
594*4882a593Smuzhiyun 	spin_unlock_irq(&connection->resource->req_lock);
595*4882a593Smuzhiyun 	return 0;
596*4882a593Smuzhiyun }
597*4882a593Smuzhiyun 
connection_oldest_requests_open(struct inode * inode,struct file * file)598*4882a593Smuzhiyun static int connection_oldest_requests_open(struct inode *inode, struct file *file)
599*4882a593Smuzhiyun {
600*4882a593Smuzhiyun 	struct drbd_connection *connection = inode->i_private;
601*4882a593Smuzhiyun 	return drbd_single_open(file, connection_oldest_requests_show, connection,
602*4882a593Smuzhiyun 				&connection->kref, drbd_destroy_connection);
603*4882a593Smuzhiyun }
604*4882a593Smuzhiyun 
connection_oldest_requests_release(struct inode * inode,struct file * file)605*4882a593Smuzhiyun static int connection_oldest_requests_release(struct inode *inode, struct file *file)
606*4882a593Smuzhiyun {
607*4882a593Smuzhiyun 	struct drbd_connection *connection = inode->i_private;
608*4882a593Smuzhiyun 	kref_put(&connection->kref, drbd_destroy_connection);
609*4882a593Smuzhiyun 	return single_release(inode, file);
610*4882a593Smuzhiyun }
611*4882a593Smuzhiyun 
612*4882a593Smuzhiyun static const struct file_operations connection_oldest_requests_fops = {
613*4882a593Smuzhiyun 	.owner		= THIS_MODULE,
614*4882a593Smuzhiyun 	.open		= connection_oldest_requests_open,
615*4882a593Smuzhiyun 	.read		= seq_read,
616*4882a593Smuzhiyun 	.llseek		= seq_lseek,
617*4882a593Smuzhiyun 	.release	= connection_oldest_requests_release,
618*4882a593Smuzhiyun };
619*4882a593Smuzhiyun 
drbd_debugfs_connection_add(struct drbd_connection * connection)620*4882a593Smuzhiyun void drbd_debugfs_connection_add(struct drbd_connection *connection)
621*4882a593Smuzhiyun {
622*4882a593Smuzhiyun 	struct dentry *conns_dir = connection->resource->debugfs_res_connections;
623*4882a593Smuzhiyun 	struct dentry *dentry;
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun 	/* Once we enable mutliple peers,
626*4882a593Smuzhiyun 	 * these connections will have descriptive names.
627*4882a593Smuzhiyun 	 * For now, it is just the one connection to the (only) "peer". */
628*4882a593Smuzhiyun 	dentry = debugfs_create_dir("peer", conns_dir);
629*4882a593Smuzhiyun 	connection->debugfs_conn = dentry;
630*4882a593Smuzhiyun 
631*4882a593Smuzhiyun 	dentry = debugfs_create_file("callback_history", 0440,
632*4882a593Smuzhiyun 				     connection->debugfs_conn, connection,
633*4882a593Smuzhiyun 				     &connection_callback_history_fops);
634*4882a593Smuzhiyun 	connection->debugfs_conn_callback_history = dentry;
635*4882a593Smuzhiyun 
636*4882a593Smuzhiyun 	dentry = debugfs_create_file("oldest_requests", 0440,
637*4882a593Smuzhiyun 				     connection->debugfs_conn, connection,
638*4882a593Smuzhiyun 				     &connection_oldest_requests_fops);
639*4882a593Smuzhiyun 	connection->debugfs_conn_oldest_requests = dentry;
640*4882a593Smuzhiyun }
641*4882a593Smuzhiyun 
drbd_debugfs_connection_cleanup(struct drbd_connection * connection)642*4882a593Smuzhiyun void drbd_debugfs_connection_cleanup(struct drbd_connection *connection)
643*4882a593Smuzhiyun {
644*4882a593Smuzhiyun 	drbd_debugfs_remove(&connection->debugfs_conn_callback_history);
645*4882a593Smuzhiyun 	drbd_debugfs_remove(&connection->debugfs_conn_oldest_requests);
646*4882a593Smuzhiyun 	drbd_debugfs_remove(&connection->debugfs_conn);
647*4882a593Smuzhiyun }
648*4882a593Smuzhiyun 
resync_dump_detail(struct seq_file * m,struct lc_element * e)649*4882a593Smuzhiyun static void resync_dump_detail(struct seq_file *m, struct lc_element *e)
650*4882a593Smuzhiyun {
651*4882a593Smuzhiyun        struct bm_extent *bme = lc_entry(e, struct bm_extent, lce);
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun        seq_printf(m, "%5d %s %s %s", bme->rs_left,
654*4882a593Smuzhiyun 		  test_bit(BME_NO_WRITES, &bme->flags) ? "NO_WRITES" : "---------",
655*4882a593Smuzhiyun 		  test_bit(BME_LOCKED, &bme->flags) ? "LOCKED" : "------",
656*4882a593Smuzhiyun 		  test_bit(BME_PRIORITY, &bme->flags) ? "PRIORITY" : "--------"
657*4882a593Smuzhiyun 		  );
658*4882a593Smuzhiyun }
659*4882a593Smuzhiyun 
device_resync_extents_show(struct seq_file * m,void * ignored)660*4882a593Smuzhiyun static int device_resync_extents_show(struct seq_file *m, void *ignored)
661*4882a593Smuzhiyun {
662*4882a593Smuzhiyun 	struct drbd_device *device = m->private;
663*4882a593Smuzhiyun 
664*4882a593Smuzhiyun 	/* BUMP me if you change the file format/content/presentation */
665*4882a593Smuzhiyun 	seq_printf(m, "v: %u\n\n", 0);
666*4882a593Smuzhiyun 
667*4882a593Smuzhiyun 	if (get_ldev_if_state(device, D_FAILED)) {
668*4882a593Smuzhiyun 		lc_seq_printf_stats(m, device->resync);
669*4882a593Smuzhiyun 		lc_seq_dump_details(m, device->resync, "rs_left flags", resync_dump_detail);
670*4882a593Smuzhiyun 		put_ldev(device);
671*4882a593Smuzhiyun 	}
672*4882a593Smuzhiyun 	return 0;
673*4882a593Smuzhiyun }
674*4882a593Smuzhiyun 
device_act_log_extents_show(struct seq_file * m,void * ignored)675*4882a593Smuzhiyun static int device_act_log_extents_show(struct seq_file *m, void *ignored)
676*4882a593Smuzhiyun {
677*4882a593Smuzhiyun 	struct drbd_device *device = m->private;
678*4882a593Smuzhiyun 
679*4882a593Smuzhiyun 	/* BUMP me if you change the file format/content/presentation */
680*4882a593Smuzhiyun 	seq_printf(m, "v: %u\n\n", 0);
681*4882a593Smuzhiyun 
682*4882a593Smuzhiyun 	if (get_ldev_if_state(device, D_FAILED)) {
683*4882a593Smuzhiyun 		lc_seq_printf_stats(m, device->act_log);
684*4882a593Smuzhiyun 		lc_seq_dump_details(m, device->act_log, "", NULL);
685*4882a593Smuzhiyun 		put_ldev(device);
686*4882a593Smuzhiyun 	}
687*4882a593Smuzhiyun 	return 0;
688*4882a593Smuzhiyun }
689*4882a593Smuzhiyun 
device_oldest_requests_show(struct seq_file * m,void * ignored)690*4882a593Smuzhiyun static int device_oldest_requests_show(struct seq_file *m, void *ignored)
691*4882a593Smuzhiyun {
692*4882a593Smuzhiyun 	struct drbd_device *device = m->private;
693*4882a593Smuzhiyun 	struct drbd_resource *resource = device->resource;
694*4882a593Smuzhiyun 	unsigned long now = jiffies;
695*4882a593Smuzhiyun 	struct drbd_request *r1, *r2;
696*4882a593Smuzhiyun 	int i;
697*4882a593Smuzhiyun 
698*4882a593Smuzhiyun 	/* BUMP me if you change the file format/content/presentation */
699*4882a593Smuzhiyun 	seq_printf(m, "v: %u\n\n", 0);
700*4882a593Smuzhiyun 
701*4882a593Smuzhiyun 	seq_puts(m, RQ_HDR);
702*4882a593Smuzhiyun 	spin_lock_irq(&resource->req_lock);
703*4882a593Smuzhiyun 	/* WRITE, then READ */
704*4882a593Smuzhiyun 	for (i = 1; i >= 0; --i) {
705*4882a593Smuzhiyun 		r1 = list_first_entry_or_null(&device->pending_master_completion[i],
706*4882a593Smuzhiyun 			struct drbd_request, req_pending_master_completion);
707*4882a593Smuzhiyun 		r2 = list_first_entry_or_null(&device->pending_completion[i],
708*4882a593Smuzhiyun 			struct drbd_request, req_pending_local);
709*4882a593Smuzhiyun 		if (r1)
710*4882a593Smuzhiyun 			seq_print_one_request(m, r1, now);
711*4882a593Smuzhiyun 		if (r2 && r2 != r1)
712*4882a593Smuzhiyun 			seq_print_one_request(m, r2, now);
713*4882a593Smuzhiyun 	}
714*4882a593Smuzhiyun 	spin_unlock_irq(&resource->req_lock);
715*4882a593Smuzhiyun 	return 0;
716*4882a593Smuzhiyun }
717*4882a593Smuzhiyun 
device_data_gen_id_show(struct seq_file * m,void * ignored)718*4882a593Smuzhiyun static int device_data_gen_id_show(struct seq_file *m, void *ignored)
719*4882a593Smuzhiyun {
720*4882a593Smuzhiyun 	struct drbd_device *device = m->private;
721*4882a593Smuzhiyun 	struct drbd_md *md;
722*4882a593Smuzhiyun 	enum drbd_uuid_index idx;
723*4882a593Smuzhiyun 
724*4882a593Smuzhiyun 	if (!get_ldev_if_state(device, D_FAILED))
725*4882a593Smuzhiyun 		return -ENODEV;
726*4882a593Smuzhiyun 
727*4882a593Smuzhiyun 	md = &device->ldev->md;
728*4882a593Smuzhiyun 	spin_lock_irq(&md->uuid_lock);
729*4882a593Smuzhiyun 	for (idx = UI_CURRENT; idx <= UI_HISTORY_END; idx++) {
730*4882a593Smuzhiyun 		seq_printf(m, "0x%016llX\n", md->uuid[idx]);
731*4882a593Smuzhiyun 	}
732*4882a593Smuzhiyun 	spin_unlock_irq(&md->uuid_lock);
733*4882a593Smuzhiyun 	put_ldev(device);
734*4882a593Smuzhiyun 	return 0;
735*4882a593Smuzhiyun }
736*4882a593Smuzhiyun 
device_ed_gen_id_show(struct seq_file * m,void * ignored)737*4882a593Smuzhiyun static int device_ed_gen_id_show(struct seq_file *m, void *ignored)
738*4882a593Smuzhiyun {
739*4882a593Smuzhiyun 	struct drbd_device *device = m->private;
740*4882a593Smuzhiyun 	seq_printf(m, "0x%016llX\n", (unsigned long long)device->ed_uuid);
741*4882a593Smuzhiyun 	return 0;
742*4882a593Smuzhiyun }
743*4882a593Smuzhiyun 
744*4882a593Smuzhiyun #define drbd_debugfs_device_attr(name)						\
745*4882a593Smuzhiyun static int device_ ## name ## _open(struct inode *inode, struct file *file)	\
746*4882a593Smuzhiyun {										\
747*4882a593Smuzhiyun 	struct drbd_device *device = inode->i_private;				\
748*4882a593Smuzhiyun 	return drbd_single_open(file, device_ ## name ## _show, device,		\
749*4882a593Smuzhiyun 				&device->kref, drbd_destroy_device);		\
750*4882a593Smuzhiyun }										\
751*4882a593Smuzhiyun static int device_ ## name ## _release(struct inode *inode, struct file *file)	\
752*4882a593Smuzhiyun {										\
753*4882a593Smuzhiyun 	struct drbd_device *device = inode->i_private;				\
754*4882a593Smuzhiyun 	kref_put(&device->kref, drbd_destroy_device);				\
755*4882a593Smuzhiyun 	return single_release(inode, file);					\
756*4882a593Smuzhiyun }										\
757*4882a593Smuzhiyun static const struct file_operations device_ ## name ## _fops = {		\
758*4882a593Smuzhiyun 	.owner		= THIS_MODULE,						\
759*4882a593Smuzhiyun 	.open		= device_ ## name ## _open,				\
760*4882a593Smuzhiyun 	.read		= seq_read,						\
761*4882a593Smuzhiyun 	.llseek		= seq_lseek,						\
762*4882a593Smuzhiyun 	.release	= device_ ## name ## _release,				\
763*4882a593Smuzhiyun };
764*4882a593Smuzhiyun 
765*4882a593Smuzhiyun drbd_debugfs_device_attr(oldest_requests)
drbd_debugfs_device_attr(act_log_extents)766*4882a593Smuzhiyun drbd_debugfs_device_attr(act_log_extents)
767*4882a593Smuzhiyun drbd_debugfs_device_attr(resync_extents)
768*4882a593Smuzhiyun drbd_debugfs_device_attr(data_gen_id)
769*4882a593Smuzhiyun drbd_debugfs_device_attr(ed_gen_id)
770*4882a593Smuzhiyun 
771*4882a593Smuzhiyun void drbd_debugfs_device_add(struct drbd_device *device)
772*4882a593Smuzhiyun {
773*4882a593Smuzhiyun 	struct dentry *vols_dir = device->resource->debugfs_res_volumes;
774*4882a593Smuzhiyun 	char minor_buf[8]; /* MINORMASK, MINORBITS == 20; */
775*4882a593Smuzhiyun 	char vnr_buf[8];   /* volume number vnr is even 16 bit only; */
776*4882a593Smuzhiyun 	char *slink_name = NULL;
777*4882a593Smuzhiyun 
778*4882a593Smuzhiyun 	struct dentry *dentry;
779*4882a593Smuzhiyun 	if (!vols_dir || !drbd_debugfs_minors)
780*4882a593Smuzhiyun 		return;
781*4882a593Smuzhiyun 
782*4882a593Smuzhiyun 	snprintf(vnr_buf, sizeof(vnr_buf), "%u", device->vnr);
783*4882a593Smuzhiyun 	dentry = debugfs_create_dir(vnr_buf, vols_dir);
784*4882a593Smuzhiyun 	device->debugfs_vol = dentry;
785*4882a593Smuzhiyun 
786*4882a593Smuzhiyun 	snprintf(minor_buf, sizeof(minor_buf), "%u", device->minor);
787*4882a593Smuzhiyun 	slink_name = kasprintf(GFP_KERNEL, "../resources/%s/volumes/%u",
788*4882a593Smuzhiyun 			device->resource->name, device->vnr);
789*4882a593Smuzhiyun 	if (!slink_name)
790*4882a593Smuzhiyun 		goto fail;
791*4882a593Smuzhiyun 	dentry = debugfs_create_symlink(minor_buf, drbd_debugfs_minors, slink_name);
792*4882a593Smuzhiyun 	device->debugfs_minor = dentry;
793*4882a593Smuzhiyun 	kfree(slink_name);
794*4882a593Smuzhiyun 	slink_name = NULL;
795*4882a593Smuzhiyun 
796*4882a593Smuzhiyun #define DCF(name)	do {					\
797*4882a593Smuzhiyun 	dentry = debugfs_create_file(#name, 0440,	\
798*4882a593Smuzhiyun 			device->debugfs_vol, device,		\
799*4882a593Smuzhiyun 			&device_ ## name ## _fops);		\
800*4882a593Smuzhiyun 	device->debugfs_vol_ ## name = dentry;			\
801*4882a593Smuzhiyun 	} while (0)
802*4882a593Smuzhiyun 
803*4882a593Smuzhiyun 	DCF(oldest_requests);
804*4882a593Smuzhiyun 	DCF(act_log_extents);
805*4882a593Smuzhiyun 	DCF(resync_extents);
806*4882a593Smuzhiyun 	DCF(data_gen_id);
807*4882a593Smuzhiyun 	DCF(ed_gen_id);
808*4882a593Smuzhiyun #undef DCF
809*4882a593Smuzhiyun 	return;
810*4882a593Smuzhiyun 
811*4882a593Smuzhiyun fail:
812*4882a593Smuzhiyun 	drbd_debugfs_device_cleanup(device);
813*4882a593Smuzhiyun 	drbd_err(device, "failed to create debugfs entries\n");
814*4882a593Smuzhiyun }
815*4882a593Smuzhiyun 
drbd_debugfs_device_cleanup(struct drbd_device * device)816*4882a593Smuzhiyun void drbd_debugfs_device_cleanup(struct drbd_device *device)
817*4882a593Smuzhiyun {
818*4882a593Smuzhiyun 	drbd_debugfs_remove(&device->debugfs_minor);
819*4882a593Smuzhiyun 	drbd_debugfs_remove(&device->debugfs_vol_oldest_requests);
820*4882a593Smuzhiyun 	drbd_debugfs_remove(&device->debugfs_vol_act_log_extents);
821*4882a593Smuzhiyun 	drbd_debugfs_remove(&device->debugfs_vol_resync_extents);
822*4882a593Smuzhiyun 	drbd_debugfs_remove(&device->debugfs_vol_data_gen_id);
823*4882a593Smuzhiyun 	drbd_debugfs_remove(&device->debugfs_vol_ed_gen_id);
824*4882a593Smuzhiyun 	drbd_debugfs_remove(&device->debugfs_vol);
825*4882a593Smuzhiyun }
826*4882a593Smuzhiyun 
drbd_debugfs_peer_device_add(struct drbd_peer_device * peer_device)827*4882a593Smuzhiyun void drbd_debugfs_peer_device_add(struct drbd_peer_device *peer_device)
828*4882a593Smuzhiyun {
829*4882a593Smuzhiyun 	struct dentry *conn_dir = peer_device->connection->debugfs_conn;
830*4882a593Smuzhiyun 	struct dentry *dentry;
831*4882a593Smuzhiyun 	char vnr_buf[8];
832*4882a593Smuzhiyun 
833*4882a593Smuzhiyun 	snprintf(vnr_buf, sizeof(vnr_buf), "%u", peer_device->device->vnr);
834*4882a593Smuzhiyun 	dentry = debugfs_create_dir(vnr_buf, conn_dir);
835*4882a593Smuzhiyun 	peer_device->debugfs_peer_dev = dentry;
836*4882a593Smuzhiyun }
837*4882a593Smuzhiyun 
drbd_debugfs_peer_device_cleanup(struct drbd_peer_device * peer_device)838*4882a593Smuzhiyun void drbd_debugfs_peer_device_cleanup(struct drbd_peer_device *peer_device)
839*4882a593Smuzhiyun {
840*4882a593Smuzhiyun 	drbd_debugfs_remove(&peer_device->debugfs_peer_dev);
841*4882a593Smuzhiyun }
842*4882a593Smuzhiyun 
drbd_version_show(struct seq_file * m,void * ignored)843*4882a593Smuzhiyun static int drbd_version_show(struct seq_file *m, void *ignored)
844*4882a593Smuzhiyun {
845*4882a593Smuzhiyun 	seq_printf(m, "# %s\n", drbd_buildtag());
846*4882a593Smuzhiyun 	seq_printf(m, "VERSION=%s\n", REL_VERSION);
847*4882a593Smuzhiyun 	seq_printf(m, "API_VERSION=%u\n", API_VERSION);
848*4882a593Smuzhiyun 	seq_printf(m, "PRO_VERSION_MIN=%u\n", PRO_VERSION_MIN);
849*4882a593Smuzhiyun 	seq_printf(m, "PRO_VERSION_MAX=%u\n", PRO_VERSION_MAX);
850*4882a593Smuzhiyun 	return 0;
851*4882a593Smuzhiyun }
852*4882a593Smuzhiyun 
drbd_version_open(struct inode * inode,struct file * file)853*4882a593Smuzhiyun static int drbd_version_open(struct inode *inode, struct file *file)
854*4882a593Smuzhiyun {
855*4882a593Smuzhiyun 	return single_open(file, drbd_version_show, NULL);
856*4882a593Smuzhiyun }
857*4882a593Smuzhiyun 
858*4882a593Smuzhiyun static const struct file_operations drbd_version_fops = {
859*4882a593Smuzhiyun 	.owner = THIS_MODULE,
860*4882a593Smuzhiyun 	.open = drbd_version_open,
861*4882a593Smuzhiyun 	.llseek = seq_lseek,
862*4882a593Smuzhiyun 	.read = seq_read,
863*4882a593Smuzhiyun 	.release = single_release,
864*4882a593Smuzhiyun };
865*4882a593Smuzhiyun 
866*4882a593Smuzhiyun /* not __exit, may be indirectly called
867*4882a593Smuzhiyun  * from the module-load-failure path as well. */
drbd_debugfs_cleanup(void)868*4882a593Smuzhiyun void drbd_debugfs_cleanup(void)
869*4882a593Smuzhiyun {
870*4882a593Smuzhiyun 	drbd_debugfs_remove(&drbd_debugfs_resources);
871*4882a593Smuzhiyun 	drbd_debugfs_remove(&drbd_debugfs_minors);
872*4882a593Smuzhiyun 	drbd_debugfs_remove(&drbd_debugfs_version);
873*4882a593Smuzhiyun 	drbd_debugfs_remove(&drbd_debugfs_root);
874*4882a593Smuzhiyun }
875*4882a593Smuzhiyun 
drbd_debugfs_init(void)876*4882a593Smuzhiyun void __init drbd_debugfs_init(void)
877*4882a593Smuzhiyun {
878*4882a593Smuzhiyun 	struct dentry *dentry;
879*4882a593Smuzhiyun 
880*4882a593Smuzhiyun 	dentry = debugfs_create_dir("drbd", NULL);
881*4882a593Smuzhiyun 	drbd_debugfs_root = dentry;
882*4882a593Smuzhiyun 
883*4882a593Smuzhiyun 	dentry = debugfs_create_file("version", 0444, drbd_debugfs_root, NULL, &drbd_version_fops);
884*4882a593Smuzhiyun 	drbd_debugfs_version = dentry;
885*4882a593Smuzhiyun 
886*4882a593Smuzhiyun 	dentry = debugfs_create_dir("resources", drbd_debugfs_root);
887*4882a593Smuzhiyun 	drbd_debugfs_resources = dentry;
888*4882a593Smuzhiyun 
889*4882a593Smuzhiyun 	dentry = debugfs_create_dir("minors", drbd_debugfs_root);
890*4882a593Smuzhiyun 	drbd_debugfs_minors = dentry;
891*4882a593Smuzhiyun }
892