xref: /openbmc/linux/drivers/block/drbd/drbd_proc.c (revision b6dcefde)
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/slab.h>
32 #include <linux/proc_fs.h>
33 #include <linux/seq_file.h>
34 #include <linux/drbd.h>
35 #include "drbd_int.h"
36 
37 static int drbd_proc_open(struct inode *inode, struct file *file);
38 
39 
40 struct proc_dir_entry *drbd_proc;
41 const struct file_operations drbd_proc_fops = {
42 	.owner		= THIS_MODULE,
43 	.open		= drbd_proc_open,
44 	.read		= seq_read,
45 	.llseek		= seq_lseek,
46 	.release	= single_release,
47 };
48 
49 
50 /*lge
51  * progress bars shamelessly adapted from driver/md/md.c
52  * output looks like
53  *	[=====>..............] 33.5% (23456/123456)
54  *	finish: 2:20:20 speed: 6,345 (6,456) K/sec
55  */
56 static void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq)
57 {
58 	unsigned long db, dt, dbdt, rt, rs_left;
59 	unsigned int res;
60 	int i, x, y;
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 	dt = (jiffies - mdev->rs_mark_time) / HZ;
95 
96 	if (dt > 20) {
97 		/* if we made no update to rs_mark_time for too long,
98 		 * we are stalled. show that. */
99 		seq_printf(seq, "stalled\n");
100 		return;
101 	}
102 
103 	if (!dt)
104 		dt++;
105 	db = mdev->rs_mark_left - rs_left;
106 	rt = (dt * (rs_left / (db/100+1)))/100; /* seconds */
107 
108 	seq_printf(seq, "finish: %lu:%02lu:%02lu",
109 		rt / 3600, (rt % 3600) / 60, rt % 60);
110 
111 	/* current speed average over (SYNC_MARKS * SYNC_MARK_STEP) jiffies */
112 	dbdt = Bit2KB(db/dt);
113 	if (dbdt > 1000)
114 		seq_printf(seq, " speed: %ld,%03ld",
115 			dbdt/1000, dbdt % 1000);
116 	else
117 		seq_printf(seq, " speed: %ld", dbdt);
118 
119 	/* mean speed since syncer started
120 	 * we do account for PausedSync periods */
121 	dt = (jiffies - mdev->rs_start - mdev->rs_paused) / HZ;
122 	if (dt <= 0)
123 		dt = 1;
124 	db = mdev->rs_total - rs_left;
125 	dbdt = Bit2KB(db/dt);
126 	if (dbdt > 1000)
127 		seq_printf(seq, " (%ld,%03ld)",
128 			dbdt/1000, dbdt % 1000);
129 	else
130 		seq_printf(seq, " (%ld)", dbdt);
131 
132 	seq_printf(seq, " K/sec\n");
133 }
134 
135 static void resync_dump_detail(struct seq_file *seq, struct lc_element *e)
136 {
137 	struct bm_extent *bme = lc_entry(e, struct bm_extent, lce);
138 
139 	seq_printf(seq, "%5d %s %s\n", bme->rs_left,
140 		   bme->flags & BME_NO_WRITES ? "NO_WRITES" : "---------",
141 		   bme->flags & BME_LOCKED ? "LOCKED" : "------"
142 		   );
143 }
144 
145 static int drbd_seq_show(struct seq_file *seq, void *v)
146 {
147 	int i, hole = 0;
148 	const char *sn;
149 	struct drbd_conf *mdev;
150 
151 	static char write_ordering_chars[] = {
152 		[WO_none] = 'n',
153 		[WO_drain_io] = 'd',
154 		[WO_bdev_flush] = 'f',
155 		[WO_bio_barrier] = 'b',
156 	};
157 
158 	seq_printf(seq, "version: " REL_VERSION " (api:%d/proto:%d-%d)\n%s\n",
159 		   API_VERSION, PRO_VERSION_MIN, PRO_VERSION_MAX, drbd_buildtag());
160 
161 	/*
162 	  cs .. connection state
163 	  ro .. node role (local/remote)
164 	  ds .. disk state (local/remote)
165 	     protocol
166 	     various flags
167 	  ns .. network send
168 	  nr .. network receive
169 	  dw .. disk write
170 	  dr .. disk read
171 	  al .. activity log write count
172 	  bm .. bitmap update write count
173 	  pe .. pending (waiting for ack or data reply)
174 	  ua .. unack'd (still need to send ack or data reply)
175 	  ap .. application requests accepted, but not yet completed
176 	  ep .. number of epochs currently "on the fly", P_BARRIER_ACK pending
177 	  wo .. write ordering mode currently in use
178 	 oos .. known out-of-sync kB
179 	*/
180 
181 	for (i = 0; i < minor_count; i++) {
182 		mdev = minor_to_mdev(i);
183 		if (!mdev) {
184 			hole = 1;
185 			continue;
186 		}
187 		if (hole) {
188 			hole = 0;
189 			seq_printf(seq, "\n");
190 		}
191 
192 		sn = drbd_conn_str(mdev->state.conn);
193 
194 		if (mdev->state.conn == C_STANDALONE &&
195 		    mdev->state.disk == D_DISKLESS &&
196 		    mdev->state.role == R_SECONDARY) {
197 			seq_printf(seq, "%2d: cs:Unconfigured\n", i);
198 		} else {
199 			seq_printf(seq,
200 			   "%2d: cs:%s ro:%s/%s ds:%s/%s %c %c%c%c%c%c\n"
201 			   "    ns:%u nr:%u dw:%u dr:%u al:%u bm:%u "
202 			   "lo:%d pe:%d ua:%d ap:%d ep:%d wo:%c",
203 			   i, sn,
204 			   drbd_role_str(mdev->state.role),
205 			   drbd_role_str(mdev->state.peer),
206 			   drbd_disk_str(mdev->state.disk),
207 			   drbd_disk_str(mdev->state.pdsk),
208 			   (mdev->net_conf == NULL ? ' ' :
209 			    (mdev->net_conf->wire_protocol - DRBD_PROT_A+'A')),
210 			   mdev->state.susp ? 's' : 'r',
211 			   mdev->state.aftr_isp ? 'a' : '-',
212 			   mdev->state.peer_isp ? 'p' : '-',
213 			   mdev->state.user_isp ? 'u' : '-',
214 			   mdev->congestion_reason ?: '-',
215 			   mdev->send_cnt/2,
216 			   mdev->recv_cnt/2,
217 			   mdev->writ_cnt/2,
218 			   mdev->read_cnt/2,
219 			   mdev->al_writ_cnt,
220 			   mdev->bm_writ_cnt,
221 			   atomic_read(&mdev->local_cnt),
222 			   atomic_read(&mdev->ap_pending_cnt) +
223 			   atomic_read(&mdev->rs_pending_cnt),
224 			   atomic_read(&mdev->unacked_cnt),
225 			   atomic_read(&mdev->ap_bio_cnt),
226 			   mdev->epochs,
227 			   write_ordering_chars[mdev->write_ordering]
228 			);
229 			seq_printf(seq, " oos:%lu\n",
230 				   Bit2KB(drbd_bm_total_weight(mdev)));
231 		}
232 		if (mdev->state.conn == C_SYNC_SOURCE ||
233 		    mdev->state.conn == C_SYNC_TARGET)
234 			drbd_syncer_progress(mdev, seq);
235 
236 		if (mdev->state.conn == C_VERIFY_S || mdev->state.conn == C_VERIFY_T)
237 			seq_printf(seq, "\t%3d%%      %lu/%lu\n",
238 				   (int)((mdev->rs_total-mdev->ov_left) /
239 					 (mdev->rs_total/100+1)),
240 				   mdev->rs_total - mdev->ov_left,
241 				   mdev->rs_total);
242 
243 		if (proc_details >= 1 && get_ldev_if_state(mdev, D_FAILED)) {
244 			lc_seq_printf_stats(seq, mdev->resync);
245 			lc_seq_printf_stats(seq, mdev->act_log);
246 			put_ldev(mdev);
247 		}
248 
249 		if (proc_details >= 2) {
250 			if (mdev->resync) {
251 				lc_seq_dump_details(seq, mdev->resync, "rs_left",
252 					resync_dump_detail);
253 			}
254 		}
255 	}
256 
257 	return 0;
258 }
259 
260 static int drbd_proc_open(struct inode *inode, struct file *file)
261 {
262 	return single_open(file, drbd_seq_show, PDE(inode)->data);
263 }
264 
265 /* PROC FS stuff end */
266