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