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