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