xref: /linux/drivers/block/drbd/drbd_proc.c (revision f8324e20f8289dffc646d64366332e05eaacab25)
1 /*
2    drbd_proc.c
3 
4    This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
5 
6    Copyright (C) 2001-2008, LINBIT Information Technologies GmbH.
7    Copyright (C) 1999-2008, Philipp Reisner <philipp.reisner@linbit.com>.
8    Copyright (C) 2002-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
9 
10    drbd is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2, or (at your option)
13    any later version.
14 
15    drbd is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with drbd; see the file COPYING.  If not, write to
22    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 
24  */
25 
26 #include <linux/module.h>
27 
28 #include <asm/uaccess.h>
29 #include <linux/fs.h>
30 #include <linux/file.h>
31 #include <linux/proc_fs.h>
32 #include <linux/seq_file.h>
33 #include <linux/drbd.h>
34 #include "drbd_int.h"
35 
36 static int drbd_proc_open(struct inode *inode, struct file *file);
37 
38 
39 struct proc_dir_entry *drbd_proc;
40 const struct file_operations drbd_proc_fops = {
41 	.owner		= THIS_MODULE,
42 	.open		= drbd_proc_open,
43 	.read		= seq_read,
44 	.llseek		= seq_lseek,
45 	.release	= single_release,
46 };
47 
48 
49 /*lge
50  * progress bars shamelessly adapted from driver/md/md.c
51  * output looks like
52  *	[=====>..............] 33.5% (23456/123456)
53  *	finish: 2:20:20 speed: 6,345 (6,456) K/sec
54  */
55 static void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq)
56 {
57 	unsigned long db, dt, dbdt, rt, rs_left;
58 	unsigned int res;
59 	int i, x, y;
60 
61 	drbd_get_syncer_progress(mdev, &rs_left, &res);
62 
63 	x = res/50;
64 	y = 20-x;
65 	seq_printf(seq, "\t[");
66 	for (i = 1; i < x; i++)
67 		seq_printf(seq, "=");
68 	seq_printf(seq, ">");
69 	for (i = 0; i < y; i++)
70 		seq_printf(seq, ".");
71 	seq_printf(seq, "] ");
72 
73 	seq_printf(seq, "sync'ed:%3u.%u%% ", res / 10, res % 10);
74 	/* if more than 1 GB display in MB */
75 	if (mdev->rs_total > 0x100000L)
76 		seq_printf(seq, "(%lu/%lu)M",
77 			    (unsigned long) Bit2KB(rs_left >> 10),
78 			    (unsigned long) Bit2KB(mdev->rs_total >> 10));
79 	else
80 		seq_printf(seq, "(%lu/%lu)K",
81 			    (unsigned long) Bit2KB(rs_left),
82 			    (unsigned long) Bit2KB(mdev->rs_total));
83 
84 	if (mdev->state.conn == C_SYNC_TARGET)
85 		seq_printf(seq, " queue_delay: %d.%d ms\n\t",
86 			   mdev->data_delay / 1000,
87 			   (mdev->data_delay % 1000) / 100);
88 	else if (mdev->state.conn == C_SYNC_SOURCE)
89 		seq_printf(seq, " delay_probe: %u\n\t", mdev->delay_seq);
90 
91 	/* see drivers/md/md.c
92 	 * We do not want to overflow, so the order of operands and
93 	 * the * 100 / 100 trick are important. We do a +1 to be
94 	 * safe against division by zero. We only estimate anyway.
95 	 *
96 	 * dt: time from mark until now
97 	 * db: blocks written from mark until now
98 	 * rt: remaining time
99 	 */
100 	dt = (jiffies - mdev->rs_mark_time) / HZ;
101 
102 	if (dt > 20) {
103 		/* if we made no update to rs_mark_time for too long,
104 		 * we are stalled. show that. */
105 		seq_printf(seq, "stalled\n");
106 		return;
107 	}
108 
109 	if (!dt)
110 		dt++;
111 	db = mdev->rs_mark_left - rs_left;
112 	rt = (dt * (rs_left / (db/100+1)))/100; /* seconds */
113 
114 	seq_printf(seq, "finish: %lu:%02lu:%02lu",
115 		rt / 3600, (rt % 3600) / 60, rt % 60);
116 
117 	/* current speed average over (SYNC_MARKS * SYNC_MARK_STEP) jiffies */
118 	dbdt = Bit2KB(db/dt);
119 	if (dbdt > 1000)
120 		seq_printf(seq, " speed: %ld,%03ld",
121 			dbdt/1000, dbdt % 1000);
122 	else
123 		seq_printf(seq, " speed: %ld", dbdt);
124 
125 	/* mean speed since syncer started
126 	 * we do account for PausedSync periods */
127 	dt = (jiffies - mdev->rs_start - mdev->rs_paused) / HZ;
128 	if (dt <= 0)
129 		dt = 1;
130 	db = mdev->rs_total - rs_left;
131 	dbdt = Bit2KB(db/dt);
132 	if (dbdt > 1000)
133 		seq_printf(seq, " (%ld,%03ld)",
134 			dbdt/1000, dbdt % 1000);
135 	else
136 		seq_printf(seq, " (%ld)", dbdt);
137 
138 	if (mdev->state.conn == C_SYNC_TARGET) {
139 		if (mdev->c_sync_rate > 1000)
140 			seq_printf(seq, " want: %d,%03d",
141 				   mdev->c_sync_rate / 1000, mdev->c_sync_rate % 1000);
142 		else
143 			seq_printf(seq, " want: %d", mdev->c_sync_rate);
144 	}
145 
146 	seq_printf(seq, " K/sec\n");
147 }
148 
149 static void resync_dump_detail(struct seq_file *seq, struct lc_element *e)
150 {
151 	struct bm_extent *bme = lc_entry(e, struct bm_extent, lce);
152 
153 	seq_printf(seq, "%5d %s %s\n", bme->rs_left,
154 		   bme->flags & BME_NO_WRITES ? "NO_WRITES" : "---------",
155 		   bme->flags & BME_LOCKED ? "LOCKED" : "------"
156 		   );
157 }
158 
159 static int drbd_seq_show(struct seq_file *seq, void *v)
160 {
161 	int i, hole = 0;
162 	const char *sn;
163 	struct drbd_conf *mdev;
164 
165 	static char write_ordering_chars[] = {
166 		[WO_none] = 'n',
167 		[WO_drain_io] = 'd',
168 		[WO_bdev_flush] = 'f',
169 		[WO_bio_barrier] = 'b',
170 	};
171 
172 	seq_printf(seq, "version: " REL_VERSION " (api:%d/proto:%d-%d)\n%s\n",
173 		   API_VERSION, PRO_VERSION_MIN, PRO_VERSION_MAX, drbd_buildtag());
174 
175 	/*
176 	  cs .. connection state
177 	  ro .. node role (local/remote)
178 	  ds .. disk state (local/remote)
179 	     protocol
180 	     various flags
181 	  ns .. network send
182 	  nr .. network receive
183 	  dw .. disk write
184 	  dr .. disk read
185 	  al .. activity log write count
186 	  bm .. bitmap update write count
187 	  pe .. pending (waiting for ack or data reply)
188 	  ua .. unack'd (still need to send ack or data reply)
189 	  ap .. application requests accepted, but not yet completed
190 	  ep .. number of epochs currently "on the fly", P_BARRIER_ACK pending
191 	  wo .. write ordering mode currently in use
192 	 oos .. known out-of-sync kB
193 	*/
194 
195 	for (i = 0; i < minor_count; i++) {
196 		mdev = minor_to_mdev(i);
197 		if (!mdev) {
198 			hole = 1;
199 			continue;
200 		}
201 		if (hole) {
202 			hole = 0;
203 			seq_printf(seq, "\n");
204 		}
205 
206 		sn = drbd_conn_str(mdev->state.conn);
207 
208 		if (mdev->state.conn == C_STANDALONE &&
209 		    mdev->state.disk == D_DISKLESS &&
210 		    mdev->state.role == R_SECONDARY) {
211 			seq_printf(seq, "%2d: cs:Unconfigured\n", i);
212 		} else {
213 			seq_printf(seq,
214 			   "%2d: cs:%s ro:%s/%s ds:%s/%s %c %c%c%c%c%c\n"
215 			   "    ns:%u nr:%u dw:%u dr:%u al:%u bm:%u "
216 			   "lo:%d pe:%d ua:%d ap:%d ep:%d wo:%c",
217 			   i, sn,
218 			   drbd_role_str(mdev->state.role),
219 			   drbd_role_str(mdev->state.peer),
220 			   drbd_disk_str(mdev->state.disk),
221 			   drbd_disk_str(mdev->state.pdsk),
222 			   (mdev->net_conf == NULL ? ' ' :
223 			    (mdev->net_conf->wire_protocol - DRBD_PROT_A+'A')),
224 			   mdev->state.susp ? 's' : 'r',
225 			   mdev->state.aftr_isp ? 'a' : '-',
226 			   mdev->state.peer_isp ? 'p' : '-',
227 			   mdev->state.user_isp ? 'u' : '-',
228 			   mdev->congestion_reason ?: '-',
229 			   mdev->send_cnt/2,
230 			   mdev->recv_cnt/2,
231 			   mdev->writ_cnt/2,
232 			   mdev->read_cnt/2,
233 			   mdev->al_writ_cnt,
234 			   mdev->bm_writ_cnt,
235 			   atomic_read(&mdev->local_cnt),
236 			   atomic_read(&mdev->ap_pending_cnt) +
237 			   atomic_read(&mdev->rs_pending_cnt),
238 			   atomic_read(&mdev->unacked_cnt),
239 			   atomic_read(&mdev->ap_bio_cnt),
240 			   mdev->epochs,
241 			   write_ordering_chars[mdev->write_ordering]
242 			);
243 			seq_printf(seq, " oos:%lu\n",
244 				   Bit2KB(drbd_bm_total_weight(mdev)));
245 		}
246 		if (mdev->state.conn == C_SYNC_SOURCE ||
247 		    mdev->state.conn == C_SYNC_TARGET)
248 			drbd_syncer_progress(mdev, seq);
249 
250 		if (mdev->state.conn == C_VERIFY_S || mdev->state.conn == C_VERIFY_T)
251 			seq_printf(seq, "\t%3d%%      %lu/%lu\n",
252 				   (int)((mdev->rs_total-mdev->ov_left) /
253 					 (mdev->rs_total/100+1)),
254 				   mdev->rs_total - mdev->ov_left,
255 				   mdev->rs_total);
256 
257 		if (proc_details >= 1 && get_ldev_if_state(mdev, D_FAILED)) {
258 			lc_seq_printf_stats(seq, mdev->resync);
259 			lc_seq_printf_stats(seq, mdev->act_log);
260 			put_ldev(mdev);
261 		}
262 
263 		if (proc_details >= 2) {
264 			if (mdev->resync) {
265 				lc_seq_dump_details(seq, mdev->resync, "rs_left",
266 					resync_dump_detail);
267 			}
268 		}
269 	}
270 
271 	return 0;
272 }
273 
274 static int drbd_proc_open(struct inode *inode, struct file *file)
275 {
276 	return single_open(file, drbd_seq_show, PDE(inode)->data);
277 }
278 
279 /* PROC FS stuff end */
280