]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/block/drbd/drbd_proc.c
drbd: show progress bar and ETA for online-verify
[karo-tx-linux.git] / drivers / block / drbd / drbd_proc.c
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 void 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 }
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  */
68 static 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;
73         int stalled = 0;
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)
90                 seq_printf(seq, "(%lu/%lu)M\n\t",
91                             (unsigned long) Bit2KB(rs_left >> 10),
92                             (unsigned long) Bit2KB(mdev->rs_total >> 10));
93         else
94                 seq_printf(seq, "(%lu/%lu)K\n\t",
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          */
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. */
110         /* ------------------------ ~18s average ------------------------ */
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;
115
116         if (!dt)
117                 dt++;
118         db = mdev->rs_mark_left[i] - rs_left;
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
124         dbdt = Bit2KB(db/dt);
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         }
145
146         /* --------------------- long term average ---------------------- */
147         /* mean speed since syncer started
148          * we do account for PausedSync periods */
149         dt = (jiffies - mdev->rs_start - mdev->rs_paused) / HZ;
150         if (dt == 0)
151                 dt = 1;
152         db = mdev->rs_total - rs_left;
153         dbdt = Bit2KB(db/dt);
154         seq_printf_with_thousands_grouping(seq, dbdt);
155         seq_printf(seq, ")");
156
157         if (mdev->state.conn == C_SYNC_TARGET) {
158                 if (mdev->c_sync_rate > 1000)
159                         seq_printf(seq, " want: %d,%03d",
160                                    mdev->c_sync_rate / 1000, mdev->c_sync_rate % 1000);
161                 else
162                         seq_printf(seq, " want: %d", mdev->c_sync_rate);
163         }
164         seq_printf(seq, " K/sec%s\n", stalled ? " (stalled)" : "");
165 }
166
167 static void resync_dump_detail(struct seq_file *seq, struct lc_element *e)
168 {
169         struct bm_extent *bme = lc_entry(e, struct bm_extent, lce);
170
171         seq_printf(seq, "%5d %s %s\n", bme->rs_left,
172                    bme->flags & BME_NO_WRITES ? "NO_WRITES" : "---------",
173                    bme->flags & BME_LOCKED ? "LOCKED" : "------"
174                    );
175 }
176
177 static int drbd_seq_show(struct seq_file *seq, void *v)
178 {
179         int i, hole = 0;
180         const char *sn;
181         struct drbd_conf *mdev;
182
183         static char write_ordering_chars[] = {
184                 [WO_none] = 'n',
185                 [WO_drain_io] = 'd',
186                 [WO_bdev_flush] = 'f',
187         };
188
189         seq_printf(seq, "version: " REL_VERSION " (api:%d/proto:%d-%d)\n%s\n",
190                    API_VERSION, PRO_VERSION_MIN, PRO_VERSION_MAX, drbd_buildtag());
191
192         /*
193           cs .. connection state
194           ro .. node role (local/remote)
195           ds .. disk state (local/remote)
196              protocol
197              various flags
198           ns .. network send
199           nr .. network receive
200           dw .. disk write
201           dr .. disk read
202           al .. activity log write count
203           bm .. bitmap update write count
204           pe .. pending (waiting for ack or data reply)
205           ua .. unack'd (still need to send ack or data reply)
206           ap .. application requests accepted, but not yet completed
207           ep .. number of epochs currently "on the fly", P_BARRIER_ACK pending
208           wo .. write ordering mode currently in use
209          oos .. known out-of-sync kB
210         */
211
212         for (i = 0; i < minor_count; i++) {
213                 mdev = minor_to_mdev(i);
214                 if (!mdev) {
215                         hole = 1;
216                         continue;
217                 }
218                 if (hole) {
219                         hole = 0;
220                         seq_printf(seq, "\n");
221                 }
222
223                 sn = drbd_conn_str(mdev->state.conn);
224
225                 if (mdev->state.conn == C_STANDALONE &&
226                     mdev->state.disk == D_DISKLESS &&
227                     mdev->state.role == R_SECONDARY) {
228                         seq_printf(seq, "%2d: cs:Unconfigured\n", i);
229                 } else {
230                         seq_printf(seq,
231                            "%2d: cs:%s ro:%s/%s ds:%s/%s %c %c%c%c%c%c%c\n"
232                            "    ns:%u nr:%u dw:%u dr:%u al:%u bm:%u "
233                            "lo:%d pe:%d ua:%d ap:%d ep:%d wo:%c",
234                            i, sn,
235                            drbd_role_str(mdev->state.role),
236                            drbd_role_str(mdev->state.peer),
237                            drbd_disk_str(mdev->state.disk),
238                            drbd_disk_str(mdev->state.pdsk),
239                            (mdev->net_conf == NULL ? ' ' :
240                             (mdev->net_conf->wire_protocol - DRBD_PROT_A+'A')),
241                            is_susp(mdev->state) ? 's' : 'r',
242                            mdev->state.aftr_isp ? 'a' : '-',
243                            mdev->state.peer_isp ? 'p' : '-',
244                            mdev->state.user_isp ? 'u' : '-',
245                            mdev->congestion_reason ?: '-',
246                            test_bit(AL_SUSPENDED, &mdev->flags) ? 's' : '-',
247                            mdev->send_cnt/2,
248                            mdev->recv_cnt/2,
249                            mdev->writ_cnt/2,
250                            mdev->read_cnt/2,
251                            mdev->al_writ_cnt,
252                            mdev->bm_writ_cnt,
253                            atomic_read(&mdev->local_cnt),
254                            atomic_read(&mdev->ap_pending_cnt) +
255                            atomic_read(&mdev->rs_pending_cnt),
256                            atomic_read(&mdev->unacked_cnt),
257                            atomic_read(&mdev->ap_bio_cnt),
258                            mdev->epochs,
259                            write_ordering_chars[mdev->write_ordering]
260                         );
261                         seq_printf(seq, " oos:%lu\n",
262                                    Bit2KB(drbd_bm_total_weight(mdev)));
263                 }
264                 if (mdev->state.conn == C_SYNC_SOURCE ||
265                     mdev->state.conn == C_SYNC_TARGET ||
266                     mdev->state.conn == C_VERIFY_S ||
267                     mdev->state.conn == C_VERIFY_T)
268                         drbd_syncer_progress(mdev, seq);
269
270                 if (mdev->state.conn == C_VERIFY_S || mdev->state.conn == C_VERIFY_T) {
271                         unsigned long bm_bits = drbd_bm_bits(mdev);
272                         seq_printf(seq, "\t%3d%%      %lu/%lu\n",
273                                    (int)((bm_bits-mdev->ov_left) /
274                                          (bm_bits/100+1)),
275                                    bm_bits - mdev->ov_left, bm_bits);
276                 }
277
278                 if (proc_details >= 1 && get_ldev_if_state(mdev, D_FAILED)) {
279                         lc_seq_printf_stats(seq, mdev->resync);
280                         lc_seq_printf_stats(seq, mdev->act_log);
281                         put_ldev(mdev);
282                 }
283
284                 if (proc_details >= 2) {
285                         if (mdev->resync) {
286                                 lc_seq_dump_details(seq, mdev->resync, "rs_left",
287                                         resync_dump_detail);
288                         }
289                 }
290         }
291
292         return 0;
293 }
294
295 static int drbd_proc_open(struct inode *inode, struct file *file)
296 {
297         return single_open(file, drbd_seq_show, PDE(inode)->data);
298 }
299
300 /* PROC FS stuff end */