xref: /openbmc/linux/drivers/block/drbd/drbd_proc.c (revision 4dc7ccf7)
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\n\t",
77 			    (unsigned long) Bit2KB(rs_left >> 10),
78 			    (unsigned long) Bit2KB(mdev->rs_total >> 10));
79 	else
80 		seq_printf(seq, "(%lu/%lu)K\n\t",
81 			    (unsigned long) Bit2KB(rs_left),
82 			    (unsigned long) Bit2KB(mdev->rs_total));
83 
84 	/* see drivers/md/md.c
85 	 * We do not want to overflow, so the order of operands and
86 	 * the * 100 / 100 trick are important. We do a +1 to be
87 	 * safe against division by zero. We only estimate anyway.
88 	 *
89 	 * dt: time from mark until now
90 	 * db: blocks written from mark until now
91 	 * rt: remaining time
92 	 */
93 	dt = (jiffies - mdev->rs_mark_time) / HZ;
94 
95 	if (dt > 20) {
96 		/* if we made no update to rs_mark_time for too long,
97 		 * we are stalled. show that. */
98 		seq_printf(seq, "stalled\n");
99 		return;
100 	}
101 
102 	if (!dt)
103 		dt++;
104 	db = mdev->rs_mark_left - 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 	seq_printf(seq, " K/sec\n");
132 }
133 
134 static void resync_dump_detail(struct seq_file *seq, struct lc_element *e)
135 {
136 	struct bm_extent *bme = lc_entry(e, struct bm_extent, lce);
137 
138 	seq_printf(seq, "%5d %s %s\n", bme->rs_left,
139 		   bme->flags & BME_NO_WRITES ? "NO_WRITES" : "---------",
140 		   bme->flags & BME_LOCKED ? "LOCKED" : "------"
141 		   );
142 }
143 
144 static int drbd_seq_show(struct seq_file *seq, void *v)
145 {
146 	int i, hole = 0;
147 	const char *sn;
148 	struct drbd_conf *mdev;
149 
150 	static char write_ordering_chars[] = {
151 		[WO_none] = 'n',
152 		[WO_drain_io] = 'd',
153 		[WO_bdev_flush] = 'f',
154 		[WO_bio_barrier] = 'b',
155 	};
156 
157 	seq_printf(seq, "version: " REL_VERSION " (api:%d/proto:%d-%d)\n%s\n",
158 		   API_VERSION, PRO_VERSION_MIN, PRO_VERSION_MAX, drbd_buildtag());
159 
160 	/*
161 	  cs .. connection state
162 	  ro .. node role (local/remote)
163 	  ds .. disk state (local/remote)
164 	     protocol
165 	     various flags
166 	  ns .. network send
167 	  nr .. network receive
168 	  dw .. disk write
169 	  dr .. disk read
170 	  al .. activity log write count
171 	  bm .. bitmap update write count
172 	  pe .. pending (waiting for ack or data reply)
173 	  ua .. unack'd (still need to send ack or data reply)
174 	  ap .. application requests accepted, but not yet completed
175 	  ep .. number of epochs currently "on the fly", P_BARRIER_ACK pending
176 	  wo .. write ordering mode currently in use
177 	 oos .. known out-of-sync kB
178 	*/
179 
180 	for (i = 0; i < minor_count; i++) {
181 		mdev = minor_to_mdev(i);
182 		if (!mdev) {
183 			hole = 1;
184 			continue;
185 		}
186 		if (hole) {
187 			hole = 0;
188 			seq_printf(seq, "\n");
189 		}
190 
191 		sn = drbd_conn_str(mdev->state.conn);
192 
193 		if (mdev->state.conn == C_STANDALONE &&
194 		    mdev->state.disk == D_DISKLESS &&
195 		    mdev->state.role == R_SECONDARY) {
196 			seq_printf(seq, "%2d: cs:Unconfigured\n", i);
197 		} else {
198 			seq_printf(seq,
199 			   "%2d: cs:%s ro:%s/%s ds:%s/%s %c %c%c%c%c%c\n"
200 			   "    ns:%u nr:%u dw:%u dr:%u al:%u bm:%u "
201 			   "lo:%d pe:%d ua:%d ap:%d ep:%d wo:%c",
202 			   i, sn,
203 			   drbd_role_str(mdev->state.role),
204 			   drbd_role_str(mdev->state.peer),
205 			   drbd_disk_str(mdev->state.disk),
206 			   drbd_disk_str(mdev->state.pdsk),
207 			   (mdev->net_conf == NULL ? ' ' :
208 			    (mdev->net_conf->wire_protocol - DRBD_PROT_A+'A')),
209 			   mdev->state.susp ? 's' : 'r',
210 			   mdev->state.aftr_isp ? 'a' : '-',
211 			   mdev->state.peer_isp ? 'p' : '-',
212 			   mdev->state.user_isp ? 'u' : '-',
213 			   mdev->congestion_reason ?: '-',
214 			   mdev->send_cnt/2,
215 			   mdev->recv_cnt/2,
216 			   mdev->writ_cnt/2,
217 			   mdev->read_cnt/2,
218 			   mdev->al_writ_cnt,
219 			   mdev->bm_writ_cnt,
220 			   atomic_read(&mdev->local_cnt),
221 			   atomic_read(&mdev->ap_pending_cnt) +
222 			   atomic_read(&mdev->rs_pending_cnt),
223 			   atomic_read(&mdev->unacked_cnt),
224 			   atomic_read(&mdev->ap_bio_cnt),
225 			   mdev->epochs,
226 			   write_ordering_chars[mdev->write_ordering]
227 			);
228 			seq_printf(seq, " oos:%lu\n",
229 				   Bit2KB(drbd_bm_total_weight(mdev)));
230 		}
231 		if (mdev->state.conn == C_SYNC_SOURCE ||
232 		    mdev->state.conn == C_SYNC_TARGET)
233 			drbd_syncer_progress(mdev, seq);
234 
235 		if (mdev->state.conn == C_VERIFY_S || mdev->state.conn == C_VERIFY_T)
236 			seq_printf(seq, "\t%3d%%      %lu/%lu\n",
237 				   (int)((mdev->rs_total-mdev->ov_left) /
238 					 (mdev->rs_total/100+1)),
239 				   mdev->rs_total - mdev->ov_left,
240 				   mdev->rs_total);
241 
242 		if (proc_details >= 1 && get_ldev_if_state(mdev, D_FAILED)) {
243 			lc_seq_printf_stats(seq, mdev->resync);
244 			lc_seq_printf_stats(seq, mdev->act_log);
245 			put_ldev(mdev);
246 		}
247 
248 		if (proc_details >= 2) {
249 			if (mdev->resync) {
250 				lc_seq_dump_details(seq, mdev->resync, "rs_left",
251 					resync_dump_detail);
252 			}
253 		}
254 	}
255 
256 	return 0;
257 }
258 
259 static int drbd_proc_open(struct inode *inode, struct file *file)
260 {
261 	return single_open(file, drbd_seq_show, PDE(inode)->data);
262 }
263 
264 /* PROC FS stuff end */
265