1b411b363SPhilipp Reisner /* 2b411b363SPhilipp Reisner drbd_proc.c 3b411b363SPhilipp Reisner 4b411b363SPhilipp Reisner This file is part of DRBD by Philipp Reisner and Lars Ellenberg. 5b411b363SPhilipp Reisner 6b411b363SPhilipp Reisner Copyright (C) 2001-2008, LINBIT Information Technologies GmbH. 7b411b363SPhilipp Reisner Copyright (C) 1999-2008, Philipp Reisner <philipp.reisner@linbit.com>. 8b411b363SPhilipp Reisner Copyright (C) 2002-2008, Lars Ellenberg <lars.ellenberg@linbit.com>. 9b411b363SPhilipp Reisner 10b411b363SPhilipp Reisner drbd is free software; you can redistribute it and/or modify 11b411b363SPhilipp Reisner it under the terms of the GNU General Public License as published by 12b411b363SPhilipp Reisner the Free Software Foundation; either version 2, or (at your option) 13b411b363SPhilipp Reisner any later version. 14b411b363SPhilipp Reisner 15b411b363SPhilipp Reisner drbd is distributed in the hope that it will be useful, 16b411b363SPhilipp Reisner but WITHOUT ANY WARRANTY; without even the implied warranty of 17b411b363SPhilipp Reisner MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18b411b363SPhilipp Reisner GNU General Public License for more details. 19b411b363SPhilipp Reisner 20b411b363SPhilipp Reisner You should have received a copy of the GNU General Public License 21b411b363SPhilipp Reisner along with drbd; see the file COPYING. If not, write to 22b411b363SPhilipp Reisner the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 23b411b363SPhilipp Reisner 24b411b363SPhilipp Reisner */ 25b411b363SPhilipp Reisner 26b411b363SPhilipp Reisner #include <linux/module.h> 27b411b363SPhilipp Reisner 28b411b363SPhilipp Reisner #include <asm/uaccess.h> 29b411b363SPhilipp Reisner #include <linux/fs.h> 30b411b363SPhilipp Reisner #include <linux/file.h> 31b411b363SPhilipp Reisner #include <linux/proc_fs.h> 32b411b363SPhilipp Reisner #include <linux/seq_file.h> 33b411b363SPhilipp Reisner #include <linux/drbd.h> 34b411b363SPhilipp Reisner #include "drbd_int.h" 35b411b363SPhilipp Reisner 36b411b363SPhilipp Reisner static int drbd_proc_open(struct inode *inode, struct file *file); 37b411b363SPhilipp Reisner 38b411b363SPhilipp Reisner 39b411b363SPhilipp Reisner struct proc_dir_entry *drbd_proc; 407d4e9d09SEmese Revfy const struct file_operations drbd_proc_fops = { 41b411b363SPhilipp Reisner .owner = THIS_MODULE, 42b411b363SPhilipp Reisner .open = drbd_proc_open, 43b411b363SPhilipp Reisner .read = seq_read, 44b411b363SPhilipp Reisner .llseek = seq_lseek, 45b411b363SPhilipp Reisner .release = single_release, 46b411b363SPhilipp Reisner }; 47b411b363SPhilipp Reisner 48439d5953SLars Ellenberg void seq_printf_with_thousands_grouping(struct seq_file *seq, long v) 49439d5953SLars Ellenberg { 50439d5953SLars Ellenberg /* v is in kB/sec. We don't expect TiByte/sec yet. */ 51439d5953SLars Ellenberg if (unlikely(v >= 1000000)) { 52439d5953SLars Ellenberg /* cool: > GiByte/s */ 53439d5953SLars Ellenberg seq_printf(seq, "%ld,", v / 1000000); 54439d5953SLars Ellenberg v /= 1000000; 55439d5953SLars Ellenberg seq_printf(seq, "%03ld,%03ld", v/1000, v % 1000); 56439d5953SLars Ellenberg } else if (likely(v >= 1000)) 57439d5953SLars Ellenberg seq_printf(seq, "%ld,%03ld", v/1000, v % 1000); 58439d5953SLars Ellenberg else 59439d5953SLars Ellenberg seq_printf(seq, "%ld", v); 60439d5953SLars Ellenberg } 61b411b363SPhilipp Reisner 62b411b363SPhilipp Reisner /*lge 63b411b363SPhilipp Reisner * progress bars shamelessly adapted from driver/md/md.c 64b411b363SPhilipp Reisner * output looks like 65b411b363SPhilipp Reisner * [=====>..............] 33.5% (23456/123456) 66b411b363SPhilipp Reisner * finish: 2:20:20 speed: 6,345 (6,456) K/sec 67b411b363SPhilipp Reisner */ 68b411b363SPhilipp Reisner static void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq) 69b411b363SPhilipp Reisner { 70b411b363SPhilipp Reisner unsigned long db, dt, dbdt, rt, rs_left; 71b411b363SPhilipp Reisner unsigned int res; 72b411b363SPhilipp Reisner int i, x, y; 731d7734a0SLars Ellenberg int stalled = 0; 74b411b363SPhilipp Reisner 75b411b363SPhilipp Reisner drbd_get_syncer_progress(mdev, &rs_left, &res); 76b411b363SPhilipp Reisner 77b411b363SPhilipp Reisner x = res/50; 78b411b363SPhilipp Reisner y = 20-x; 79b411b363SPhilipp Reisner seq_printf(seq, "\t["); 80b411b363SPhilipp Reisner for (i = 1; i < x; i++) 81b411b363SPhilipp Reisner seq_printf(seq, "="); 82b411b363SPhilipp Reisner seq_printf(seq, ">"); 83b411b363SPhilipp Reisner for (i = 0; i < y; i++) 84b411b363SPhilipp Reisner seq_printf(seq, "."); 85b411b363SPhilipp Reisner seq_printf(seq, "] "); 86b411b363SPhilipp Reisner 875f9915bbSLars Ellenberg if (mdev->state.conn == C_VERIFY_S || mdev->state.conn == C_VERIFY_T) 885f9915bbSLars Ellenberg seq_printf(seq, "verified:"); 895f9915bbSLars Ellenberg else 905f9915bbSLars Ellenberg seq_printf(seq, "sync'ed:"); 915f9915bbSLars Ellenberg seq_printf(seq, "%3u.%u%% ", res / 10, res % 10); 925f9915bbSLars Ellenberg 93b411b363SPhilipp Reisner /* if more than 1 GB display in MB */ 94b411b363SPhilipp Reisner if (mdev->rs_total > 0x100000L) 95e7f52dfbSLars Ellenberg seq_printf(seq, "(%lu/%lu)M\n\t", 96b411b363SPhilipp Reisner (unsigned long) Bit2KB(rs_left >> 10), 97b411b363SPhilipp Reisner (unsigned long) Bit2KB(mdev->rs_total >> 10)); 98b411b363SPhilipp Reisner else 99e7f52dfbSLars Ellenberg seq_printf(seq, "(%lu/%lu)K\n\t", 100b411b363SPhilipp Reisner (unsigned long) Bit2KB(rs_left), 101b411b363SPhilipp Reisner (unsigned long) Bit2KB(mdev->rs_total)); 102b411b363SPhilipp Reisner 103b411b363SPhilipp Reisner /* see drivers/md/md.c 104b411b363SPhilipp Reisner * We do not want to overflow, so the order of operands and 105b411b363SPhilipp Reisner * the * 100 / 100 trick are important. We do a +1 to be 106b411b363SPhilipp Reisner * safe against division by zero. We only estimate anyway. 107b411b363SPhilipp Reisner * 108b411b363SPhilipp Reisner * dt: time from mark until now 109b411b363SPhilipp Reisner * db: blocks written from mark until now 110b411b363SPhilipp Reisner * rt: remaining time 111b411b363SPhilipp Reisner */ 1121d7734a0SLars Ellenberg /* Rolling marks. last_mark+1 may just now be modified. last_mark+2 is 1131d7734a0SLars Ellenberg * at least (DRBD_SYNC_MARKS-2)*DRBD_SYNC_MARK_STEP old, and has at 1141d7734a0SLars Ellenberg * least DRBD_SYNC_MARK_STEP time before it will be modified. */ 115439d5953SLars Ellenberg /* ------------------------ ~18s average ------------------------ */ 1161d7734a0SLars Ellenberg i = (mdev->rs_last_mark + 2) % DRBD_SYNC_MARKS; 1171d7734a0SLars Ellenberg dt = (jiffies - mdev->rs_mark_time[i]) / HZ; 1181d7734a0SLars Ellenberg if (dt > (DRBD_SYNC_MARK_STEP * DRBD_SYNC_MARKS)) 1191d7734a0SLars Ellenberg stalled = 1; 120b411b363SPhilipp Reisner 121b411b363SPhilipp Reisner if (!dt) 122b411b363SPhilipp Reisner dt++; 1231d7734a0SLars Ellenberg db = mdev->rs_mark_left[i] - rs_left; 124b411b363SPhilipp Reisner rt = (dt * (rs_left / (db/100+1)))/100; /* seconds */ 125b411b363SPhilipp Reisner 126b411b363SPhilipp Reisner seq_printf(seq, "finish: %lu:%02lu:%02lu", 127b411b363SPhilipp Reisner rt / 3600, (rt % 3600) / 60, rt % 60); 128b411b363SPhilipp Reisner 129b411b363SPhilipp Reisner dbdt = Bit2KB(db/dt); 130439d5953SLars Ellenberg seq_printf(seq, " speed: "); 131439d5953SLars Ellenberg seq_printf_with_thousands_grouping(seq, dbdt); 132439d5953SLars Ellenberg seq_printf(seq, " ("); 133439d5953SLars Ellenberg /* ------------------------- ~3s average ------------------------ */ 134439d5953SLars Ellenberg if (proc_details >= 1) { 135439d5953SLars Ellenberg /* this is what drbd_rs_should_slow_down() uses */ 136439d5953SLars Ellenberg i = (mdev->rs_last_mark + DRBD_SYNC_MARKS-1) % DRBD_SYNC_MARKS; 137439d5953SLars Ellenberg dt = (jiffies - mdev->rs_mark_time[i]) / HZ; 138439d5953SLars Ellenberg if (!dt) 139439d5953SLars Ellenberg dt++; 140439d5953SLars Ellenberg db = mdev->rs_mark_left[i] - rs_left; 141439d5953SLars Ellenberg dbdt = Bit2KB(db/dt); 142439d5953SLars Ellenberg seq_printf_with_thousands_grouping(seq, dbdt); 143439d5953SLars Ellenberg seq_printf(seq, " -- "); 144439d5953SLars Ellenberg } 145439d5953SLars Ellenberg 146439d5953SLars Ellenberg /* --------------------- long term average ---------------------- */ 147b411b363SPhilipp Reisner /* mean speed since syncer started 148b411b363SPhilipp Reisner * we do account for PausedSync periods */ 149b411b363SPhilipp Reisner dt = (jiffies - mdev->rs_start - mdev->rs_paused) / HZ; 15022657695SDan Carpenter if (dt == 0) 151b411b363SPhilipp Reisner dt = 1; 152b411b363SPhilipp Reisner db = mdev->rs_total - rs_left; 153b411b363SPhilipp Reisner dbdt = Bit2KB(db/dt); 154439d5953SLars Ellenberg seq_printf_with_thousands_grouping(seq, dbdt); 155439d5953SLars Ellenberg seq_printf(seq, ")"); 156b411b363SPhilipp Reisner 1572649f080SLars Ellenberg if (mdev->state.conn == C_SYNC_TARGET || 1582649f080SLars Ellenberg mdev->state.conn == C_VERIFY_S) { 1595f9915bbSLars Ellenberg seq_printf(seq, " want: "); 1605f9915bbSLars Ellenberg seq_printf_with_thousands_grouping(seq, mdev->c_sync_rate); 1611d7734a0SLars Ellenberg } 1621d7734a0SLars Ellenberg seq_printf(seq, " K/sec%s\n", stalled ? " (stalled)" : ""); 1635f9915bbSLars Ellenberg 1645f9915bbSLars Ellenberg if (proc_details >= 1) { 1655f9915bbSLars Ellenberg /* 64 bit: 1665f9915bbSLars Ellenberg * we convert to sectors in the display below. */ 167*4896e8c1SLars Ellenberg unsigned long bm_bits = drbd_bm_bits(mdev); 168*4896e8c1SLars Ellenberg unsigned long bit_pos; 1695f9915bbSLars Ellenberg if (mdev->state.conn == C_VERIFY_S || 1705f9915bbSLars Ellenberg mdev->state.conn == C_VERIFY_T) 1715f9915bbSLars Ellenberg bit_pos = bm_bits - mdev->ov_left; 1725f9915bbSLars Ellenberg else 1735f9915bbSLars Ellenberg bit_pos = mdev->bm_resync_fo; 1745f9915bbSLars Ellenberg /* Total sectors may be slightly off for oddly 1755f9915bbSLars Ellenberg * sized devices. So what. */ 1765f9915bbSLars Ellenberg seq_printf(seq, 1775f9915bbSLars Ellenberg "\t%3d%% sector pos: %llu/%llu\n", 1785f9915bbSLars Ellenberg (int)(bit_pos / (bm_bits/100+1)), 179*4896e8c1SLars Ellenberg (unsigned long long)bit_pos * BM_SECT_PER_BIT, 180*4896e8c1SLars Ellenberg (unsigned long long)bm_bits * BM_SECT_PER_BIT); 1815f9915bbSLars Ellenberg } 182b411b363SPhilipp Reisner } 183b411b363SPhilipp Reisner 184b411b363SPhilipp Reisner static void resync_dump_detail(struct seq_file *seq, struct lc_element *e) 185b411b363SPhilipp Reisner { 186b411b363SPhilipp Reisner struct bm_extent *bme = lc_entry(e, struct bm_extent, lce); 187b411b363SPhilipp Reisner 188b411b363SPhilipp Reisner seq_printf(seq, "%5d %s %s\n", bme->rs_left, 189b411b363SPhilipp Reisner bme->flags & BME_NO_WRITES ? "NO_WRITES" : "---------", 190b411b363SPhilipp Reisner bme->flags & BME_LOCKED ? "LOCKED" : "------" 191b411b363SPhilipp Reisner ); 192b411b363SPhilipp Reisner } 193b411b363SPhilipp Reisner 194b411b363SPhilipp Reisner static int drbd_seq_show(struct seq_file *seq, void *v) 195b411b363SPhilipp Reisner { 196b411b363SPhilipp Reisner int i, hole = 0; 197b411b363SPhilipp Reisner const char *sn; 198b411b363SPhilipp Reisner struct drbd_conf *mdev; 199b411b363SPhilipp Reisner 200b411b363SPhilipp Reisner static char write_ordering_chars[] = { 201b411b363SPhilipp Reisner [WO_none] = 'n', 202b411b363SPhilipp Reisner [WO_drain_io] = 'd', 203b411b363SPhilipp Reisner [WO_bdev_flush] = 'f', 204b411b363SPhilipp Reisner }; 205b411b363SPhilipp Reisner 206b411b363SPhilipp Reisner seq_printf(seq, "version: " REL_VERSION " (api:%d/proto:%d-%d)\n%s\n", 207b411b363SPhilipp Reisner API_VERSION, PRO_VERSION_MIN, PRO_VERSION_MAX, drbd_buildtag()); 208b411b363SPhilipp Reisner 209b411b363SPhilipp Reisner /* 210b411b363SPhilipp Reisner cs .. connection state 211b411b363SPhilipp Reisner ro .. node role (local/remote) 212b411b363SPhilipp Reisner ds .. disk state (local/remote) 213b411b363SPhilipp Reisner protocol 214b411b363SPhilipp Reisner various flags 215b411b363SPhilipp Reisner ns .. network send 216b411b363SPhilipp Reisner nr .. network receive 217b411b363SPhilipp Reisner dw .. disk write 218b411b363SPhilipp Reisner dr .. disk read 219b411b363SPhilipp Reisner al .. activity log write count 220b411b363SPhilipp Reisner bm .. bitmap update write count 221b411b363SPhilipp Reisner pe .. pending (waiting for ack or data reply) 222b411b363SPhilipp Reisner ua .. unack'd (still need to send ack or data reply) 223b411b363SPhilipp Reisner ap .. application requests accepted, but not yet completed 224b411b363SPhilipp Reisner ep .. number of epochs currently "on the fly", P_BARRIER_ACK pending 225b411b363SPhilipp Reisner wo .. write ordering mode currently in use 226b411b363SPhilipp Reisner oos .. known out-of-sync kB 227b411b363SPhilipp Reisner */ 228b411b363SPhilipp Reisner 229b411b363SPhilipp Reisner for (i = 0; i < minor_count; i++) { 230b411b363SPhilipp Reisner mdev = minor_to_mdev(i); 231b411b363SPhilipp Reisner if (!mdev) { 232b411b363SPhilipp Reisner hole = 1; 233b411b363SPhilipp Reisner continue; 234b411b363SPhilipp Reisner } 235b411b363SPhilipp Reisner if (hole) { 236b411b363SPhilipp Reisner hole = 0; 237b411b363SPhilipp Reisner seq_printf(seq, "\n"); 238b411b363SPhilipp Reisner } 239b411b363SPhilipp Reisner 240b411b363SPhilipp Reisner sn = drbd_conn_str(mdev->state.conn); 241b411b363SPhilipp Reisner 242b411b363SPhilipp Reisner if (mdev->state.conn == C_STANDALONE && 243b411b363SPhilipp Reisner mdev->state.disk == D_DISKLESS && 244b411b363SPhilipp Reisner mdev->state.role == R_SECONDARY) { 245b411b363SPhilipp Reisner seq_printf(seq, "%2d: cs:Unconfigured\n", i); 246b411b363SPhilipp Reisner } else { 247b411b363SPhilipp Reisner seq_printf(seq, 2480778286aSPhilipp Reisner "%2d: cs:%s ro:%s/%s ds:%s/%s %c %c%c%c%c%c%c\n" 249b411b363SPhilipp Reisner " ns:%u nr:%u dw:%u dr:%u al:%u bm:%u " 250b411b363SPhilipp Reisner "lo:%d pe:%d ua:%d ap:%d ep:%d wo:%c", 251b411b363SPhilipp Reisner i, sn, 252b411b363SPhilipp Reisner drbd_role_str(mdev->state.role), 253b411b363SPhilipp Reisner drbd_role_str(mdev->state.peer), 254b411b363SPhilipp Reisner drbd_disk_str(mdev->state.disk), 255b411b363SPhilipp Reisner drbd_disk_str(mdev->state.pdsk), 256b411b363SPhilipp Reisner (mdev->net_conf == NULL ? ' ' : 257b411b363SPhilipp Reisner (mdev->net_conf->wire_protocol - DRBD_PROT_A+'A')), 258fb22c402SPhilipp Reisner is_susp(mdev->state) ? 's' : 'r', 259b411b363SPhilipp Reisner mdev->state.aftr_isp ? 'a' : '-', 260b411b363SPhilipp Reisner mdev->state.peer_isp ? 'p' : '-', 261b411b363SPhilipp Reisner mdev->state.user_isp ? 'u' : '-', 262b411b363SPhilipp Reisner mdev->congestion_reason ?: '-', 2630778286aSPhilipp Reisner test_bit(AL_SUSPENDED, &mdev->flags) ? 's' : '-', 264b411b363SPhilipp Reisner mdev->send_cnt/2, 265b411b363SPhilipp Reisner mdev->recv_cnt/2, 266b411b363SPhilipp Reisner mdev->writ_cnt/2, 267b411b363SPhilipp Reisner mdev->read_cnt/2, 268b411b363SPhilipp Reisner mdev->al_writ_cnt, 269b411b363SPhilipp Reisner mdev->bm_writ_cnt, 270b411b363SPhilipp Reisner atomic_read(&mdev->local_cnt), 271b411b363SPhilipp Reisner atomic_read(&mdev->ap_pending_cnt) + 272b411b363SPhilipp Reisner atomic_read(&mdev->rs_pending_cnt), 273b411b363SPhilipp Reisner atomic_read(&mdev->unacked_cnt), 274b411b363SPhilipp Reisner atomic_read(&mdev->ap_bio_cnt), 275b411b363SPhilipp Reisner mdev->epochs, 276b411b363SPhilipp Reisner write_ordering_chars[mdev->write_ordering] 277b411b363SPhilipp Reisner ); 27818edc0b9SLars Ellenberg seq_printf(seq, " oos:%llu\n", 27918edc0b9SLars Ellenberg Bit2KB((unsigned long long) 28018edc0b9SLars Ellenberg drbd_bm_total_weight(mdev))); 281b411b363SPhilipp Reisner } 282b411b363SPhilipp Reisner if (mdev->state.conn == C_SYNC_SOURCE || 283439d5953SLars Ellenberg mdev->state.conn == C_SYNC_TARGET || 284439d5953SLars Ellenberg mdev->state.conn == C_VERIFY_S || 285439d5953SLars Ellenberg mdev->state.conn == C_VERIFY_T) 286b411b363SPhilipp Reisner drbd_syncer_progress(mdev, seq); 287b411b363SPhilipp Reisner 288b411b363SPhilipp Reisner if (proc_details >= 1 && get_ldev_if_state(mdev, D_FAILED)) { 289b411b363SPhilipp Reisner lc_seq_printf_stats(seq, mdev->resync); 290b411b363SPhilipp Reisner lc_seq_printf_stats(seq, mdev->act_log); 291b411b363SPhilipp Reisner put_ldev(mdev); 292b411b363SPhilipp Reisner } 293b411b363SPhilipp Reisner 294b411b363SPhilipp Reisner if (proc_details >= 2) { 295b411b363SPhilipp Reisner if (mdev->resync) { 296b411b363SPhilipp Reisner lc_seq_dump_details(seq, mdev->resync, "rs_left", 297b411b363SPhilipp Reisner resync_dump_detail); 298b411b363SPhilipp Reisner } 299b411b363SPhilipp Reisner } 300b411b363SPhilipp Reisner } 301b411b363SPhilipp Reisner 302b411b363SPhilipp Reisner return 0; 303b411b363SPhilipp Reisner } 304b411b363SPhilipp Reisner 305b411b363SPhilipp Reisner static int drbd_proc_open(struct inode *inode, struct file *file) 306b411b363SPhilipp Reisner { 307b411b363SPhilipp Reisner return single_open(file, drbd_seq_show, PDE(inode)->data); 308b411b363SPhilipp Reisner } 309b411b363SPhilipp Reisner 310b411b363SPhilipp Reisner /* PROC FS stuff end */ 311