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