162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci#define pr_fmt(fmt) "drbd debugfs: " fmt 362306a36Sopenharmony_ci#include <linux/kernel.h> 462306a36Sopenharmony_ci#include <linux/module.h> 562306a36Sopenharmony_ci#include <linux/debugfs.h> 662306a36Sopenharmony_ci#include <linux/seq_file.h> 762306a36Sopenharmony_ci#include <linux/stat.h> 862306a36Sopenharmony_ci#include <linux/jiffies.h> 962306a36Sopenharmony_ci#include <linux/list.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include "drbd_int.h" 1262306a36Sopenharmony_ci#include "drbd_req.h" 1362306a36Sopenharmony_ci#include "drbd_debugfs.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci/********************************************************************** 1762306a36Sopenharmony_ci * Whenever you change the file format, remember to bump the version. * 1862306a36Sopenharmony_ci **********************************************************************/ 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistatic struct dentry *drbd_debugfs_root; 2162306a36Sopenharmony_cistatic struct dentry *drbd_debugfs_version; 2262306a36Sopenharmony_cistatic struct dentry *drbd_debugfs_resources; 2362306a36Sopenharmony_cistatic struct dentry *drbd_debugfs_minors; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic void seq_print_age_or_dash(struct seq_file *m, bool valid, unsigned long dt) 2662306a36Sopenharmony_ci{ 2762306a36Sopenharmony_ci if (valid) 2862306a36Sopenharmony_ci seq_printf(m, "\t%d", jiffies_to_msecs(dt)); 2962306a36Sopenharmony_ci else 3062306a36Sopenharmony_ci seq_printf(m, "\t-"); 3162306a36Sopenharmony_ci} 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic void __seq_print_rq_state_bit(struct seq_file *m, 3462306a36Sopenharmony_ci bool is_set, char *sep, const char *set_name, const char *unset_name) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci if (is_set && set_name) { 3762306a36Sopenharmony_ci seq_putc(m, *sep); 3862306a36Sopenharmony_ci seq_puts(m, set_name); 3962306a36Sopenharmony_ci *sep = '|'; 4062306a36Sopenharmony_ci } else if (!is_set && unset_name) { 4162306a36Sopenharmony_ci seq_putc(m, *sep); 4262306a36Sopenharmony_ci seq_puts(m, unset_name); 4362306a36Sopenharmony_ci *sep = '|'; 4462306a36Sopenharmony_ci } 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic void seq_print_rq_state_bit(struct seq_file *m, 4862306a36Sopenharmony_ci bool is_set, char *sep, const char *set_name) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci __seq_print_rq_state_bit(m, is_set, sep, set_name, NULL); 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci/* pretty print enum drbd_req_state_bits req->rq_state */ 5462306a36Sopenharmony_cistatic void seq_print_request_state(struct seq_file *m, struct drbd_request *req) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci unsigned int s = req->rq_state; 5762306a36Sopenharmony_ci char sep = ' '; 5862306a36Sopenharmony_ci seq_printf(m, "\t0x%08x", s); 5962306a36Sopenharmony_ci seq_printf(m, "\tmaster: %s", req->master_bio ? "pending" : "completed"); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci /* RQ_WRITE ignored, already reported */ 6262306a36Sopenharmony_ci seq_puts(m, "\tlocal:"); 6362306a36Sopenharmony_ci seq_print_rq_state_bit(m, s & RQ_IN_ACT_LOG, &sep, "in-AL"); 6462306a36Sopenharmony_ci seq_print_rq_state_bit(m, s & RQ_POSTPONED, &sep, "postponed"); 6562306a36Sopenharmony_ci seq_print_rq_state_bit(m, s & RQ_COMPLETION_SUSP, &sep, "suspended"); 6662306a36Sopenharmony_ci sep = ' '; 6762306a36Sopenharmony_ci seq_print_rq_state_bit(m, s & RQ_LOCAL_PENDING, &sep, "pending"); 6862306a36Sopenharmony_ci seq_print_rq_state_bit(m, s & RQ_LOCAL_COMPLETED, &sep, "completed"); 6962306a36Sopenharmony_ci seq_print_rq_state_bit(m, s & RQ_LOCAL_ABORTED, &sep, "aborted"); 7062306a36Sopenharmony_ci seq_print_rq_state_bit(m, s & RQ_LOCAL_OK, &sep, "ok"); 7162306a36Sopenharmony_ci if (sep == ' ') 7262306a36Sopenharmony_ci seq_puts(m, " -"); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci /* for_each_connection ... */ 7562306a36Sopenharmony_ci seq_printf(m, "\tnet:"); 7662306a36Sopenharmony_ci sep = ' '; 7762306a36Sopenharmony_ci seq_print_rq_state_bit(m, s & RQ_NET_PENDING, &sep, "pending"); 7862306a36Sopenharmony_ci seq_print_rq_state_bit(m, s & RQ_NET_QUEUED, &sep, "queued"); 7962306a36Sopenharmony_ci seq_print_rq_state_bit(m, s & RQ_NET_SENT, &sep, "sent"); 8062306a36Sopenharmony_ci seq_print_rq_state_bit(m, s & RQ_NET_DONE, &sep, "done"); 8162306a36Sopenharmony_ci seq_print_rq_state_bit(m, s & RQ_NET_SIS, &sep, "sis"); 8262306a36Sopenharmony_ci seq_print_rq_state_bit(m, s & RQ_NET_OK, &sep, "ok"); 8362306a36Sopenharmony_ci if (sep == ' ') 8462306a36Sopenharmony_ci seq_puts(m, " -"); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci seq_printf(m, " :"); 8762306a36Sopenharmony_ci sep = ' '; 8862306a36Sopenharmony_ci seq_print_rq_state_bit(m, s & RQ_EXP_RECEIVE_ACK, &sep, "B"); 8962306a36Sopenharmony_ci seq_print_rq_state_bit(m, s & RQ_EXP_WRITE_ACK, &sep, "C"); 9062306a36Sopenharmony_ci seq_print_rq_state_bit(m, s & RQ_EXP_BARR_ACK, &sep, "barr"); 9162306a36Sopenharmony_ci if (sep == ' ') 9262306a36Sopenharmony_ci seq_puts(m, " -"); 9362306a36Sopenharmony_ci seq_printf(m, "\n"); 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cistatic void seq_print_one_request(struct seq_file *m, struct drbd_request *req, unsigned long now) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci /* change anything here, fixup header below! */ 9962306a36Sopenharmony_ci unsigned int s = req->rq_state; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci#define RQ_HDR_1 "epoch\tsector\tsize\trw" 10262306a36Sopenharmony_ci seq_printf(m, "0x%x\t%llu\t%u\t%s", 10362306a36Sopenharmony_ci req->epoch, 10462306a36Sopenharmony_ci (unsigned long long)req->i.sector, req->i.size >> 9, 10562306a36Sopenharmony_ci (s & RQ_WRITE) ? "W" : "R"); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci#define RQ_HDR_2 "\tstart\tin AL\tsubmit" 10862306a36Sopenharmony_ci seq_printf(m, "\t%d", jiffies_to_msecs(now - req->start_jif)); 10962306a36Sopenharmony_ci seq_print_age_or_dash(m, s & RQ_IN_ACT_LOG, now - req->in_actlog_jif); 11062306a36Sopenharmony_ci seq_print_age_or_dash(m, s & RQ_LOCAL_PENDING, now - req->pre_submit_jif); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci#define RQ_HDR_3 "\tsent\tacked\tdone" 11362306a36Sopenharmony_ci seq_print_age_or_dash(m, s & RQ_NET_SENT, now - req->pre_send_jif); 11462306a36Sopenharmony_ci seq_print_age_or_dash(m, (s & RQ_NET_SENT) && !(s & RQ_NET_PENDING), now - req->acked_jif); 11562306a36Sopenharmony_ci seq_print_age_or_dash(m, s & RQ_NET_DONE, now - req->net_done_jif); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci#define RQ_HDR_4 "\tstate\n" 11862306a36Sopenharmony_ci seq_print_request_state(m, req); 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci#define RQ_HDR RQ_HDR_1 RQ_HDR_2 RQ_HDR_3 RQ_HDR_4 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic void seq_print_minor_vnr_req(struct seq_file *m, struct drbd_request *req, unsigned long now) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci seq_printf(m, "%u\t%u\t", req->device->minor, req->device->vnr); 12562306a36Sopenharmony_ci seq_print_one_request(m, req, now); 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic void seq_print_resource_pending_meta_io(struct seq_file *m, struct drbd_resource *resource, unsigned long now) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci struct drbd_device *device; 13162306a36Sopenharmony_ci unsigned int i; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci seq_puts(m, "minor\tvnr\tstart\tsubmit\tintent\n"); 13462306a36Sopenharmony_ci rcu_read_lock(); 13562306a36Sopenharmony_ci idr_for_each_entry(&resource->devices, device, i) { 13662306a36Sopenharmony_ci struct drbd_md_io tmp; 13762306a36Sopenharmony_ci /* In theory this is racy, 13862306a36Sopenharmony_ci * in the sense that there could have been a 13962306a36Sopenharmony_ci * drbd_md_put_buffer(); drbd_md_get_buffer(); 14062306a36Sopenharmony_ci * between accessing these members here. */ 14162306a36Sopenharmony_ci tmp = device->md_io; 14262306a36Sopenharmony_ci if (atomic_read(&tmp.in_use)) { 14362306a36Sopenharmony_ci seq_printf(m, "%u\t%u\t%d\t", 14462306a36Sopenharmony_ci device->minor, device->vnr, 14562306a36Sopenharmony_ci jiffies_to_msecs(now - tmp.start_jif)); 14662306a36Sopenharmony_ci if (time_before(tmp.submit_jif, tmp.start_jif)) 14762306a36Sopenharmony_ci seq_puts(m, "-\t"); 14862306a36Sopenharmony_ci else 14962306a36Sopenharmony_ci seq_printf(m, "%d\t", jiffies_to_msecs(now - tmp.submit_jif)); 15062306a36Sopenharmony_ci seq_printf(m, "%s\n", tmp.current_use); 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci rcu_read_unlock(); 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cistatic void seq_print_waiting_for_AL(struct seq_file *m, struct drbd_resource *resource, unsigned long now) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci struct drbd_device *device; 15962306a36Sopenharmony_ci unsigned int i; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci seq_puts(m, "minor\tvnr\tage\t#waiting\n"); 16262306a36Sopenharmony_ci rcu_read_lock(); 16362306a36Sopenharmony_ci idr_for_each_entry(&resource->devices, device, i) { 16462306a36Sopenharmony_ci unsigned long jif; 16562306a36Sopenharmony_ci struct drbd_request *req; 16662306a36Sopenharmony_ci int n = atomic_read(&device->ap_actlog_cnt); 16762306a36Sopenharmony_ci if (n) { 16862306a36Sopenharmony_ci spin_lock_irq(&device->resource->req_lock); 16962306a36Sopenharmony_ci req = list_first_entry_or_null(&device->pending_master_completion[1], 17062306a36Sopenharmony_ci struct drbd_request, req_pending_master_completion); 17162306a36Sopenharmony_ci /* if the oldest request does not wait for the activity log 17262306a36Sopenharmony_ci * it is not interesting for us here */ 17362306a36Sopenharmony_ci if (req && !(req->rq_state & RQ_IN_ACT_LOG)) 17462306a36Sopenharmony_ci jif = req->start_jif; 17562306a36Sopenharmony_ci else 17662306a36Sopenharmony_ci req = NULL; 17762306a36Sopenharmony_ci spin_unlock_irq(&device->resource->req_lock); 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci if (n) { 18062306a36Sopenharmony_ci seq_printf(m, "%u\t%u\t", device->minor, device->vnr); 18162306a36Sopenharmony_ci if (req) 18262306a36Sopenharmony_ci seq_printf(m, "%u\t", jiffies_to_msecs(now - jif)); 18362306a36Sopenharmony_ci else 18462306a36Sopenharmony_ci seq_puts(m, "-\t"); 18562306a36Sopenharmony_ci seq_printf(m, "%u\n", n); 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci rcu_read_unlock(); 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistatic void seq_print_device_bitmap_io(struct seq_file *m, struct drbd_device *device, unsigned long now) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci struct drbd_bm_aio_ctx *ctx; 19462306a36Sopenharmony_ci unsigned long start_jif; 19562306a36Sopenharmony_ci unsigned int in_flight; 19662306a36Sopenharmony_ci unsigned int flags; 19762306a36Sopenharmony_ci spin_lock_irq(&device->resource->req_lock); 19862306a36Sopenharmony_ci ctx = list_first_entry_or_null(&device->pending_bitmap_io, struct drbd_bm_aio_ctx, list); 19962306a36Sopenharmony_ci if (ctx && ctx->done) 20062306a36Sopenharmony_ci ctx = NULL; 20162306a36Sopenharmony_ci if (ctx) { 20262306a36Sopenharmony_ci start_jif = ctx->start_jif; 20362306a36Sopenharmony_ci in_flight = atomic_read(&ctx->in_flight); 20462306a36Sopenharmony_ci flags = ctx->flags; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci spin_unlock_irq(&device->resource->req_lock); 20762306a36Sopenharmony_ci if (ctx) { 20862306a36Sopenharmony_ci seq_printf(m, "%u\t%u\t%c\t%u\t%u\n", 20962306a36Sopenharmony_ci device->minor, device->vnr, 21062306a36Sopenharmony_ci (flags & BM_AIO_READ) ? 'R' : 'W', 21162306a36Sopenharmony_ci jiffies_to_msecs(now - start_jif), 21262306a36Sopenharmony_ci in_flight); 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic void seq_print_resource_pending_bitmap_io(struct seq_file *m, struct drbd_resource *resource, unsigned long now) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci struct drbd_device *device; 21962306a36Sopenharmony_ci unsigned int i; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci seq_puts(m, "minor\tvnr\trw\tage\t#in-flight\n"); 22262306a36Sopenharmony_ci rcu_read_lock(); 22362306a36Sopenharmony_ci idr_for_each_entry(&resource->devices, device, i) { 22462306a36Sopenharmony_ci seq_print_device_bitmap_io(m, device, now); 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci rcu_read_unlock(); 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci/* pretty print enum peer_req->flags */ 23062306a36Sopenharmony_cistatic void seq_print_peer_request_flags(struct seq_file *m, struct drbd_peer_request *peer_req) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci unsigned long f = peer_req->flags; 23362306a36Sopenharmony_ci char sep = ' '; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci __seq_print_rq_state_bit(m, f & EE_SUBMITTED, &sep, "submitted", "preparing"); 23662306a36Sopenharmony_ci __seq_print_rq_state_bit(m, f & EE_APPLICATION, &sep, "application", "internal"); 23762306a36Sopenharmony_ci seq_print_rq_state_bit(m, f & EE_CALL_AL_COMPLETE_IO, &sep, "in-AL"); 23862306a36Sopenharmony_ci seq_print_rq_state_bit(m, f & EE_SEND_WRITE_ACK, &sep, "C"); 23962306a36Sopenharmony_ci seq_print_rq_state_bit(m, f & EE_MAY_SET_IN_SYNC, &sep, "set-in-sync"); 24062306a36Sopenharmony_ci seq_print_rq_state_bit(m, f & EE_TRIM, &sep, "trim"); 24162306a36Sopenharmony_ci seq_print_rq_state_bit(m, f & EE_ZEROOUT, &sep, "zero-out"); 24262306a36Sopenharmony_ci seq_print_rq_state_bit(m, f & EE_WRITE_SAME, &sep, "write-same"); 24362306a36Sopenharmony_ci seq_putc(m, '\n'); 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistatic void seq_print_peer_request(struct seq_file *m, 24762306a36Sopenharmony_ci struct drbd_device *device, struct list_head *lh, 24862306a36Sopenharmony_ci unsigned long now) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci bool reported_preparing = false; 25162306a36Sopenharmony_ci struct drbd_peer_request *peer_req; 25262306a36Sopenharmony_ci list_for_each_entry(peer_req, lh, w.list) { 25362306a36Sopenharmony_ci if (reported_preparing && !(peer_req->flags & EE_SUBMITTED)) 25462306a36Sopenharmony_ci continue; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if (device) 25762306a36Sopenharmony_ci seq_printf(m, "%u\t%u\t", device->minor, device->vnr); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci seq_printf(m, "%llu\t%u\t%c\t%u\t", 26062306a36Sopenharmony_ci (unsigned long long)peer_req->i.sector, peer_req->i.size >> 9, 26162306a36Sopenharmony_ci (peer_req->flags & EE_WRITE) ? 'W' : 'R', 26262306a36Sopenharmony_ci jiffies_to_msecs(now - peer_req->submit_jif)); 26362306a36Sopenharmony_ci seq_print_peer_request_flags(m, peer_req); 26462306a36Sopenharmony_ci if (peer_req->flags & EE_SUBMITTED) 26562306a36Sopenharmony_ci break; 26662306a36Sopenharmony_ci else 26762306a36Sopenharmony_ci reported_preparing = true; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic void seq_print_device_peer_requests(struct seq_file *m, 27262306a36Sopenharmony_ci struct drbd_device *device, unsigned long now) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci seq_puts(m, "minor\tvnr\tsector\tsize\trw\tage\tflags\n"); 27562306a36Sopenharmony_ci spin_lock_irq(&device->resource->req_lock); 27662306a36Sopenharmony_ci seq_print_peer_request(m, device, &device->active_ee, now); 27762306a36Sopenharmony_ci seq_print_peer_request(m, device, &device->read_ee, now); 27862306a36Sopenharmony_ci seq_print_peer_request(m, device, &device->sync_ee, now); 27962306a36Sopenharmony_ci spin_unlock_irq(&device->resource->req_lock); 28062306a36Sopenharmony_ci if (test_bit(FLUSH_PENDING, &device->flags)) { 28162306a36Sopenharmony_ci seq_printf(m, "%u\t%u\t-\t-\tF\t%u\tflush\n", 28262306a36Sopenharmony_ci device->minor, device->vnr, 28362306a36Sopenharmony_ci jiffies_to_msecs(now - device->flush_jif)); 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci} 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_cistatic void seq_print_resource_pending_peer_requests(struct seq_file *m, 28862306a36Sopenharmony_ci struct drbd_resource *resource, unsigned long now) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci struct drbd_device *device; 29162306a36Sopenharmony_ci unsigned int i; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci rcu_read_lock(); 29462306a36Sopenharmony_ci idr_for_each_entry(&resource->devices, device, i) { 29562306a36Sopenharmony_ci seq_print_device_peer_requests(m, device, now); 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci rcu_read_unlock(); 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cistatic void seq_print_resource_transfer_log_summary(struct seq_file *m, 30162306a36Sopenharmony_ci struct drbd_resource *resource, 30262306a36Sopenharmony_ci struct drbd_connection *connection, 30362306a36Sopenharmony_ci unsigned long now) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci struct drbd_request *req; 30662306a36Sopenharmony_ci unsigned int count = 0; 30762306a36Sopenharmony_ci unsigned int show_state = 0; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci seq_puts(m, "n\tdevice\tvnr\t" RQ_HDR); 31062306a36Sopenharmony_ci spin_lock_irq(&resource->req_lock); 31162306a36Sopenharmony_ci list_for_each_entry(req, &connection->transfer_log, tl_requests) { 31262306a36Sopenharmony_ci unsigned int tmp = 0; 31362306a36Sopenharmony_ci unsigned int s; 31462306a36Sopenharmony_ci ++count; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci /* don't disable irq "forever" */ 31762306a36Sopenharmony_ci if (!(count & 0x1ff)) { 31862306a36Sopenharmony_ci struct drbd_request *req_next; 31962306a36Sopenharmony_ci kref_get(&req->kref); 32062306a36Sopenharmony_ci spin_unlock_irq(&resource->req_lock); 32162306a36Sopenharmony_ci cond_resched(); 32262306a36Sopenharmony_ci spin_lock_irq(&resource->req_lock); 32362306a36Sopenharmony_ci req_next = list_next_entry(req, tl_requests); 32462306a36Sopenharmony_ci if (kref_put(&req->kref, drbd_req_destroy)) 32562306a36Sopenharmony_ci req = req_next; 32662306a36Sopenharmony_ci if (&req->tl_requests == &connection->transfer_log) 32762306a36Sopenharmony_ci break; 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci s = req->rq_state; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci /* This is meant to summarize timing issues, to be able to tell 33362306a36Sopenharmony_ci * local disk problems from network problems. 33462306a36Sopenharmony_ci * Skip requests, if we have shown an even older request with 33562306a36Sopenharmony_ci * similar aspects already. */ 33662306a36Sopenharmony_ci if (req->master_bio == NULL) 33762306a36Sopenharmony_ci tmp |= 1; 33862306a36Sopenharmony_ci if ((s & RQ_LOCAL_MASK) && (s & RQ_LOCAL_PENDING)) 33962306a36Sopenharmony_ci tmp |= 2; 34062306a36Sopenharmony_ci if (s & RQ_NET_MASK) { 34162306a36Sopenharmony_ci if (!(s & RQ_NET_SENT)) 34262306a36Sopenharmony_ci tmp |= 4; 34362306a36Sopenharmony_ci if (s & RQ_NET_PENDING) 34462306a36Sopenharmony_ci tmp |= 8; 34562306a36Sopenharmony_ci if (!(s & RQ_NET_DONE)) 34662306a36Sopenharmony_ci tmp |= 16; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci if ((tmp & show_state) == tmp) 34962306a36Sopenharmony_ci continue; 35062306a36Sopenharmony_ci show_state |= tmp; 35162306a36Sopenharmony_ci seq_printf(m, "%u\t", count); 35262306a36Sopenharmony_ci seq_print_minor_vnr_req(m, req, now); 35362306a36Sopenharmony_ci if (show_state == 0x1f) 35462306a36Sopenharmony_ci break; 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci spin_unlock_irq(&resource->req_lock); 35762306a36Sopenharmony_ci} 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci/* TODO: transfer_log and friends should be moved to resource */ 36062306a36Sopenharmony_cistatic int in_flight_summary_show(struct seq_file *m, void *pos) 36162306a36Sopenharmony_ci{ 36262306a36Sopenharmony_ci struct drbd_resource *resource = m->private; 36362306a36Sopenharmony_ci struct drbd_connection *connection; 36462306a36Sopenharmony_ci unsigned long jif = jiffies; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci connection = first_connection(resource); 36762306a36Sopenharmony_ci /* This does not happen, actually. 36862306a36Sopenharmony_ci * But be robust and prepare for future code changes. */ 36962306a36Sopenharmony_ci if (!connection || !kref_get_unless_zero(&connection->kref)) 37062306a36Sopenharmony_ci return -ESTALE; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci /* BUMP me if you change the file format/content/presentation */ 37362306a36Sopenharmony_ci seq_printf(m, "v: %u\n\n", 0); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci seq_puts(m, "oldest bitmap IO\n"); 37662306a36Sopenharmony_ci seq_print_resource_pending_bitmap_io(m, resource, jif); 37762306a36Sopenharmony_ci seq_putc(m, '\n'); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci seq_puts(m, "meta data IO\n"); 38062306a36Sopenharmony_ci seq_print_resource_pending_meta_io(m, resource, jif); 38162306a36Sopenharmony_ci seq_putc(m, '\n'); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci seq_puts(m, "socket buffer stats\n"); 38462306a36Sopenharmony_ci /* for each connection ... once we have more than one */ 38562306a36Sopenharmony_ci rcu_read_lock(); 38662306a36Sopenharmony_ci if (connection->data.socket) { 38762306a36Sopenharmony_ci /* open coded SIOCINQ, the "relevant" part */ 38862306a36Sopenharmony_ci struct tcp_sock *tp = tcp_sk(connection->data.socket->sk); 38962306a36Sopenharmony_ci int answ = tp->rcv_nxt - tp->copied_seq; 39062306a36Sopenharmony_ci seq_printf(m, "unread receive buffer: %u Byte\n", answ); 39162306a36Sopenharmony_ci /* open coded SIOCOUTQ, the "relevant" part */ 39262306a36Sopenharmony_ci answ = tp->write_seq - tp->snd_una; 39362306a36Sopenharmony_ci seq_printf(m, "unacked send buffer: %u Byte\n", answ); 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci rcu_read_unlock(); 39662306a36Sopenharmony_ci seq_putc(m, '\n'); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci seq_puts(m, "oldest peer requests\n"); 39962306a36Sopenharmony_ci seq_print_resource_pending_peer_requests(m, resource, jif); 40062306a36Sopenharmony_ci seq_putc(m, '\n'); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci seq_puts(m, "application requests waiting for activity log\n"); 40362306a36Sopenharmony_ci seq_print_waiting_for_AL(m, resource, jif); 40462306a36Sopenharmony_ci seq_putc(m, '\n'); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci seq_puts(m, "oldest application requests\n"); 40762306a36Sopenharmony_ci seq_print_resource_transfer_log_summary(m, resource, connection, jif); 40862306a36Sopenharmony_ci seq_putc(m, '\n'); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci jif = jiffies - jif; 41162306a36Sopenharmony_ci if (jif) 41262306a36Sopenharmony_ci seq_printf(m, "generated in %d ms\n", jiffies_to_msecs(jif)); 41362306a36Sopenharmony_ci kref_put(&connection->kref, drbd_destroy_connection); 41462306a36Sopenharmony_ci return 0; 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci/* make sure at *open* time that the respective object won't go away. */ 41862306a36Sopenharmony_cistatic int drbd_single_open(struct file *file, int (*show)(struct seq_file *, void *), 41962306a36Sopenharmony_ci void *data, struct kref *kref, 42062306a36Sopenharmony_ci void (*release)(struct kref *)) 42162306a36Sopenharmony_ci{ 42262306a36Sopenharmony_ci struct dentry *parent; 42362306a36Sopenharmony_ci int ret = -ESTALE; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci /* Are we still linked, 42662306a36Sopenharmony_ci * or has debugfs_remove() already been called? */ 42762306a36Sopenharmony_ci parent = file->f_path.dentry->d_parent; 42862306a36Sopenharmony_ci /* serialize with d_delete() */ 42962306a36Sopenharmony_ci inode_lock(d_inode(parent)); 43062306a36Sopenharmony_ci /* Make sure the object is still alive */ 43162306a36Sopenharmony_ci if (simple_positive(file->f_path.dentry) 43262306a36Sopenharmony_ci && kref_get_unless_zero(kref)) 43362306a36Sopenharmony_ci ret = 0; 43462306a36Sopenharmony_ci inode_unlock(d_inode(parent)); 43562306a36Sopenharmony_ci if (!ret) { 43662306a36Sopenharmony_ci ret = single_open(file, show, data); 43762306a36Sopenharmony_ci if (ret) 43862306a36Sopenharmony_ci kref_put(kref, release); 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci return ret; 44162306a36Sopenharmony_ci} 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_cistatic int in_flight_summary_open(struct inode *inode, struct file *file) 44462306a36Sopenharmony_ci{ 44562306a36Sopenharmony_ci struct drbd_resource *resource = inode->i_private; 44662306a36Sopenharmony_ci return drbd_single_open(file, in_flight_summary_show, resource, 44762306a36Sopenharmony_ci &resource->kref, drbd_destroy_resource); 44862306a36Sopenharmony_ci} 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_cistatic int in_flight_summary_release(struct inode *inode, struct file *file) 45162306a36Sopenharmony_ci{ 45262306a36Sopenharmony_ci struct drbd_resource *resource = inode->i_private; 45362306a36Sopenharmony_ci kref_put(&resource->kref, drbd_destroy_resource); 45462306a36Sopenharmony_ci return single_release(inode, file); 45562306a36Sopenharmony_ci} 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_cistatic const struct file_operations in_flight_summary_fops = { 45862306a36Sopenharmony_ci .owner = THIS_MODULE, 45962306a36Sopenharmony_ci .open = in_flight_summary_open, 46062306a36Sopenharmony_ci .read = seq_read, 46162306a36Sopenharmony_ci .llseek = seq_lseek, 46262306a36Sopenharmony_ci .release = in_flight_summary_release, 46362306a36Sopenharmony_ci}; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_civoid drbd_debugfs_resource_add(struct drbd_resource *resource) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci struct dentry *dentry; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci dentry = debugfs_create_dir(resource->name, drbd_debugfs_resources); 47062306a36Sopenharmony_ci resource->debugfs_res = dentry; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci dentry = debugfs_create_dir("volumes", resource->debugfs_res); 47362306a36Sopenharmony_ci resource->debugfs_res_volumes = dentry; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci dentry = debugfs_create_dir("connections", resource->debugfs_res); 47662306a36Sopenharmony_ci resource->debugfs_res_connections = dentry; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci dentry = debugfs_create_file("in_flight_summary", 0440, 47962306a36Sopenharmony_ci resource->debugfs_res, resource, 48062306a36Sopenharmony_ci &in_flight_summary_fops); 48162306a36Sopenharmony_ci resource->debugfs_res_in_flight_summary = dentry; 48262306a36Sopenharmony_ci} 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_cistatic void drbd_debugfs_remove(struct dentry **dp) 48562306a36Sopenharmony_ci{ 48662306a36Sopenharmony_ci debugfs_remove(*dp); 48762306a36Sopenharmony_ci *dp = NULL; 48862306a36Sopenharmony_ci} 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_civoid drbd_debugfs_resource_cleanup(struct drbd_resource *resource) 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci /* it is ok to call debugfs_remove(NULL) */ 49362306a36Sopenharmony_ci drbd_debugfs_remove(&resource->debugfs_res_in_flight_summary); 49462306a36Sopenharmony_ci drbd_debugfs_remove(&resource->debugfs_res_connections); 49562306a36Sopenharmony_ci drbd_debugfs_remove(&resource->debugfs_res_volumes); 49662306a36Sopenharmony_ci drbd_debugfs_remove(&resource->debugfs_res); 49762306a36Sopenharmony_ci} 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_cistatic void seq_print_one_timing_detail(struct seq_file *m, 50062306a36Sopenharmony_ci const struct drbd_thread_timing_details *tdp, 50162306a36Sopenharmony_ci unsigned long now) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci struct drbd_thread_timing_details td; 50462306a36Sopenharmony_ci /* No locking... 50562306a36Sopenharmony_ci * use temporary assignment to get at consistent data. */ 50662306a36Sopenharmony_ci do { 50762306a36Sopenharmony_ci td = *tdp; 50862306a36Sopenharmony_ci } while (td.cb_nr != tdp->cb_nr); 50962306a36Sopenharmony_ci if (!td.cb_addr) 51062306a36Sopenharmony_ci return; 51162306a36Sopenharmony_ci seq_printf(m, "%u\t%d\t%s:%u\t%ps\n", 51262306a36Sopenharmony_ci td.cb_nr, 51362306a36Sopenharmony_ci jiffies_to_msecs(now - td.start_jif), 51462306a36Sopenharmony_ci td.caller_fn, td.line, 51562306a36Sopenharmony_ci td.cb_addr); 51662306a36Sopenharmony_ci} 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_cistatic void seq_print_timing_details(struct seq_file *m, 51962306a36Sopenharmony_ci const char *title, 52062306a36Sopenharmony_ci unsigned int cb_nr, struct drbd_thread_timing_details *tdp, unsigned long now) 52162306a36Sopenharmony_ci{ 52262306a36Sopenharmony_ci unsigned int start_idx; 52362306a36Sopenharmony_ci unsigned int i; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci seq_printf(m, "%s\n", title); 52662306a36Sopenharmony_ci /* If not much is going on, this will result in natural ordering. 52762306a36Sopenharmony_ci * If it is very busy, we will possibly skip events, or even see wrap 52862306a36Sopenharmony_ci * arounds, which could only be avoided with locking. 52962306a36Sopenharmony_ci */ 53062306a36Sopenharmony_ci start_idx = cb_nr % DRBD_THREAD_DETAILS_HIST; 53162306a36Sopenharmony_ci for (i = start_idx; i < DRBD_THREAD_DETAILS_HIST; i++) 53262306a36Sopenharmony_ci seq_print_one_timing_detail(m, tdp+i, now); 53362306a36Sopenharmony_ci for (i = 0; i < start_idx; i++) 53462306a36Sopenharmony_ci seq_print_one_timing_detail(m, tdp+i, now); 53562306a36Sopenharmony_ci} 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_cistatic int callback_history_show(struct seq_file *m, void *ignored) 53862306a36Sopenharmony_ci{ 53962306a36Sopenharmony_ci struct drbd_connection *connection = m->private; 54062306a36Sopenharmony_ci unsigned long jif = jiffies; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci /* BUMP me if you change the file format/content/presentation */ 54362306a36Sopenharmony_ci seq_printf(m, "v: %u\n\n", 0); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci seq_puts(m, "n\tage\tcallsite\tfn\n"); 54662306a36Sopenharmony_ci seq_print_timing_details(m, "worker", connection->w_cb_nr, connection->w_timing_details, jif); 54762306a36Sopenharmony_ci seq_print_timing_details(m, "receiver", connection->r_cb_nr, connection->r_timing_details, jif); 54862306a36Sopenharmony_ci return 0; 54962306a36Sopenharmony_ci} 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_cistatic int callback_history_open(struct inode *inode, struct file *file) 55262306a36Sopenharmony_ci{ 55362306a36Sopenharmony_ci struct drbd_connection *connection = inode->i_private; 55462306a36Sopenharmony_ci return drbd_single_open(file, callback_history_show, connection, 55562306a36Sopenharmony_ci &connection->kref, drbd_destroy_connection); 55662306a36Sopenharmony_ci} 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_cistatic int callback_history_release(struct inode *inode, struct file *file) 55962306a36Sopenharmony_ci{ 56062306a36Sopenharmony_ci struct drbd_connection *connection = inode->i_private; 56162306a36Sopenharmony_ci kref_put(&connection->kref, drbd_destroy_connection); 56262306a36Sopenharmony_ci return single_release(inode, file); 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_cistatic const struct file_operations connection_callback_history_fops = { 56662306a36Sopenharmony_ci .owner = THIS_MODULE, 56762306a36Sopenharmony_ci .open = callback_history_open, 56862306a36Sopenharmony_ci .read = seq_read, 56962306a36Sopenharmony_ci .llseek = seq_lseek, 57062306a36Sopenharmony_ci .release = callback_history_release, 57162306a36Sopenharmony_ci}; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_cistatic int connection_oldest_requests_show(struct seq_file *m, void *ignored) 57462306a36Sopenharmony_ci{ 57562306a36Sopenharmony_ci struct drbd_connection *connection = m->private; 57662306a36Sopenharmony_ci unsigned long now = jiffies; 57762306a36Sopenharmony_ci struct drbd_request *r1, *r2; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci /* BUMP me if you change the file format/content/presentation */ 58062306a36Sopenharmony_ci seq_printf(m, "v: %u\n\n", 0); 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci spin_lock_irq(&connection->resource->req_lock); 58362306a36Sopenharmony_ci r1 = connection->req_next; 58462306a36Sopenharmony_ci if (r1) 58562306a36Sopenharmony_ci seq_print_minor_vnr_req(m, r1, now); 58662306a36Sopenharmony_ci r2 = connection->req_ack_pending; 58762306a36Sopenharmony_ci if (r2 && r2 != r1) { 58862306a36Sopenharmony_ci r1 = r2; 58962306a36Sopenharmony_ci seq_print_minor_vnr_req(m, r1, now); 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci r2 = connection->req_not_net_done; 59262306a36Sopenharmony_ci if (r2 && r2 != r1) 59362306a36Sopenharmony_ci seq_print_minor_vnr_req(m, r2, now); 59462306a36Sopenharmony_ci spin_unlock_irq(&connection->resource->req_lock); 59562306a36Sopenharmony_ci return 0; 59662306a36Sopenharmony_ci} 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_cistatic int connection_oldest_requests_open(struct inode *inode, struct file *file) 59962306a36Sopenharmony_ci{ 60062306a36Sopenharmony_ci struct drbd_connection *connection = inode->i_private; 60162306a36Sopenharmony_ci return drbd_single_open(file, connection_oldest_requests_show, connection, 60262306a36Sopenharmony_ci &connection->kref, drbd_destroy_connection); 60362306a36Sopenharmony_ci} 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_cistatic int connection_oldest_requests_release(struct inode *inode, struct file *file) 60662306a36Sopenharmony_ci{ 60762306a36Sopenharmony_ci struct drbd_connection *connection = inode->i_private; 60862306a36Sopenharmony_ci kref_put(&connection->kref, drbd_destroy_connection); 60962306a36Sopenharmony_ci return single_release(inode, file); 61062306a36Sopenharmony_ci} 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_cistatic const struct file_operations connection_oldest_requests_fops = { 61362306a36Sopenharmony_ci .owner = THIS_MODULE, 61462306a36Sopenharmony_ci .open = connection_oldest_requests_open, 61562306a36Sopenharmony_ci .read = seq_read, 61662306a36Sopenharmony_ci .llseek = seq_lseek, 61762306a36Sopenharmony_ci .release = connection_oldest_requests_release, 61862306a36Sopenharmony_ci}; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_civoid drbd_debugfs_connection_add(struct drbd_connection *connection) 62162306a36Sopenharmony_ci{ 62262306a36Sopenharmony_ci struct dentry *conns_dir = connection->resource->debugfs_res_connections; 62362306a36Sopenharmony_ci struct dentry *dentry; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci /* Once we enable mutliple peers, 62662306a36Sopenharmony_ci * these connections will have descriptive names. 62762306a36Sopenharmony_ci * For now, it is just the one connection to the (only) "peer". */ 62862306a36Sopenharmony_ci dentry = debugfs_create_dir("peer", conns_dir); 62962306a36Sopenharmony_ci connection->debugfs_conn = dentry; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci dentry = debugfs_create_file("callback_history", 0440, 63262306a36Sopenharmony_ci connection->debugfs_conn, connection, 63362306a36Sopenharmony_ci &connection_callback_history_fops); 63462306a36Sopenharmony_ci connection->debugfs_conn_callback_history = dentry; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci dentry = debugfs_create_file("oldest_requests", 0440, 63762306a36Sopenharmony_ci connection->debugfs_conn, connection, 63862306a36Sopenharmony_ci &connection_oldest_requests_fops); 63962306a36Sopenharmony_ci connection->debugfs_conn_oldest_requests = dentry; 64062306a36Sopenharmony_ci} 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_civoid drbd_debugfs_connection_cleanup(struct drbd_connection *connection) 64362306a36Sopenharmony_ci{ 64462306a36Sopenharmony_ci drbd_debugfs_remove(&connection->debugfs_conn_callback_history); 64562306a36Sopenharmony_ci drbd_debugfs_remove(&connection->debugfs_conn_oldest_requests); 64662306a36Sopenharmony_ci drbd_debugfs_remove(&connection->debugfs_conn); 64762306a36Sopenharmony_ci} 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_cistatic void resync_dump_detail(struct seq_file *m, struct lc_element *e) 65062306a36Sopenharmony_ci{ 65162306a36Sopenharmony_ci struct bm_extent *bme = lc_entry(e, struct bm_extent, lce); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci seq_printf(m, "%5d %s %s %s", bme->rs_left, 65462306a36Sopenharmony_ci test_bit(BME_NO_WRITES, &bme->flags) ? "NO_WRITES" : "---------", 65562306a36Sopenharmony_ci test_bit(BME_LOCKED, &bme->flags) ? "LOCKED" : "------", 65662306a36Sopenharmony_ci test_bit(BME_PRIORITY, &bme->flags) ? "PRIORITY" : "--------" 65762306a36Sopenharmony_ci ); 65862306a36Sopenharmony_ci} 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_cistatic int device_resync_extents_show(struct seq_file *m, void *ignored) 66162306a36Sopenharmony_ci{ 66262306a36Sopenharmony_ci struct drbd_device *device = m->private; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci /* BUMP me if you change the file format/content/presentation */ 66562306a36Sopenharmony_ci seq_printf(m, "v: %u\n\n", 0); 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci if (get_ldev_if_state(device, D_FAILED)) { 66862306a36Sopenharmony_ci lc_seq_printf_stats(m, device->resync); 66962306a36Sopenharmony_ci lc_seq_dump_details(m, device->resync, "rs_left flags", resync_dump_detail); 67062306a36Sopenharmony_ci put_ldev(device); 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci return 0; 67362306a36Sopenharmony_ci} 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_cistatic int device_act_log_extents_show(struct seq_file *m, void *ignored) 67662306a36Sopenharmony_ci{ 67762306a36Sopenharmony_ci struct drbd_device *device = m->private; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci /* BUMP me if you change the file format/content/presentation */ 68062306a36Sopenharmony_ci seq_printf(m, "v: %u\n\n", 0); 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci if (get_ldev_if_state(device, D_FAILED)) { 68362306a36Sopenharmony_ci lc_seq_printf_stats(m, device->act_log); 68462306a36Sopenharmony_ci lc_seq_dump_details(m, device->act_log, "", NULL); 68562306a36Sopenharmony_ci put_ldev(device); 68662306a36Sopenharmony_ci } 68762306a36Sopenharmony_ci return 0; 68862306a36Sopenharmony_ci} 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_cistatic int device_oldest_requests_show(struct seq_file *m, void *ignored) 69162306a36Sopenharmony_ci{ 69262306a36Sopenharmony_ci struct drbd_device *device = m->private; 69362306a36Sopenharmony_ci struct drbd_resource *resource = device->resource; 69462306a36Sopenharmony_ci unsigned long now = jiffies; 69562306a36Sopenharmony_ci struct drbd_request *r1, *r2; 69662306a36Sopenharmony_ci int i; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci /* BUMP me if you change the file format/content/presentation */ 69962306a36Sopenharmony_ci seq_printf(m, "v: %u\n\n", 0); 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci seq_puts(m, RQ_HDR); 70262306a36Sopenharmony_ci spin_lock_irq(&resource->req_lock); 70362306a36Sopenharmony_ci /* WRITE, then READ */ 70462306a36Sopenharmony_ci for (i = 1; i >= 0; --i) { 70562306a36Sopenharmony_ci r1 = list_first_entry_or_null(&device->pending_master_completion[i], 70662306a36Sopenharmony_ci struct drbd_request, req_pending_master_completion); 70762306a36Sopenharmony_ci r2 = list_first_entry_or_null(&device->pending_completion[i], 70862306a36Sopenharmony_ci struct drbd_request, req_pending_local); 70962306a36Sopenharmony_ci if (r1) 71062306a36Sopenharmony_ci seq_print_one_request(m, r1, now); 71162306a36Sopenharmony_ci if (r2 && r2 != r1) 71262306a36Sopenharmony_ci seq_print_one_request(m, r2, now); 71362306a36Sopenharmony_ci } 71462306a36Sopenharmony_ci spin_unlock_irq(&resource->req_lock); 71562306a36Sopenharmony_ci return 0; 71662306a36Sopenharmony_ci} 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_cistatic int device_data_gen_id_show(struct seq_file *m, void *ignored) 71962306a36Sopenharmony_ci{ 72062306a36Sopenharmony_ci struct drbd_device *device = m->private; 72162306a36Sopenharmony_ci struct drbd_md *md; 72262306a36Sopenharmony_ci enum drbd_uuid_index idx; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci if (!get_ldev_if_state(device, D_FAILED)) 72562306a36Sopenharmony_ci return -ENODEV; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci md = &device->ldev->md; 72862306a36Sopenharmony_ci spin_lock_irq(&md->uuid_lock); 72962306a36Sopenharmony_ci for (idx = UI_CURRENT; idx <= UI_HISTORY_END; idx++) { 73062306a36Sopenharmony_ci seq_printf(m, "0x%016llX\n", md->uuid[idx]); 73162306a36Sopenharmony_ci } 73262306a36Sopenharmony_ci spin_unlock_irq(&md->uuid_lock); 73362306a36Sopenharmony_ci put_ldev(device); 73462306a36Sopenharmony_ci return 0; 73562306a36Sopenharmony_ci} 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_cistatic int device_ed_gen_id_show(struct seq_file *m, void *ignored) 73862306a36Sopenharmony_ci{ 73962306a36Sopenharmony_ci struct drbd_device *device = m->private; 74062306a36Sopenharmony_ci seq_printf(m, "0x%016llX\n", (unsigned long long)device->ed_uuid); 74162306a36Sopenharmony_ci return 0; 74262306a36Sopenharmony_ci} 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci#define drbd_debugfs_device_attr(name) \ 74562306a36Sopenharmony_cistatic int device_ ## name ## _open(struct inode *inode, struct file *file) \ 74662306a36Sopenharmony_ci{ \ 74762306a36Sopenharmony_ci struct drbd_device *device = inode->i_private; \ 74862306a36Sopenharmony_ci return drbd_single_open(file, device_ ## name ## _show, device, \ 74962306a36Sopenharmony_ci &device->kref, drbd_destroy_device); \ 75062306a36Sopenharmony_ci} \ 75162306a36Sopenharmony_cistatic int device_ ## name ## _release(struct inode *inode, struct file *file) \ 75262306a36Sopenharmony_ci{ \ 75362306a36Sopenharmony_ci struct drbd_device *device = inode->i_private; \ 75462306a36Sopenharmony_ci kref_put(&device->kref, drbd_destroy_device); \ 75562306a36Sopenharmony_ci return single_release(inode, file); \ 75662306a36Sopenharmony_ci} \ 75762306a36Sopenharmony_cistatic const struct file_operations device_ ## name ## _fops = { \ 75862306a36Sopenharmony_ci .owner = THIS_MODULE, \ 75962306a36Sopenharmony_ci .open = device_ ## name ## _open, \ 76062306a36Sopenharmony_ci .read = seq_read, \ 76162306a36Sopenharmony_ci .llseek = seq_lseek, \ 76262306a36Sopenharmony_ci .release = device_ ## name ## _release, \ 76362306a36Sopenharmony_ci}; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_cidrbd_debugfs_device_attr(oldest_requests) 76662306a36Sopenharmony_cidrbd_debugfs_device_attr(act_log_extents) 76762306a36Sopenharmony_cidrbd_debugfs_device_attr(resync_extents) 76862306a36Sopenharmony_cidrbd_debugfs_device_attr(data_gen_id) 76962306a36Sopenharmony_cidrbd_debugfs_device_attr(ed_gen_id) 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_civoid drbd_debugfs_device_add(struct drbd_device *device) 77262306a36Sopenharmony_ci{ 77362306a36Sopenharmony_ci struct dentry *vols_dir = device->resource->debugfs_res_volumes; 77462306a36Sopenharmony_ci char minor_buf[8]; /* MINORMASK, MINORBITS == 20; */ 77562306a36Sopenharmony_ci char vnr_buf[8]; /* volume number vnr is even 16 bit only; */ 77662306a36Sopenharmony_ci char *slink_name = NULL; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci struct dentry *dentry; 77962306a36Sopenharmony_ci if (!vols_dir || !drbd_debugfs_minors) 78062306a36Sopenharmony_ci return; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci snprintf(vnr_buf, sizeof(vnr_buf), "%u", device->vnr); 78362306a36Sopenharmony_ci dentry = debugfs_create_dir(vnr_buf, vols_dir); 78462306a36Sopenharmony_ci device->debugfs_vol = dentry; 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci snprintf(minor_buf, sizeof(minor_buf), "%u", device->minor); 78762306a36Sopenharmony_ci slink_name = kasprintf(GFP_KERNEL, "../resources/%s/volumes/%u", 78862306a36Sopenharmony_ci device->resource->name, device->vnr); 78962306a36Sopenharmony_ci if (!slink_name) 79062306a36Sopenharmony_ci goto fail; 79162306a36Sopenharmony_ci dentry = debugfs_create_symlink(minor_buf, drbd_debugfs_minors, slink_name); 79262306a36Sopenharmony_ci device->debugfs_minor = dentry; 79362306a36Sopenharmony_ci kfree(slink_name); 79462306a36Sopenharmony_ci slink_name = NULL; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci#define DCF(name) do { \ 79762306a36Sopenharmony_ci dentry = debugfs_create_file(#name, 0440, \ 79862306a36Sopenharmony_ci device->debugfs_vol, device, \ 79962306a36Sopenharmony_ci &device_ ## name ## _fops); \ 80062306a36Sopenharmony_ci device->debugfs_vol_ ## name = dentry; \ 80162306a36Sopenharmony_ci } while (0) 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci DCF(oldest_requests); 80462306a36Sopenharmony_ci DCF(act_log_extents); 80562306a36Sopenharmony_ci DCF(resync_extents); 80662306a36Sopenharmony_ci DCF(data_gen_id); 80762306a36Sopenharmony_ci DCF(ed_gen_id); 80862306a36Sopenharmony_ci#undef DCF 80962306a36Sopenharmony_ci return; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_cifail: 81262306a36Sopenharmony_ci drbd_debugfs_device_cleanup(device); 81362306a36Sopenharmony_ci drbd_err(device, "failed to create debugfs entries\n"); 81462306a36Sopenharmony_ci} 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_civoid drbd_debugfs_device_cleanup(struct drbd_device *device) 81762306a36Sopenharmony_ci{ 81862306a36Sopenharmony_ci drbd_debugfs_remove(&device->debugfs_minor); 81962306a36Sopenharmony_ci drbd_debugfs_remove(&device->debugfs_vol_oldest_requests); 82062306a36Sopenharmony_ci drbd_debugfs_remove(&device->debugfs_vol_act_log_extents); 82162306a36Sopenharmony_ci drbd_debugfs_remove(&device->debugfs_vol_resync_extents); 82262306a36Sopenharmony_ci drbd_debugfs_remove(&device->debugfs_vol_data_gen_id); 82362306a36Sopenharmony_ci drbd_debugfs_remove(&device->debugfs_vol_ed_gen_id); 82462306a36Sopenharmony_ci drbd_debugfs_remove(&device->debugfs_vol); 82562306a36Sopenharmony_ci} 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_civoid drbd_debugfs_peer_device_add(struct drbd_peer_device *peer_device) 82862306a36Sopenharmony_ci{ 82962306a36Sopenharmony_ci struct dentry *conn_dir = peer_device->connection->debugfs_conn; 83062306a36Sopenharmony_ci struct dentry *dentry; 83162306a36Sopenharmony_ci char vnr_buf[8]; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci snprintf(vnr_buf, sizeof(vnr_buf), "%u", peer_device->device->vnr); 83462306a36Sopenharmony_ci dentry = debugfs_create_dir(vnr_buf, conn_dir); 83562306a36Sopenharmony_ci peer_device->debugfs_peer_dev = dentry; 83662306a36Sopenharmony_ci} 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_civoid drbd_debugfs_peer_device_cleanup(struct drbd_peer_device *peer_device) 83962306a36Sopenharmony_ci{ 84062306a36Sopenharmony_ci drbd_debugfs_remove(&peer_device->debugfs_peer_dev); 84162306a36Sopenharmony_ci} 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_cistatic int drbd_version_show(struct seq_file *m, void *ignored) 84462306a36Sopenharmony_ci{ 84562306a36Sopenharmony_ci seq_printf(m, "# %s\n", drbd_buildtag()); 84662306a36Sopenharmony_ci seq_printf(m, "VERSION=%s\n", REL_VERSION); 84762306a36Sopenharmony_ci seq_printf(m, "API_VERSION=%u\n", GENL_MAGIC_VERSION); 84862306a36Sopenharmony_ci seq_printf(m, "PRO_VERSION_MIN=%u\n", PRO_VERSION_MIN); 84962306a36Sopenharmony_ci seq_printf(m, "PRO_VERSION_MAX=%u\n", PRO_VERSION_MAX); 85062306a36Sopenharmony_ci return 0; 85162306a36Sopenharmony_ci} 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_cistatic int drbd_version_open(struct inode *inode, struct file *file) 85462306a36Sopenharmony_ci{ 85562306a36Sopenharmony_ci return single_open(file, drbd_version_show, NULL); 85662306a36Sopenharmony_ci} 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_cistatic const struct file_operations drbd_version_fops = { 85962306a36Sopenharmony_ci .owner = THIS_MODULE, 86062306a36Sopenharmony_ci .open = drbd_version_open, 86162306a36Sopenharmony_ci .llseek = seq_lseek, 86262306a36Sopenharmony_ci .read = seq_read, 86362306a36Sopenharmony_ci .release = single_release, 86462306a36Sopenharmony_ci}; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci/* not __exit, may be indirectly called 86762306a36Sopenharmony_ci * from the module-load-failure path as well. */ 86862306a36Sopenharmony_civoid drbd_debugfs_cleanup(void) 86962306a36Sopenharmony_ci{ 87062306a36Sopenharmony_ci drbd_debugfs_remove(&drbd_debugfs_resources); 87162306a36Sopenharmony_ci drbd_debugfs_remove(&drbd_debugfs_minors); 87262306a36Sopenharmony_ci drbd_debugfs_remove(&drbd_debugfs_version); 87362306a36Sopenharmony_ci drbd_debugfs_remove(&drbd_debugfs_root); 87462306a36Sopenharmony_ci} 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_civoid __init drbd_debugfs_init(void) 87762306a36Sopenharmony_ci{ 87862306a36Sopenharmony_ci struct dentry *dentry; 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci dentry = debugfs_create_dir("drbd", NULL); 88162306a36Sopenharmony_ci drbd_debugfs_root = dentry; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci dentry = debugfs_create_file("version", 0444, drbd_debugfs_root, NULL, &drbd_version_fops); 88462306a36Sopenharmony_ci drbd_debugfs_version = dentry; 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci dentry = debugfs_create_dir("resources", drbd_debugfs_root); 88762306a36Sopenharmony_ci drbd_debugfs_resources = dentry; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci dentry = debugfs_create_dir("minors", drbd_debugfs_root); 89062306a36Sopenharmony_ci drbd_debugfs_minors = dentry; 89162306a36Sopenharmony_ci} 892