162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci drbd_proc.c 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci This file is part of DRBD by Philipp Reisner and Lars Ellenberg. 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci Copyright (C) 2001-2008, LINBIT Information Technologies GmbH. 862306a36Sopenharmony_ci Copyright (C) 1999-2008, Philipp Reisner <philipp.reisner@linbit.com>. 962306a36Sopenharmony_ci Copyright (C) 2002-2008, Lars Ellenberg <lars.ellenberg@linbit.com>. 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <linux/uaccess.h> 1762306a36Sopenharmony_ci#include <linux/fs.h> 1862306a36Sopenharmony_ci#include <linux/file.h> 1962306a36Sopenharmony_ci#include <linux/proc_fs.h> 2062306a36Sopenharmony_ci#include <linux/seq_file.h> 2162306a36Sopenharmony_ci#include <linux/drbd.h> 2262306a36Sopenharmony_ci#include "drbd_int.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistruct proc_dir_entry *drbd_proc; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic void seq_printf_with_thousands_grouping(struct seq_file *seq, long v) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci /* v is in kB/sec. We don't expect TiByte/sec yet. */ 2962306a36Sopenharmony_ci if (unlikely(v >= 1000000)) { 3062306a36Sopenharmony_ci /* cool: > GiByte/s */ 3162306a36Sopenharmony_ci seq_printf(seq, "%ld,", v / 1000000); 3262306a36Sopenharmony_ci v %= 1000000; 3362306a36Sopenharmony_ci seq_printf(seq, "%03ld,%03ld", v/1000, v % 1000); 3462306a36Sopenharmony_ci } else if (likely(v >= 1000)) 3562306a36Sopenharmony_ci seq_printf(seq, "%ld,%03ld", v/1000, v % 1000); 3662306a36Sopenharmony_ci else 3762306a36Sopenharmony_ci seq_printf(seq, "%ld", v); 3862306a36Sopenharmony_ci} 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic void drbd_get_syncer_progress(struct drbd_device *device, 4162306a36Sopenharmony_ci union drbd_dev_state state, unsigned long *rs_total, 4262306a36Sopenharmony_ci unsigned long *bits_left, unsigned int *per_mil_done) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci /* this is to break it at compile time when we change that, in case we 4562306a36Sopenharmony_ci * want to support more than (1<<32) bits on a 32bit arch. */ 4662306a36Sopenharmony_ci typecheck(unsigned long, device->rs_total); 4762306a36Sopenharmony_ci *rs_total = device->rs_total; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci /* note: both rs_total and rs_left are in bits, i.e. in 5062306a36Sopenharmony_ci * units of BM_BLOCK_SIZE. 5162306a36Sopenharmony_ci * for the percentage, we don't care. */ 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci if (state.conn == C_VERIFY_S || state.conn == C_VERIFY_T) 5462306a36Sopenharmony_ci *bits_left = device->ov_left; 5562306a36Sopenharmony_ci else 5662306a36Sopenharmony_ci *bits_left = drbd_bm_total_weight(device) - device->rs_failed; 5762306a36Sopenharmony_ci /* >> 10 to prevent overflow, 5862306a36Sopenharmony_ci * +1 to prevent division by zero */ 5962306a36Sopenharmony_ci if (*bits_left > *rs_total) { 6062306a36Sopenharmony_ci /* D'oh. Maybe a logic bug somewhere. More likely just a race 6162306a36Sopenharmony_ci * between state change and reset of rs_total. 6262306a36Sopenharmony_ci */ 6362306a36Sopenharmony_ci *bits_left = *rs_total; 6462306a36Sopenharmony_ci *per_mil_done = *rs_total ? 0 : 1000; 6562306a36Sopenharmony_ci } else { 6662306a36Sopenharmony_ci /* Make sure the division happens in long context. 6762306a36Sopenharmony_ci * We allow up to one petabyte storage right now, 6862306a36Sopenharmony_ci * at a granularity of 4k per bit that is 2**38 bits. 6962306a36Sopenharmony_ci * After shift right and multiplication by 1000, 7062306a36Sopenharmony_ci * this should still fit easily into a 32bit long, 7162306a36Sopenharmony_ci * so we don't need a 64bit division on 32bit arch. 7262306a36Sopenharmony_ci * Note: currently we don't support such large bitmaps on 32bit 7362306a36Sopenharmony_ci * arch anyways, but no harm done to be prepared for it here. 7462306a36Sopenharmony_ci */ 7562306a36Sopenharmony_ci unsigned int shift = *rs_total > UINT_MAX ? 16 : 10; 7662306a36Sopenharmony_ci unsigned long left = *bits_left >> shift; 7762306a36Sopenharmony_ci unsigned long total = 1UL + (*rs_total >> shift); 7862306a36Sopenharmony_ci unsigned long tmp = 1000UL - left * 1000UL/total; 7962306a36Sopenharmony_ci *per_mil_done = tmp; 8062306a36Sopenharmony_ci } 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci/*lge 8562306a36Sopenharmony_ci * progress bars shamelessly adapted from driver/md/md.c 8662306a36Sopenharmony_ci * output looks like 8762306a36Sopenharmony_ci * [=====>..............] 33.5% (23456/123456) 8862306a36Sopenharmony_ci * finish: 2:20:20 speed: 6,345 (6,456) K/sec 8962306a36Sopenharmony_ci */ 9062306a36Sopenharmony_cistatic void drbd_syncer_progress(struct drbd_device *device, struct seq_file *seq, 9162306a36Sopenharmony_ci union drbd_dev_state state) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci unsigned long db, dt, dbdt, rt, rs_total, rs_left; 9462306a36Sopenharmony_ci unsigned int res; 9562306a36Sopenharmony_ci int i, x, y; 9662306a36Sopenharmony_ci int stalled = 0; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci drbd_get_syncer_progress(device, state, &rs_total, &rs_left, &res); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci x = res/50; 10162306a36Sopenharmony_ci y = 20-x; 10262306a36Sopenharmony_ci seq_puts(seq, "\t["); 10362306a36Sopenharmony_ci for (i = 1; i < x; i++) 10462306a36Sopenharmony_ci seq_putc(seq, '='); 10562306a36Sopenharmony_ci seq_putc(seq, '>'); 10662306a36Sopenharmony_ci for (i = 0; i < y; i++) 10762306a36Sopenharmony_ci seq_putc(seq, '.'); 10862306a36Sopenharmony_ci seq_puts(seq, "] "); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci if (state.conn == C_VERIFY_S || state.conn == C_VERIFY_T) 11162306a36Sopenharmony_ci seq_puts(seq, "verified:"); 11262306a36Sopenharmony_ci else 11362306a36Sopenharmony_ci seq_puts(seq, "sync'ed:"); 11462306a36Sopenharmony_ci seq_printf(seq, "%3u.%u%% ", res / 10, res % 10); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci /* if more than a few GB, display in MB */ 11762306a36Sopenharmony_ci if (rs_total > (4UL << (30 - BM_BLOCK_SHIFT))) 11862306a36Sopenharmony_ci seq_printf(seq, "(%lu/%lu)M", 11962306a36Sopenharmony_ci (unsigned long) Bit2KB(rs_left >> 10), 12062306a36Sopenharmony_ci (unsigned long) Bit2KB(rs_total >> 10)); 12162306a36Sopenharmony_ci else 12262306a36Sopenharmony_ci seq_printf(seq, "(%lu/%lu)K", 12362306a36Sopenharmony_ci (unsigned long) Bit2KB(rs_left), 12462306a36Sopenharmony_ci (unsigned long) Bit2KB(rs_total)); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci seq_puts(seq, "\n\t"); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci /* see drivers/md/md.c 12962306a36Sopenharmony_ci * We do not want to overflow, so the order of operands and 13062306a36Sopenharmony_ci * the * 100 / 100 trick are important. We do a +1 to be 13162306a36Sopenharmony_ci * safe against division by zero. We only estimate anyway. 13262306a36Sopenharmony_ci * 13362306a36Sopenharmony_ci * dt: time from mark until now 13462306a36Sopenharmony_ci * db: blocks written from mark until now 13562306a36Sopenharmony_ci * rt: remaining time 13662306a36Sopenharmony_ci */ 13762306a36Sopenharmony_ci /* Rolling marks. last_mark+1 may just now be modified. last_mark+2 is 13862306a36Sopenharmony_ci * at least (DRBD_SYNC_MARKS-2)*DRBD_SYNC_MARK_STEP old, and has at 13962306a36Sopenharmony_ci * least DRBD_SYNC_MARK_STEP time before it will be modified. */ 14062306a36Sopenharmony_ci /* ------------------------ ~18s average ------------------------ */ 14162306a36Sopenharmony_ci i = (device->rs_last_mark + 2) % DRBD_SYNC_MARKS; 14262306a36Sopenharmony_ci dt = (jiffies - device->rs_mark_time[i]) / HZ; 14362306a36Sopenharmony_ci if (dt > 180) 14462306a36Sopenharmony_ci stalled = 1; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci if (!dt) 14762306a36Sopenharmony_ci dt++; 14862306a36Sopenharmony_ci db = device->rs_mark_left[i] - rs_left; 14962306a36Sopenharmony_ci rt = (dt * (rs_left / (db/100+1)))/100; /* seconds */ 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci seq_printf(seq, "finish: %lu:%02lu:%02lu", 15262306a36Sopenharmony_ci rt / 3600, (rt % 3600) / 60, rt % 60); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci dbdt = Bit2KB(db/dt); 15562306a36Sopenharmony_ci seq_puts(seq, " speed: "); 15662306a36Sopenharmony_ci seq_printf_with_thousands_grouping(seq, dbdt); 15762306a36Sopenharmony_ci seq_puts(seq, " ("); 15862306a36Sopenharmony_ci /* ------------------------- ~3s average ------------------------ */ 15962306a36Sopenharmony_ci if (drbd_proc_details >= 1) { 16062306a36Sopenharmony_ci /* this is what drbd_rs_should_slow_down() uses */ 16162306a36Sopenharmony_ci i = (device->rs_last_mark + DRBD_SYNC_MARKS-1) % DRBD_SYNC_MARKS; 16262306a36Sopenharmony_ci dt = (jiffies - device->rs_mark_time[i]) / HZ; 16362306a36Sopenharmony_ci if (!dt) 16462306a36Sopenharmony_ci dt++; 16562306a36Sopenharmony_ci db = device->rs_mark_left[i] - rs_left; 16662306a36Sopenharmony_ci dbdt = Bit2KB(db/dt); 16762306a36Sopenharmony_ci seq_printf_with_thousands_grouping(seq, dbdt); 16862306a36Sopenharmony_ci seq_puts(seq, " -- "); 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci /* --------------------- long term average ---------------------- */ 17262306a36Sopenharmony_ci /* mean speed since syncer started 17362306a36Sopenharmony_ci * we do account for PausedSync periods */ 17462306a36Sopenharmony_ci dt = (jiffies - device->rs_start - device->rs_paused) / HZ; 17562306a36Sopenharmony_ci if (dt == 0) 17662306a36Sopenharmony_ci dt = 1; 17762306a36Sopenharmony_ci db = rs_total - rs_left; 17862306a36Sopenharmony_ci dbdt = Bit2KB(db/dt); 17962306a36Sopenharmony_ci seq_printf_with_thousands_grouping(seq, dbdt); 18062306a36Sopenharmony_ci seq_putc(seq, ')'); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci if (state.conn == C_SYNC_TARGET || 18362306a36Sopenharmony_ci state.conn == C_VERIFY_S) { 18462306a36Sopenharmony_ci seq_puts(seq, " want: "); 18562306a36Sopenharmony_ci seq_printf_with_thousands_grouping(seq, device->c_sync_rate); 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci seq_printf(seq, " K/sec%s\n", stalled ? " (stalled)" : ""); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci if (drbd_proc_details >= 1) { 19062306a36Sopenharmony_ci /* 64 bit: 19162306a36Sopenharmony_ci * we convert to sectors in the display below. */ 19262306a36Sopenharmony_ci unsigned long bm_bits = drbd_bm_bits(device); 19362306a36Sopenharmony_ci unsigned long bit_pos; 19462306a36Sopenharmony_ci unsigned long long stop_sector = 0; 19562306a36Sopenharmony_ci if (state.conn == C_VERIFY_S || 19662306a36Sopenharmony_ci state.conn == C_VERIFY_T) { 19762306a36Sopenharmony_ci bit_pos = bm_bits - device->ov_left; 19862306a36Sopenharmony_ci if (verify_can_do_stop_sector(device)) 19962306a36Sopenharmony_ci stop_sector = device->ov_stop_sector; 20062306a36Sopenharmony_ci } else 20162306a36Sopenharmony_ci bit_pos = device->bm_resync_fo; 20262306a36Sopenharmony_ci /* Total sectors may be slightly off for oddly 20362306a36Sopenharmony_ci * sized devices. So what. */ 20462306a36Sopenharmony_ci seq_printf(seq, 20562306a36Sopenharmony_ci "\t%3d%% sector pos: %llu/%llu", 20662306a36Sopenharmony_ci (int)(bit_pos / (bm_bits/100+1)), 20762306a36Sopenharmony_ci (unsigned long long)bit_pos * BM_SECT_PER_BIT, 20862306a36Sopenharmony_ci (unsigned long long)bm_bits * BM_SECT_PER_BIT); 20962306a36Sopenharmony_ci if (stop_sector != 0 && stop_sector != ULLONG_MAX) 21062306a36Sopenharmony_ci seq_printf(seq, " stop sector: %llu", stop_sector); 21162306a36Sopenharmony_ci seq_putc(seq, '\n'); 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ciint drbd_seq_show(struct seq_file *seq, void *v) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci int i, prev_i = -1; 21862306a36Sopenharmony_ci const char *sn; 21962306a36Sopenharmony_ci struct drbd_device *device; 22062306a36Sopenharmony_ci struct net_conf *nc; 22162306a36Sopenharmony_ci union drbd_dev_state state; 22262306a36Sopenharmony_ci char wp; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci static char write_ordering_chars[] = { 22562306a36Sopenharmony_ci [WO_NONE] = 'n', 22662306a36Sopenharmony_ci [WO_DRAIN_IO] = 'd', 22762306a36Sopenharmony_ci [WO_BDEV_FLUSH] = 'f', 22862306a36Sopenharmony_ci }; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci seq_printf(seq, "version: " REL_VERSION " (api:%d/proto:%d-%d)\n%s\n", 23162306a36Sopenharmony_ci GENL_MAGIC_VERSION, PRO_VERSION_MIN, PRO_VERSION_MAX, drbd_buildtag()); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci /* 23462306a36Sopenharmony_ci cs .. connection state 23562306a36Sopenharmony_ci ro .. node role (local/remote) 23662306a36Sopenharmony_ci ds .. disk state (local/remote) 23762306a36Sopenharmony_ci protocol 23862306a36Sopenharmony_ci various flags 23962306a36Sopenharmony_ci ns .. network send 24062306a36Sopenharmony_ci nr .. network receive 24162306a36Sopenharmony_ci dw .. disk write 24262306a36Sopenharmony_ci dr .. disk read 24362306a36Sopenharmony_ci al .. activity log write count 24462306a36Sopenharmony_ci bm .. bitmap update write count 24562306a36Sopenharmony_ci pe .. pending (waiting for ack or data reply) 24662306a36Sopenharmony_ci ua .. unack'd (still need to send ack or data reply) 24762306a36Sopenharmony_ci ap .. application requests accepted, but not yet completed 24862306a36Sopenharmony_ci ep .. number of epochs currently "on the fly", P_BARRIER_ACK pending 24962306a36Sopenharmony_ci wo .. write ordering mode currently in use 25062306a36Sopenharmony_ci oos .. known out-of-sync kB 25162306a36Sopenharmony_ci */ 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci rcu_read_lock(); 25462306a36Sopenharmony_ci idr_for_each_entry(&drbd_devices, device, i) { 25562306a36Sopenharmony_ci if (prev_i != i - 1) 25662306a36Sopenharmony_ci seq_putc(seq, '\n'); 25762306a36Sopenharmony_ci prev_i = i; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci state = device->state; 26062306a36Sopenharmony_ci sn = drbd_conn_str(state.conn); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci if (state.conn == C_STANDALONE && 26362306a36Sopenharmony_ci state.disk == D_DISKLESS && 26462306a36Sopenharmony_ci state.role == R_SECONDARY) { 26562306a36Sopenharmony_ci seq_printf(seq, "%2d: cs:Unconfigured\n", i); 26662306a36Sopenharmony_ci } else { 26762306a36Sopenharmony_ci /* reset device->congestion_reason */ 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci nc = rcu_dereference(first_peer_device(device)->connection->net_conf); 27062306a36Sopenharmony_ci wp = nc ? nc->wire_protocol - DRBD_PROT_A + 'A' : ' '; 27162306a36Sopenharmony_ci seq_printf(seq, 27262306a36Sopenharmony_ci "%2d: cs:%s ro:%s/%s ds:%s/%s %c %c%c%c%c%c%c\n" 27362306a36Sopenharmony_ci " ns:%u nr:%u dw:%u dr:%u al:%u bm:%u " 27462306a36Sopenharmony_ci "lo:%d pe:%d ua:%d ap:%d ep:%d wo:%c", 27562306a36Sopenharmony_ci i, sn, 27662306a36Sopenharmony_ci drbd_role_str(state.role), 27762306a36Sopenharmony_ci drbd_role_str(state.peer), 27862306a36Sopenharmony_ci drbd_disk_str(state.disk), 27962306a36Sopenharmony_ci drbd_disk_str(state.pdsk), 28062306a36Sopenharmony_ci wp, 28162306a36Sopenharmony_ci drbd_suspended(device) ? 's' : 'r', 28262306a36Sopenharmony_ci state.aftr_isp ? 'a' : '-', 28362306a36Sopenharmony_ci state.peer_isp ? 'p' : '-', 28462306a36Sopenharmony_ci state.user_isp ? 'u' : '-', 28562306a36Sopenharmony_ci device->congestion_reason ?: '-', 28662306a36Sopenharmony_ci test_bit(AL_SUSPENDED, &device->flags) ? 's' : '-', 28762306a36Sopenharmony_ci device->send_cnt/2, 28862306a36Sopenharmony_ci device->recv_cnt/2, 28962306a36Sopenharmony_ci device->writ_cnt/2, 29062306a36Sopenharmony_ci device->read_cnt/2, 29162306a36Sopenharmony_ci device->al_writ_cnt, 29262306a36Sopenharmony_ci device->bm_writ_cnt, 29362306a36Sopenharmony_ci atomic_read(&device->local_cnt), 29462306a36Sopenharmony_ci atomic_read(&device->ap_pending_cnt) + 29562306a36Sopenharmony_ci atomic_read(&device->rs_pending_cnt), 29662306a36Sopenharmony_ci atomic_read(&device->unacked_cnt), 29762306a36Sopenharmony_ci atomic_read(&device->ap_bio_cnt), 29862306a36Sopenharmony_ci first_peer_device(device)->connection->epochs, 29962306a36Sopenharmony_ci write_ordering_chars[device->resource->write_ordering] 30062306a36Sopenharmony_ci ); 30162306a36Sopenharmony_ci seq_printf(seq, " oos:%llu\n", 30262306a36Sopenharmony_ci Bit2KB((unsigned long long) 30362306a36Sopenharmony_ci drbd_bm_total_weight(device))); 30462306a36Sopenharmony_ci } 30562306a36Sopenharmony_ci if (state.conn == C_SYNC_SOURCE || 30662306a36Sopenharmony_ci state.conn == C_SYNC_TARGET || 30762306a36Sopenharmony_ci state.conn == C_VERIFY_S || 30862306a36Sopenharmony_ci state.conn == C_VERIFY_T) 30962306a36Sopenharmony_ci drbd_syncer_progress(device, seq, state); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci if (drbd_proc_details >= 1 && get_ldev_if_state(device, D_FAILED)) { 31262306a36Sopenharmony_ci lc_seq_printf_stats(seq, device->resync); 31362306a36Sopenharmony_ci lc_seq_printf_stats(seq, device->act_log); 31462306a36Sopenharmony_ci put_ldev(device); 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci if (drbd_proc_details >= 2) 31862306a36Sopenharmony_ci seq_printf(seq, "\tblocked on activity log: %d\n", atomic_read(&device->ap_actlog_cnt)); 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci rcu_read_unlock(); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci return 0; 32362306a36Sopenharmony_ci} 324