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