]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/block/drbd/drbd_proc.c
drbd: fix potential wrap of 32bit oos:%lu display in /proc/drbd
[mirror_ubuntu-bionic-kernel.git] / drivers / block / drbd / drbd_proc.c
CommitLineData
b411b363
PR
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
b411b363
PR
26#include <linux/module.h>
27
28#include <asm/uaccess.h>
29#include <linux/fs.h>
30#include <linux/file.h>
b411b363
PR
31#include <linux/proc_fs.h>
32#include <linux/seq_file.h>
33#include <linux/drbd.h>
34#include "drbd_int.h"
35
36static int drbd_proc_open(struct inode *inode, struct file *file);
37
38
39struct proc_dir_entry *drbd_proc;
7d4e9d09 40const struct file_operations drbd_proc_fops = {
b411b363
PR
41 .owner = THIS_MODULE,
42 .open = drbd_proc_open,
43 .read = seq_read,
44 .llseek = seq_lseek,
45 .release = single_release,
46};
47
439d5953
LE
48void seq_printf_with_thousands_grouping(struct seq_file *seq, long v)
49{
50 /* v is in kB/sec. We don't expect TiByte/sec yet. */
51 if (unlikely(v >= 1000000)) {
52 /* cool: > GiByte/s */
53 seq_printf(seq, "%ld,", v / 1000000);
54 v /= 1000000;
55 seq_printf(seq, "%03ld,%03ld", v/1000, v % 1000);
56 } else if (likely(v >= 1000))
57 seq_printf(seq, "%ld,%03ld", v/1000, v % 1000);
58 else
59 seq_printf(seq, "%ld", v);
60}
b411b363
PR
61
62/*lge
63 * progress bars shamelessly adapted from driver/md/md.c
64 * output looks like
65 * [=====>..............] 33.5% (23456/123456)
66 * finish: 2:20:20 speed: 6,345 (6,456) K/sec
67 */
68static void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq)
69{
70 unsigned long db, dt, dbdt, rt, rs_left;
71 unsigned int res;
72 int i, x, y;
1d7734a0 73 int stalled = 0;
b411b363
PR
74
75 drbd_get_syncer_progress(mdev, &rs_left, &res);
76
77 x = res/50;
78 y = 20-x;
79 seq_printf(seq, "\t[");
80 for (i = 1; i < x; i++)
81 seq_printf(seq, "=");
82 seq_printf(seq, ">");
83 for (i = 0; i < y; i++)
84 seq_printf(seq, ".");
85 seq_printf(seq, "] ");
86
87 seq_printf(seq, "sync'ed:%3u.%u%% ", res / 10, res % 10);
88 /* if more than 1 GB display in MB */
89 if (mdev->rs_total > 0x100000L)
e7f52dfb 90 seq_printf(seq, "(%lu/%lu)M\n\t",
b411b363
PR
91 (unsigned long) Bit2KB(rs_left >> 10),
92 (unsigned long) Bit2KB(mdev->rs_total >> 10));
93 else
e7f52dfb 94 seq_printf(seq, "(%lu/%lu)K\n\t",
b411b363
PR
95 (unsigned long) Bit2KB(rs_left),
96 (unsigned long) Bit2KB(mdev->rs_total));
97
98 /* see drivers/md/md.c
99 * We do not want to overflow, so the order of operands and
100 * the * 100 / 100 trick are important. We do a +1 to be
101 * safe against division by zero. We only estimate anyway.
102 *
103 * dt: time from mark until now
104 * db: blocks written from mark until now
105 * rt: remaining time
106 */
1d7734a0
LE
107 /* Rolling marks. last_mark+1 may just now be modified. last_mark+2 is
108 * at least (DRBD_SYNC_MARKS-2)*DRBD_SYNC_MARK_STEP old, and has at
109 * least DRBD_SYNC_MARK_STEP time before it will be modified. */
439d5953 110 /* ------------------------ ~18s average ------------------------ */
1d7734a0
LE
111 i = (mdev->rs_last_mark + 2) % DRBD_SYNC_MARKS;
112 dt = (jiffies - mdev->rs_mark_time[i]) / HZ;
113 if (dt > (DRBD_SYNC_MARK_STEP * DRBD_SYNC_MARKS))
114 stalled = 1;
b411b363
PR
115
116 if (!dt)
117 dt++;
1d7734a0 118 db = mdev->rs_mark_left[i] - rs_left;
b411b363
PR
119 rt = (dt * (rs_left / (db/100+1)))/100; /* seconds */
120
121 seq_printf(seq, "finish: %lu:%02lu:%02lu",
122 rt / 3600, (rt % 3600) / 60, rt % 60);
123
b411b363 124 dbdt = Bit2KB(db/dt);
439d5953
LE
125 seq_printf(seq, " speed: ");
126 seq_printf_with_thousands_grouping(seq, dbdt);
127 seq_printf(seq, " (");
128 /* ------------------------- ~3s average ------------------------ */
129 if (proc_details >= 1) {
130 /* this is what drbd_rs_should_slow_down() uses */
131 i = (mdev->rs_last_mark + DRBD_SYNC_MARKS-1) % DRBD_SYNC_MARKS;
132 dt = (jiffies - mdev->rs_mark_time[i]) / HZ;
133 if (dt > (DRBD_SYNC_MARK_STEP * DRBD_SYNC_MARKS))
134 stalled = 1;
135
136 if (!dt)
137 dt++;
138 db = mdev->rs_mark_left[i] - rs_left;
139 rt = (dt * (rs_left / (db/100+1)))/100; /* seconds */
140
141 dbdt = Bit2KB(db/dt);
142 seq_printf_with_thousands_grouping(seq, dbdt);
143 seq_printf(seq, " -- ");
144 }
b411b363 145
439d5953 146 /* --------------------- long term average ---------------------- */
b411b363
PR
147 /* mean speed since syncer started
148 * we do account for PausedSync periods */
149 dt = (jiffies - mdev->rs_start - mdev->rs_paused) / HZ;
22657695 150 if (dt == 0)
b411b363
PR
151 dt = 1;
152 db = mdev->rs_total - rs_left;
153 dbdt = Bit2KB(db/dt);
439d5953
LE
154 seq_printf_with_thousands_grouping(seq, dbdt);
155 seq_printf(seq, ")");
b411b363 156
2649f080
LE
157 if (mdev->state.conn == C_SYNC_TARGET ||
158 mdev->state.conn == C_VERIFY_S) {
1d7734a0
LE
159 if (mdev->c_sync_rate > 1000)
160 seq_printf(seq, " want: %d,%03d",
161 mdev->c_sync_rate / 1000, mdev->c_sync_rate % 1000);
162 else
163 seq_printf(seq, " want: %d", mdev->c_sync_rate);
164 }
165 seq_printf(seq, " K/sec%s\n", stalled ? " (stalled)" : "");
b411b363
PR
166}
167
168static void resync_dump_detail(struct seq_file *seq, struct lc_element *e)
169{
170 struct bm_extent *bme = lc_entry(e, struct bm_extent, lce);
171
172 seq_printf(seq, "%5d %s %s\n", bme->rs_left,
173 bme->flags & BME_NO_WRITES ? "NO_WRITES" : "---------",
174 bme->flags & BME_LOCKED ? "LOCKED" : "------"
175 );
176}
177
178static int drbd_seq_show(struct seq_file *seq, void *v)
179{
180 int i, hole = 0;
181 const char *sn;
182 struct drbd_conf *mdev;
183
184 static char write_ordering_chars[] = {
185 [WO_none] = 'n',
186 [WO_drain_io] = 'd',
187 [WO_bdev_flush] = 'f',
b411b363
PR
188 };
189
190 seq_printf(seq, "version: " REL_VERSION " (api:%d/proto:%d-%d)\n%s\n",
191 API_VERSION, PRO_VERSION_MIN, PRO_VERSION_MAX, drbd_buildtag());
192
193 /*
194 cs .. connection state
195 ro .. node role (local/remote)
196 ds .. disk state (local/remote)
197 protocol
198 various flags
199 ns .. network send
200 nr .. network receive
201 dw .. disk write
202 dr .. disk read
203 al .. activity log write count
204 bm .. bitmap update write count
205 pe .. pending (waiting for ack or data reply)
206 ua .. unack'd (still need to send ack or data reply)
207 ap .. application requests accepted, but not yet completed
208 ep .. number of epochs currently "on the fly", P_BARRIER_ACK pending
209 wo .. write ordering mode currently in use
210 oos .. known out-of-sync kB
211 */
212
213 for (i = 0; i < minor_count; i++) {
214 mdev = minor_to_mdev(i);
215 if (!mdev) {
216 hole = 1;
217 continue;
218 }
219 if (hole) {
220 hole = 0;
221 seq_printf(seq, "\n");
222 }
223
224 sn = drbd_conn_str(mdev->state.conn);
225
226 if (mdev->state.conn == C_STANDALONE &&
227 mdev->state.disk == D_DISKLESS &&
228 mdev->state.role == R_SECONDARY) {
229 seq_printf(seq, "%2d: cs:Unconfigured\n", i);
230 } else {
231 seq_printf(seq,
0778286a 232 "%2d: cs:%s ro:%s/%s ds:%s/%s %c %c%c%c%c%c%c\n"
b411b363
PR
233 " ns:%u nr:%u dw:%u dr:%u al:%u bm:%u "
234 "lo:%d pe:%d ua:%d ap:%d ep:%d wo:%c",
235 i, sn,
236 drbd_role_str(mdev->state.role),
237 drbd_role_str(mdev->state.peer),
238 drbd_disk_str(mdev->state.disk),
239 drbd_disk_str(mdev->state.pdsk),
240 (mdev->net_conf == NULL ? ' ' :
241 (mdev->net_conf->wire_protocol - DRBD_PROT_A+'A')),
fb22c402 242 is_susp(mdev->state) ? 's' : 'r',
b411b363
PR
243 mdev->state.aftr_isp ? 'a' : '-',
244 mdev->state.peer_isp ? 'p' : '-',
245 mdev->state.user_isp ? 'u' : '-',
246 mdev->congestion_reason ?: '-',
0778286a 247 test_bit(AL_SUSPENDED, &mdev->flags) ? 's' : '-',
b411b363
PR
248 mdev->send_cnt/2,
249 mdev->recv_cnt/2,
250 mdev->writ_cnt/2,
251 mdev->read_cnt/2,
252 mdev->al_writ_cnt,
253 mdev->bm_writ_cnt,
254 atomic_read(&mdev->local_cnt),
255 atomic_read(&mdev->ap_pending_cnt) +
256 atomic_read(&mdev->rs_pending_cnt),
257 atomic_read(&mdev->unacked_cnt),
258 atomic_read(&mdev->ap_bio_cnt),
259 mdev->epochs,
260 write_ordering_chars[mdev->write_ordering]
261 );
18edc0b9
LE
262 seq_printf(seq, " oos:%llu\n",
263 Bit2KB((unsigned long long)
264 drbd_bm_total_weight(mdev)));
b411b363
PR
265 }
266 if (mdev->state.conn == C_SYNC_SOURCE ||
439d5953
LE
267 mdev->state.conn == C_SYNC_TARGET ||
268 mdev->state.conn == C_VERIFY_S ||
269 mdev->state.conn == C_VERIFY_T)
b411b363
PR
270 drbd_syncer_progress(mdev, seq);
271
30b743a2
LE
272 if (mdev->state.conn == C_VERIFY_S || mdev->state.conn == C_VERIFY_T) {
273 unsigned long bm_bits = drbd_bm_bits(mdev);
b411b363 274 seq_printf(seq, "\t%3d%% %lu/%lu\n",
30b743a2
LE
275 (int)((bm_bits-mdev->ov_left) /
276 (bm_bits/100+1)),
277 bm_bits - mdev->ov_left, bm_bits);
278 }
b411b363
PR
279
280 if (proc_details >= 1 && get_ldev_if_state(mdev, D_FAILED)) {
281 lc_seq_printf_stats(seq, mdev->resync);
282 lc_seq_printf_stats(seq, mdev->act_log);
283 put_ldev(mdev);
284 }
285
286 if (proc_details >= 2) {
287 if (mdev->resync) {
288 lc_seq_dump_details(seq, mdev->resync, "rs_left",
289 resync_dump_detail);
290 }
291 }
292 }
293
294 return 0;
295}
296
297static int drbd_proc_open(struct inode *inode, struct file *file)
298{
299 return single_open(file, drbd_seq_show, PDE(inode)->data);
300}
301
302/* PROC FS stuff end */