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