1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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
36static int drbd_proc_open(struct inode *inode, struct file *file);
37static int drbd_proc_release(struct inode *inode, struct file *file);
38
39
40struct proc_dir_entry *drbd_proc;
41const struct file_operations drbd_proc_fops = {
42 .owner = THIS_MODULE,
43 .open = drbd_proc_open,
44 .read = seq_read,
45 .llseek = seq_lseek,
46 .release = drbd_proc_release,
47};
48
49void seq_printf_with_thousands_grouping(struct seq_file *seq, long v)
50{
51
52 if (unlikely(v >= 1000000)) {
53
54 seq_printf(seq, "%ld,", v / 1000000);
55 v %= 1000000;
56 seq_printf(seq, "%03ld,%03ld", v/1000, v % 1000);
57 } else if (likely(v >= 1000))
58 seq_printf(seq, "%ld,%03ld", v/1000, v % 1000);
59 else
60 seq_printf(seq, "%ld", v);
61}
62
63
64
65
66
67
68
69static void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq)
70{
71 unsigned long db, dt, dbdt, rt, rs_left;
72 unsigned int res;
73 int i, x, y;
74 int stalled = 0;
75
76 drbd_get_syncer_progress(mdev, &rs_left, &res);
77
78 x = res/50;
79 y = 20-x;
80 seq_printf(seq, "\t[");
81 for (i = 1; i < x; i++)
82 seq_printf(seq, "=");
83 seq_printf(seq, ">");
84 for (i = 0; i < y; i++)
85 seq_printf(seq, ".");
86 seq_printf(seq, "] ");
87
88 if (mdev->state.conn == C_VERIFY_S || mdev->state.conn == C_VERIFY_T)
89 seq_printf(seq, "verified:");
90 else
91 seq_printf(seq, "sync'ed:");
92 seq_printf(seq, "%3u.%u%% ", res / 10, res % 10);
93
94
95 if (mdev->rs_total > (4UL << (30 - BM_BLOCK_SHIFT)))
96 seq_printf(seq, "(%lu/%lu)M",
97 (unsigned long) Bit2KB(rs_left >> 10),
98 (unsigned long) Bit2KB(mdev->rs_total >> 10));
99 else
100 seq_printf(seq, "(%lu/%lu)K\n\t",
101 (unsigned long) Bit2KB(rs_left),
102 (unsigned long) Bit2KB(mdev->rs_total));
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117 i = (mdev->rs_last_mark + 2) % DRBD_SYNC_MARKS;
118 dt = (jiffies - mdev->rs_mark_time[i]) / HZ;
119 if (dt > (DRBD_SYNC_MARK_STEP * DRBD_SYNC_MARKS))
120 stalled = 1;
121
122 if (!dt)
123 dt++;
124 db = mdev->rs_mark_left[i] - rs_left;
125 rt = (dt * (rs_left / (db/100+1)))/100;
126
127 seq_printf(seq, "finish: %lu:%02lu:%02lu",
128 rt / 3600, (rt % 3600) / 60, rt % 60);
129
130 dbdt = Bit2KB(db/dt);
131 seq_printf(seq, " speed: ");
132 seq_printf_with_thousands_grouping(seq, dbdt);
133 seq_printf(seq, " (");
134
135 if (proc_details >= 1) {
136
137 i = (mdev->rs_last_mark + DRBD_SYNC_MARKS-1) % DRBD_SYNC_MARKS;
138 dt = (jiffies - mdev->rs_mark_time[i]) / HZ;
139 if (!dt)
140 dt++;
141 db = mdev->rs_mark_left[i] - rs_left;
142 dbdt = Bit2KB(db/dt);
143 seq_printf_with_thousands_grouping(seq, dbdt);
144 seq_printf(seq, " -- ");
145 }
146
147
148
149
150 dt = (jiffies - mdev->rs_start - mdev->rs_paused) / HZ;
151 if (dt == 0)
152 dt = 1;
153 db = mdev->rs_total - rs_left;
154 dbdt = Bit2KB(db/dt);
155 seq_printf_with_thousands_grouping(seq, dbdt);
156 seq_printf(seq, ")");
157
158 if (mdev->state.conn == C_SYNC_TARGET ||
159 mdev->state.conn == C_VERIFY_S) {
160 seq_printf(seq, " want: ");
161 seq_printf_with_thousands_grouping(seq, mdev->c_sync_rate);
162 }
163 seq_printf(seq, " K/sec%s\n", stalled ? " (stalled)" : "");
164
165 if (proc_details >= 1) {
166
167
168 unsigned long bm_bits = drbd_bm_bits(mdev);
169 unsigned long bit_pos;
170 unsigned long long stop_sector = 0;
171 if (mdev->state.conn == C_VERIFY_S ||
172 mdev->state.conn == C_VERIFY_T) {
173 bit_pos = bm_bits - mdev->ov_left;
174 if (verify_can_do_stop_sector(mdev))
175 stop_sector = mdev->ov_stop_sector;
176 } else
177 bit_pos = mdev->bm_resync_fo;
178
179
180 seq_printf(seq,
181 "\t%3d%% sector pos: %llu/%llu",
182 (int)(bit_pos / (bm_bits/100+1)),
183 (unsigned long long)bit_pos * BM_SECT_PER_BIT,
184 (unsigned long long)bm_bits * BM_SECT_PER_BIT);
185 if (stop_sector != 0 && stop_sector != ULLONG_MAX)
186 seq_printf(seq, " stop sector: %llu", stop_sector);
187 seq_printf(seq, "\n");
188 }
189}
190
191static void resync_dump_detail(struct seq_file *seq, struct lc_element *e)
192{
193 struct bm_extent *bme = lc_entry(e, struct bm_extent, lce);
194
195 seq_printf(seq, "%5d %s %s\n", bme->rs_left,
196 bme->flags & BME_NO_WRITES ? "NO_WRITES" : "---------",
197 bme->flags & BME_LOCKED ? "LOCKED" : "------"
198 );
199}
200
201static int drbd_seq_show(struct seq_file *seq, void *v)
202{
203 int i, prev_i = -1;
204 const char *sn;
205 struct drbd_conf *mdev;
206 struct net_conf *nc;
207 char wp;
208
209 static char write_ordering_chars[] = {
210 [WO_none] = 'n',
211 [WO_drain_io] = 'd',
212 [WO_bdev_flush] = 'f',
213 };
214
215 seq_printf(seq, "version: " REL_VERSION " (api:%d/proto:%d-%d)\n%s\n",
216 API_VERSION, PRO_VERSION_MIN, PRO_VERSION_MAX, drbd_buildtag());
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238 rcu_read_lock();
239 idr_for_each_entry(&minors, mdev, i) {
240 if (prev_i != i - 1)
241 seq_printf(seq, "\n");
242 prev_i = i;
243
244 sn = drbd_conn_str(mdev->state.conn);
245
246 if (mdev->state.conn == C_STANDALONE &&
247 mdev->state.disk == D_DISKLESS &&
248 mdev->state.role == R_SECONDARY) {
249 seq_printf(seq, "%2d: cs:Unconfigured\n", i);
250 } else {
251
252 bdi_rw_congested(&mdev->rq_queue->backing_dev_info);
253
254 nc = rcu_dereference(mdev->tconn->net_conf);
255 wp = nc ? nc->wire_protocol - DRBD_PROT_A + 'A' : ' ';
256 seq_printf(seq,
257 "%2d: cs:%s ro:%s/%s ds:%s/%s %c %c%c%c%c%c%c\n"
258 " ns:%u nr:%u dw:%u dr:%u al:%u bm:%u "
259 "lo:%d pe:%d ua:%d ap:%d ep:%d wo:%c",
260 i, sn,
261 drbd_role_str(mdev->state.role),
262 drbd_role_str(mdev->state.peer),
263 drbd_disk_str(mdev->state.disk),
264 drbd_disk_str(mdev->state.pdsk),
265 wp,
266 drbd_suspended(mdev) ? 's' : 'r',
267 mdev->state.aftr_isp ? 'a' : '-',
268 mdev->state.peer_isp ? 'p' : '-',
269 mdev->state.user_isp ? 'u' : '-',
270 mdev->congestion_reason ?: '-',
271 test_bit(AL_SUSPENDED, &mdev->flags) ? 's' : '-',
272 mdev->send_cnt/2,
273 mdev->recv_cnt/2,
274 mdev->writ_cnt/2,
275 mdev->read_cnt/2,
276 mdev->al_writ_cnt,
277 mdev->bm_writ_cnt,
278 atomic_read(&mdev->local_cnt),
279 atomic_read(&mdev->ap_pending_cnt) +
280 atomic_read(&mdev->rs_pending_cnt),
281 atomic_read(&mdev->unacked_cnt),
282 atomic_read(&mdev->ap_bio_cnt),
283 mdev->tconn->epochs,
284 write_ordering_chars[mdev->tconn->write_ordering]
285 );
286 seq_printf(seq, " oos:%llu\n",
287 Bit2KB((unsigned long long)
288 drbd_bm_total_weight(mdev)));
289 }
290 if (mdev->state.conn == C_SYNC_SOURCE ||
291 mdev->state.conn == C_SYNC_TARGET ||
292 mdev->state.conn == C_VERIFY_S ||
293 mdev->state.conn == C_VERIFY_T)
294 drbd_syncer_progress(mdev, seq);
295
296 if (proc_details >= 1 && get_ldev_if_state(mdev, D_FAILED)) {
297 lc_seq_printf_stats(seq, mdev->resync);
298 lc_seq_printf_stats(seq, mdev->act_log);
299 put_ldev(mdev);
300 }
301
302 if (proc_details >= 2) {
303 if (mdev->resync) {
304 lc_seq_dump_details(seq, mdev->resync, "rs_left",
305 resync_dump_detail);
306 }
307 }
308 }
309 rcu_read_unlock();
310
311 return 0;
312}
313
314static int drbd_proc_open(struct inode *inode, struct file *file)
315{
316 int err;
317
318 if (try_module_get(THIS_MODULE)) {
319 err = single_open(file, drbd_seq_show, PDE_DATA(inode));
320 if (err)
321 module_put(THIS_MODULE);
322 return err;
323 }
324 return -ENODEV;
325}
326
327static int drbd_proc_release(struct inode *inode, struct file *file)
328{
329 module_put(THIS_MODULE);
330 return single_release(inode, file);
331}
332
333
334