xref: /openbmc/linux/drivers/block/drbd/drbd_proc.c (revision 4800cd83)
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 	};
162 
163 	seq_printf(seq, "version: " REL_VERSION " (api:%d/proto:%d-%d)\n%s\n",
164 		   API_VERSION, PRO_VERSION_MIN, PRO_VERSION_MAX, drbd_buildtag());
165 
166 	/*
167 	  cs .. connection state
168 	  ro .. node role (local/remote)
169 	  ds .. disk state (local/remote)
170 	     protocol
171 	     various flags
172 	  ns .. network send
173 	  nr .. network receive
174 	  dw .. disk write
175 	  dr .. disk read
176 	  al .. activity log write count
177 	  bm .. bitmap update write count
178 	  pe .. pending (waiting for ack or data reply)
179 	  ua .. unack'd (still need to send ack or data reply)
180 	  ap .. application requests accepted, but not yet completed
181 	  ep .. number of epochs currently "on the fly", P_BARRIER_ACK pending
182 	  wo .. write ordering mode currently in use
183 	 oos .. known out-of-sync kB
184 	*/
185 
186 	for (i = 0; i < minor_count; i++) {
187 		mdev = minor_to_mdev(i);
188 		if (!mdev) {
189 			hole = 1;
190 			continue;
191 		}
192 		if (hole) {
193 			hole = 0;
194 			seq_printf(seq, "\n");
195 		}
196 
197 		sn = drbd_conn_str(mdev->state.conn);
198 
199 		if (mdev->state.conn == C_STANDALONE &&
200 		    mdev->state.disk == D_DISKLESS &&
201 		    mdev->state.role == R_SECONDARY) {
202 			seq_printf(seq, "%2d: cs:Unconfigured\n", i);
203 		} else {
204 			seq_printf(seq,
205 			   "%2d: cs:%s ro:%s/%s ds:%s/%s %c %c%c%c%c%c%c\n"
206 			   "    ns:%u nr:%u dw:%u dr:%u al:%u bm:%u "
207 			   "lo:%d pe:%d ua:%d ap:%d ep:%d wo:%c",
208 			   i, sn,
209 			   drbd_role_str(mdev->state.role),
210 			   drbd_role_str(mdev->state.peer),
211 			   drbd_disk_str(mdev->state.disk),
212 			   drbd_disk_str(mdev->state.pdsk),
213 			   (mdev->net_conf == NULL ? ' ' :
214 			    (mdev->net_conf->wire_protocol - DRBD_PROT_A+'A')),
215 			   is_susp(mdev->state) ? 's' : 'r',
216 			   mdev->state.aftr_isp ? 'a' : '-',
217 			   mdev->state.peer_isp ? 'p' : '-',
218 			   mdev->state.user_isp ? 'u' : '-',
219 			   mdev->congestion_reason ?: '-',
220 			   test_bit(AL_SUSPENDED, &mdev->flags) ? 's' : '-',
221 			   mdev->send_cnt/2,
222 			   mdev->recv_cnt/2,
223 			   mdev->writ_cnt/2,
224 			   mdev->read_cnt/2,
225 			   mdev->al_writ_cnt,
226 			   mdev->bm_writ_cnt,
227 			   atomic_read(&mdev->local_cnt),
228 			   atomic_read(&mdev->ap_pending_cnt) +
229 			   atomic_read(&mdev->rs_pending_cnt),
230 			   atomic_read(&mdev->unacked_cnt),
231 			   atomic_read(&mdev->ap_bio_cnt),
232 			   mdev->epochs,
233 			   write_ordering_chars[mdev->write_ordering]
234 			);
235 			seq_printf(seq, " oos:%lu\n",
236 				   Bit2KB(drbd_bm_total_weight(mdev)));
237 		}
238 		if (mdev->state.conn == C_SYNC_SOURCE ||
239 		    mdev->state.conn == C_SYNC_TARGET)
240 			drbd_syncer_progress(mdev, seq);
241 
242 		if (mdev->state.conn == C_VERIFY_S || mdev->state.conn == C_VERIFY_T)
243 			seq_printf(seq, "\t%3d%%      %lu/%lu\n",
244 				   (int)((mdev->rs_total-mdev->ov_left) /
245 					 (mdev->rs_total/100+1)),
246 				   mdev->rs_total - mdev->ov_left,
247 				   mdev->rs_total);
248 
249 		if (proc_details >= 1 && get_ldev_if_state(mdev, D_FAILED)) {
250 			lc_seq_printf_stats(seq, mdev->resync);
251 			lc_seq_printf_stats(seq, mdev->act_log);
252 			put_ldev(mdev);
253 		}
254 
255 		if (proc_details >= 2) {
256 			if (mdev->resync) {
257 				lc_seq_dump_details(seq, mdev->resync, "rs_left",
258 					resync_dump_detail);
259 			}
260 		}
261 	}
262 
263 	return 0;
264 }
265 
266 static int drbd_proc_open(struct inode *inode, struct file *file)
267 {
268 	return single_open(file, drbd_seq_show, PDE(inode)->data);
269 }
270 
271 /* PROC FS stuff end */
272