xref: /linux/drivers/block/drbd/drbd_proc.c (revision cb299ba8b5ef2239429484072fea394cd7581bd7)
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 	int stalled = 0;
61 
62 	drbd_get_syncer_progress(mdev, &rs_left, &res);
63 
64 	x = res/50;
65 	y = 20-x;
66 	seq_printf(seq, "\t[");
67 	for (i = 1; i < x; i++)
68 		seq_printf(seq, "=");
69 	seq_printf(seq, ">");
70 	for (i = 0; i < y; i++)
71 		seq_printf(seq, ".");
72 	seq_printf(seq, "] ");
73 
74 	seq_printf(seq, "sync'ed:%3u.%u%% ", res / 10, res % 10);
75 	/* if more than 1 GB display in MB */
76 	if (mdev->rs_total > 0x100000L)
77 		seq_printf(seq, "(%lu/%lu)M\n\t",
78 			    (unsigned long) Bit2KB(rs_left >> 10),
79 			    (unsigned long) Bit2KB(mdev->rs_total >> 10));
80 	else
81 		seq_printf(seq, "(%lu/%lu)K\n\t",
82 			    (unsigned long) Bit2KB(rs_left),
83 			    (unsigned long) Bit2KB(mdev->rs_total));
84 
85 	/* see drivers/md/md.c
86 	 * We do not want to overflow, so the order of operands and
87 	 * the * 100 / 100 trick are important. We do a +1 to be
88 	 * safe against division by zero. We only estimate anyway.
89 	 *
90 	 * dt: time from mark until now
91 	 * db: blocks written from mark until now
92 	 * rt: remaining time
93 	 */
94 	/* Rolling marks. last_mark+1 may just now be modified.  last_mark+2 is
95 	 * at least (DRBD_SYNC_MARKS-2)*DRBD_SYNC_MARK_STEP old, and has at
96 	 * least DRBD_SYNC_MARK_STEP time before it will be modified. */
97 	i = (mdev->rs_last_mark + 2) % DRBD_SYNC_MARKS;
98 	dt = (jiffies - mdev->rs_mark_time[i]) / HZ;
99 	if (dt > (DRBD_SYNC_MARK_STEP * DRBD_SYNC_MARKS))
100 		stalled = 1;
101 
102 	if (!dt)
103 		dt++;
104 	db = mdev->rs_mark_left[i] - rs_left;
105 	rt = (dt * (rs_left / (db/100+1)))/100; /* seconds */
106 
107 	seq_printf(seq, "finish: %lu:%02lu:%02lu",
108 		rt / 3600, (rt % 3600) / 60, rt % 60);
109 
110 	/* current speed average over (SYNC_MARKS * SYNC_MARK_STEP) jiffies */
111 	dbdt = Bit2KB(db/dt);
112 	if (dbdt > 1000)
113 		seq_printf(seq, " speed: %ld,%03ld",
114 			dbdt/1000, dbdt % 1000);
115 	else
116 		seq_printf(seq, " speed: %ld", dbdt);
117 
118 	/* mean speed since syncer started
119 	 * we do account for PausedSync periods */
120 	dt = (jiffies - mdev->rs_start - mdev->rs_paused) / HZ;
121 	if (dt == 0)
122 		dt = 1;
123 	db = mdev->rs_total - rs_left;
124 	dbdt = Bit2KB(db/dt);
125 	if (dbdt > 1000)
126 		seq_printf(seq, " (%ld,%03ld)",
127 			dbdt/1000, dbdt % 1000);
128 	else
129 		seq_printf(seq, " (%ld)", dbdt);
130 
131 	if (mdev->state.conn == C_SYNC_TARGET) {
132 		if (mdev->c_sync_rate > 1000)
133 			seq_printf(seq, " want: %d,%03d",
134 				   mdev->c_sync_rate / 1000, mdev->c_sync_rate % 1000);
135 		else
136 			seq_printf(seq, " want: %d", mdev->c_sync_rate);
137 	}
138 	seq_printf(seq, " K/sec%s\n", stalled ? " (stalled)" : "");
139 }
140 
141 static void resync_dump_detail(struct seq_file *seq, struct lc_element *e)
142 {
143 	struct bm_extent *bme = lc_entry(e, struct bm_extent, lce);
144 
145 	seq_printf(seq, "%5d %s %s\n", bme->rs_left,
146 		   bme->flags & BME_NO_WRITES ? "NO_WRITES" : "---------",
147 		   bme->flags & BME_LOCKED ? "LOCKED" : "------"
148 		   );
149 }
150 
151 static int drbd_seq_show(struct seq_file *seq, void *v)
152 {
153 	int i, hole = 0;
154 	const char *sn;
155 	struct drbd_conf *mdev;
156 
157 	static char write_ordering_chars[] = {
158 		[WO_none] = 'n',
159 		[WO_drain_io] = 'd',
160 		[WO_bdev_flush] = 'f',
161 		[WO_bio_barrier] = 'b',
162 	};
163 
164 	seq_printf(seq, "version: " REL_VERSION " (api:%d/proto:%d-%d)\n%s\n",
165 		   API_VERSION, PRO_VERSION_MIN, PRO_VERSION_MAX, drbd_buildtag());
166 
167 	/*
168 	  cs .. connection state
169 	  ro .. node role (local/remote)
170 	  ds .. disk state (local/remote)
171 	     protocol
172 	     various flags
173 	  ns .. network send
174 	  nr .. network receive
175 	  dw .. disk write
176 	  dr .. disk read
177 	  al .. activity log write count
178 	  bm .. bitmap update write count
179 	  pe .. pending (waiting for ack or data reply)
180 	  ua .. unack'd (still need to send ack or data reply)
181 	  ap .. application requests accepted, but not yet completed
182 	  ep .. number of epochs currently "on the fly", P_BARRIER_ACK pending
183 	  wo .. write ordering mode currently in use
184 	 oos .. known out-of-sync kB
185 	*/
186 
187 	for (i = 0; i < minor_count; i++) {
188 		mdev = minor_to_mdev(i);
189 		if (!mdev) {
190 			hole = 1;
191 			continue;
192 		}
193 		if (hole) {
194 			hole = 0;
195 			seq_printf(seq, "\n");
196 		}
197 
198 		sn = drbd_conn_str(mdev->state.conn);
199 
200 		if (mdev->state.conn == C_STANDALONE &&
201 		    mdev->state.disk == D_DISKLESS &&
202 		    mdev->state.role == R_SECONDARY) {
203 			seq_printf(seq, "%2d: cs:Unconfigured\n", i);
204 		} else {
205 			seq_printf(seq,
206 			   "%2d: cs:%s ro:%s/%s ds:%s/%s %c %c%c%c%c%c%c\n"
207 			   "    ns:%u nr:%u dw:%u dr:%u al:%u bm:%u "
208 			   "lo:%d pe:%d ua:%d ap:%d ep:%d wo:%c",
209 			   i, sn,
210 			   drbd_role_str(mdev->state.role),
211 			   drbd_role_str(mdev->state.peer),
212 			   drbd_disk_str(mdev->state.disk),
213 			   drbd_disk_str(mdev->state.pdsk),
214 			   (mdev->net_conf == NULL ? ' ' :
215 			    (mdev->net_conf->wire_protocol - DRBD_PROT_A+'A')),
216 			   is_susp(mdev->state) ? 's' : 'r',
217 			   mdev->state.aftr_isp ? 'a' : '-',
218 			   mdev->state.peer_isp ? 'p' : '-',
219 			   mdev->state.user_isp ? 'u' : '-',
220 			   mdev->congestion_reason ?: '-',
221 			   test_bit(AL_SUSPENDED, &mdev->flags) ? 's' : '-',
222 			   mdev->send_cnt/2,
223 			   mdev->recv_cnt/2,
224 			   mdev->writ_cnt/2,
225 			   mdev->read_cnt/2,
226 			   mdev->al_writ_cnt,
227 			   mdev->bm_writ_cnt,
228 			   atomic_read(&mdev->local_cnt),
229 			   atomic_read(&mdev->ap_pending_cnt) +
230 			   atomic_read(&mdev->rs_pending_cnt),
231 			   atomic_read(&mdev->unacked_cnt),
232 			   atomic_read(&mdev->ap_bio_cnt),
233 			   mdev->epochs,
234 			   write_ordering_chars[mdev->write_ordering]
235 			);
236 			seq_printf(seq, " oos:%lu\n",
237 				   Bit2KB(drbd_bm_total_weight(mdev)));
238 		}
239 		if (mdev->state.conn == C_SYNC_SOURCE ||
240 		    mdev->state.conn == C_SYNC_TARGET)
241 			drbd_syncer_progress(mdev, seq);
242 
243 		if (mdev->state.conn == C_VERIFY_S || mdev->state.conn == C_VERIFY_T)
244 			seq_printf(seq, "\t%3d%%      %lu/%lu\n",
245 				   (int)((mdev->rs_total-mdev->ov_left) /
246 					 (mdev->rs_total/100+1)),
247 				   mdev->rs_total - mdev->ov_left,
248 				   mdev->rs_total);
249 
250 		if (proc_details >= 1 && get_ldev_if_state(mdev, D_FAILED)) {
251 			lc_seq_printf_stats(seq, mdev->resync);
252 			lc_seq_printf_stats(seq, mdev->act_log);
253 			put_ldev(mdev);
254 		}
255 
256 		if (proc_details >= 2) {
257 			if (mdev->resync) {
258 				lc_seq_dump_details(seq, mdev->resync, "rs_left",
259 					resync_dump_detail);
260 			}
261 		}
262 	}
263 
264 	return 0;
265 }
266 
267 static int drbd_proc_open(struct inode *inode, struct file *file)
268 {
269 	return single_open(file, drbd_seq_show, PDE(inode)->data);
270 }
271 
272 /* PROC FS stuff end */
273