162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * netdebug.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * debug functionality for o2net 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (C) 2005, 2008 Oracle. All rights reserved. 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/types.h> 1462306a36Sopenharmony_ci#include <linux/slab.h> 1562306a36Sopenharmony_ci#include <linux/idr.h> 1662306a36Sopenharmony_ci#include <linux/kref.h> 1762306a36Sopenharmony_ci#include <linux/seq_file.h> 1862306a36Sopenharmony_ci#include <linux/debugfs.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include <linux/uaccess.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include "tcp.h" 2362306a36Sopenharmony_ci#include "nodemanager.h" 2462306a36Sopenharmony_ci#define MLOG_MASK_PREFIX ML_TCP 2562306a36Sopenharmony_ci#include "masklog.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include "tcp_internal.h" 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define O2NET_DEBUG_DIR "o2net" 3062306a36Sopenharmony_ci#define SC_DEBUG_NAME "sock_containers" 3162306a36Sopenharmony_ci#define NST_DEBUG_NAME "send_tracking" 3262306a36Sopenharmony_ci#define STATS_DEBUG_NAME "stats" 3362306a36Sopenharmony_ci#define NODES_DEBUG_NAME "connected_nodes" 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#define SHOW_SOCK_CONTAINERS 0 3662306a36Sopenharmony_ci#define SHOW_SOCK_STATS 1 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic struct dentry *o2net_dentry; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic DEFINE_SPINLOCK(o2net_debug_lock); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistatic LIST_HEAD(sock_containers); 4362306a36Sopenharmony_cistatic LIST_HEAD(send_tracking); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_civoid o2net_debug_add_nst(struct o2net_send_tracking *nst) 4662306a36Sopenharmony_ci{ 4762306a36Sopenharmony_ci spin_lock_bh(&o2net_debug_lock); 4862306a36Sopenharmony_ci list_add(&nst->st_net_debug_item, &send_tracking); 4962306a36Sopenharmony_ci spin_unlock_bh(&o2net_debug_lock); 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_civoid o2net_debug_del_nst(struct o2net_send_tracking *nst) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci spin_lock_bh(&o2net_debug_lock); 5562306a36Sopenharmony_ci if (!list_empty(&nst->st_net_debug_item)) 5662306a36Sopenharmony_ci list_del_init(&nst->st_net_debug_item); 5762306a36Sopenharmony_ci spin_unlock_bh(&o2net_debug_lock); 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic struct o2net_send_tracking 6162306a36Sopenharmony_ci *next_nst(struct o2net_send_tracking *nst_start) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci struct o2net_send_tracking *nst, *ret = NULL; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci assert_spin_locked(&o2net_debug_lock); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci list_for_each_entry(nst, &nst_start->st_net_debug_item, 6862306a36Sopenharmony_ci st_net_debug_item) { 6962306a36Sopenharmony_ci /* discover the head of the list */ 7062306a36Sopenharmony_ci if (&nst->st_net_debug_item == &send_tracking) 7162306a36Sopenharmony_ci break; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci /* use st_task to detect real nsts in the list */ 7462306a36Sopenharmony_ci if (nst->st_task != NULL) { 7562306a36Sopenharmony_ci ret = nst; 7662306a36Sopenharmony_ci break; 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci } 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci return ret; 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic void *nst_seq_start(struct seq_file *seq, loff_t *pos) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci struct o2net_send_tracking *nst, *dummy_nst = seq->private; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci spin_lock_bh(&o2net_debug_lock); 8862306a36Sopenharmony_ci nst = next_nst(dummy_nst); 8962306a36Sopenharmony_ci spin_unlock_bh(&o2net_debug_lock); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci return nst; 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic void *nst_seq_next(struct seq_file *seq, void *v, loff_t *pos) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci struct o2net_send_tracking *nst, *dummy_nst = seq->private; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci spin_lock_bh(&o2net_debug_lock); 9962306a36Sopenharmony_ci nst = next_nst(dummy_nst); 10062306a36Sopenharmony_ci list_del_init(&dummy_nst->st_net_debug_item); 10162306a36Sopenharmony_ci if (nst) 10262306a36Sopenharmony_ci list_add(&dummy_nst->st_net_debug_item, 10362306a36Sopenharmony_ci &nst->st_net_debug_item); 10462306a36Sopenharmony_ci spin_unlock_bh(&o2net_debug_lock); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci return nst; /* unused, just needs to be null when done */ 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic int nst_seq_show(struct seq_file *seq, void *v) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci struct o2net_send_tracking *nst, *dummy_nst = seq->private; 11262306a36Sopenharmony_ci ktime_t now; 11362306a36Sopenharmony_ci s64 sock, send, status; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci spin_lock_bh(&o2net_debug_lock); 11662306a36Sopenharmony_ci nst = next_nst(dummy_nst); 11762306a36Sopenharmony_ci if (!nst) 11862306a36Sopenharmony_ci goto out; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci now = ktime_get(); 12162306a36Sopenharmony_ci sock = ktime_to_us(ktime_sub(now, nst->st_sock_time)); 12262306a36Sopenharmony_ci send = ktime_to_us(ktime_sub(now, nst->st_send_time)); 12362306a36Sopenharmony_ci status = ktime_to_us(ktime_sub(now, nst->st_status_time)); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci /* get_task_comm isn't exported. oh well. */ 12662306a36Sopenharmony_ci seq_printf(seq, "%p:\n" 12762306a36Sopenharmony_ci " pid: %lu\n" 12862306a36Sopenharmony_ci " tgid: %lu\n" 12962306a36Sopenharmony_ci " process name: %s\n" 13062306a36Sopenharmony_ci " node: %u\n" 13162306a36Sopenharmony_ci " sc: %p\n" 13262306a36Sopenharmony_ci " message id: %d\n" 13362306a36Sopenharmony_ci " message type: %u\n" 13462306a36Sopenharmony_ci " message key: 0x%08x\n" 13562306a36Sopenharmony_ci " sock acquiry: %lld usecs ago\n" 13662306a36Sopenharmony_ci " send start: %lld usecs ago\n" 13762306a36Sopenharmony_ci " wait start: %lld usecs ago\n", 13862306a36Sopenharmony_ci nst, (unsigned long)task_pid_nr(nst->st_task), 13962306a36Sopenharmony_ci (unsigned long)nst->st_task->tgid, 14062306a36Sopenharmony_ci nst->st_task->comm, nst->st_node, 14162306a36Sopenharmony_ci nst->st_sc, nst->st_id, nst->st_msg_type, 14262306a36Sopenharmony_ci nst->st_msg_key, 14362306a36Sopenharmony_ci (long long)sock, 14462306a36Sopenharmony_ci (long long)send, 14562306a36Sopenharmony_ci (long long)status); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ciout: 14862306a36Sopenharmony_ci spin_unlock_bh(&o2net_debug_lock); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci return 0; 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistatic void nst_seq_stop(struct seq_file *seq, void *v) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic const struct seq_operations nst_seq_ops = { 15862306a36Sopenharmony_ci .start = nst_seq_start, 15962306a36Sopenharmony_ci .next = nst_seq_next, 16062306a36Sopenharmony_ci .stop = nst_seq_stop, 16162306a36Sopenharmony_ci .show = nst_seq_show, 16262306a36Sopenharmony_ci}; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic int nst_fop_open(struct inode *inode, struct file *file) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci struct o2net_send_tracking *dummy_nst; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci dummy_nst = __seq_open_private(file, &nst_seq_ops, sizeof(*dummy_nst)); 16962306a36Sopenharmony_ci if (!dummy_nst) 17062306a36Sopenharmony_ci return -ENOMEM; 17162306a36Sopenharmony_ci o2net_debug_add_nst(dummy_nst); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci return 0; 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistatic int nst_fop_release(struct inode *inode, struct file *file) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci struct seq_file *seq = file->private_data; 17962306a36Sopenharmony_ci struct o2net_send_tracking *dummy_nst = seq->private; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci o2net_debug_del_nst(dummy_nst); 18262306a36Sopenharmony_ci return seq_release_private(inode, file); 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic const struct file_operations nst_seq_fops = { 18662306a36Sopenharmony_ci .open = nst_fop_open, 18762306a36Sopenharmony_ci .read = seq_read, 18862306a36Sopenharmony_ci .llseek = seq_lseek, 18962306a36Sopenharmony_ci .release = nst_fop_release, 19062306a36Sopenharmony_ci}; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_civoid o2net_debug_add_sc(struct o2net_sock_container *sc) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci spin_lock_bh(&o2net_debug_lock); 19562306a36Sopenharmony_ci list_add(&sc->sc_net_debug_item, &sock_containers); 19662306a36Sopenharmony_ci spin_unlock_bh(&o2net_debug_lock); 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_civoid o2net_debug_del_sc(struct o2net_sock_container *sc) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci spin_lock_bh(&o2net_debug_lock); 20262306a36Sopenharmony_ci list_del_init(&sc->sc_net_debug_item); 20362306a36Sopenharmony_ci spin_unlock_bh(&o2net_debug_lock); 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistruct o2net_sock_debug { 20762306a36Sopenharmony_ci int dbg_ctxt; 20862306a36Sopenharmony_ci struct o2net_sock_container *dbg_sock; 20962306a36Sopenharmony_ci}; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic struct o2net_sock_container 21262306a36Sopenharmony_ci *next_sc(struct o2net_sock_container *sc_start) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci struct o2net_sock_container *sc, *ret = NULL; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci assert_spin_locked(&o2net_debug_lock); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci list_for_each_entry(sc, &sc_start->sc_net_debug_item, 21962306a36Sopenharmony_ci sc_net_debug_item) { 22062306a36Sopenharmony_ci /* discover the head of the list miscast as a sc */ 22162306a36Sopenharmony_ci if (&sc->sc_net_debug_item == &sock_containers) 22262306a36Sopenharmony_ci break; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci /* use sc_page to detect real scs in the list */ 22562306a36Sopenharmony_ci if (sc->sc_page != NULL) { 22662306a36Sopenharmony_ci ret = sc; 22762306a36Sopenharmony_ci break; 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci return ret; 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_cistatic void *sc_seq_start(struct seq_file *seq, loff_t *pos) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci struct o2net_sock_debug *sd = seq->private; 23762306a36Sopenharmony_ci struct o2net_sock_container *sc, *dummy_sc = sd->dbg_sock; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci spin_lock_bh(&o2net_debug_lock); 24062306a36Sopenharmony_ci sc = next_sc(dummy_sc); 24162306a36Sopenharmony_ci spin_unlock_bh(&o2net_debug_lock); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci return sc; 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistatic void *sc_seq_next(struct seq_file *seq, void *v, loff_t *pos) 24762306a36Sopenharmony_ci{ 24862306a36Sopenharmony_ci struct o2net_sock_debug *sd = seq->private; 24962306a36Sopenharmony_ci struct o2net_sock_container *sc, *dummy_sc = sd->dbg_sock; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci spin_lock_bh(&o2net_debug_lock); 25262306a36Sopenharmony_ci sc = next_sc(dummy_sc); 25362306a36Sopenharmony_ci list_del_init(&dummy_sc->sc_net_debug_item); 25462306a36Sopenharmony_ci if (sc) 25562306a36Sopenharmony_ci list_add(&dummy_sc->sc_net_debug_item, &sc->sc_net_debug_item); 25662306a36Sopenharmony_ci spin_unlock_bh(&o2net_debug_lock); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci return sc; /* unused, just needs to be null when done */ 25962306a36Sopenharmony_ci} 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci#ifdef CONFIG_OCFS2_FS_STATS 26262306a36Sopenharmony_ci# define sc_send_count(_s) ((_s)->sc_send_count) 26362306a36Sopenharmony_ci# define sc_recv_count(_s) ((_s)->sc_recv_count) 26462306a36Sopenharmony_ci# define sc_tv_acquiry_total_ns(_s) (ktime_to_ns((_s)->sc_tv_acquiry_total)) 26562306a36Sopenharmony_ci# define sc_tv_send_total_ns(_s) (ktime_to_ns((_s)->sc_tv_send_total)) 26662306a36Sopenharmony_ci# define sc_tv_status_total_ns(_s) (ktime_to_ns((_s)->sc_tv_status_total)) 26762306a36Sopenharmony_ci# define sc_tv_process_total_ns(_s) (ktime_to_ns((_s)->sc_tv_process_total)) 26862306a36Sopenharmony_ci#else 26962306a36Sopenharmony_ci# define sc_send_count(_s) (0U) 27062306a36Sopenharmony_ci# define sc_recv_count(_s) (0U) 27162306a36Sopenharmony_ci# define sc_tv_acquiry_total_ns(_s) (0LL) 27262306a36Sopenharmony_ci# define sc_tv_send_total_ns(_s) (0LL) 27362306a36Sopenharmony_ci# define sc_tv_status_total_ns(_s) (0LL) 27462306a36Sopenharmony_ci# define sc_tv_process_total_ns(_s) (0LL) 27562306a36Sopenharmony_ci#endif 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci/* So that debugfs.ocfs2 can determine which format is being used */ 27862306a36Sopenharmony_ci#define O2NET_STATS_STR_VERSION 1 27962306a36Sopenharmony_cistatic void sc_show_sock_stats(struct seq_file *seq, 28062306a36Sopenharmony_ci struct o2net_sock_container *sc) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci if (!sc) 28362306a36Sopenharmony_ci return; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci seq_printf(seq, "%d,%u,%lu,%lld,%lld,%lld,%lu,%lld\n", O2NET_STATS_STR_VERSION, 28662306a36Sopenharmony_ci sc->sc_node->nd_num, (unsigned long)sc_send_count(sc), 28762306a36Sopenharmony_ci (long long)sc_tv_acquiry_total_ns(sc), 28862306a36Sopenharmony_ci (long long)sc_tv_send_total_ns(sc), 28962306a36Sopenharmony_ci (long long)sc_tv_status_total_ns(sc), 29062306a36Sopenharmony_ci (unsigned long)sc_recv_count(sc), 29162306a36Sopenharmony_ci (long long)sc_tv_process_total_ns(sc)); 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cistatic void sc_show_sock_container(struct seq_file *seq, 29562306a36Sopenharmony_ci struct o2net_sock_container *sc) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci struct inet_sock *inet = NULL; 29862306a36Sopenharmony_ci __be32 saddr = 0, daddr = 0; 29962306a36Sopenharmony_ci __be16 sport = 0, dport = 0; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci if (!sc) 30262306a36Sopenharmony_ci return; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci if (sc->sc_sock) { 30562306a36Sopenharmony_ci inet = inet_sk(sc->sc_sock->sk); 30662306a36Sopenharmony_ci /* the stack's structs aren't sparse endian clean */ 30762306a36Sopenharmony_ci saddr = (__force __be32)inet->inet_saddr; 30862306a36Sopenharmony_ci daddr = (__force __be32)inet->inet_daddr; 30962306a36Sopenharmony_ci sport = (__force __be16)inet->inet_sport; 31062306a36Sopenharmony_ci dport = (__force __be16)inet->inet_dport; 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci /* XXX sigh, inet-> doesn't have sparse annotation so any 31462306a36Sopenharmony_ci * use of it here generates a warning with -Wbitwise */ 31562306a36Sopenharmony_ci seq_printf(seq, "%p:\n" 31662306a36Sopenharmony_ci " krefs: %d\n" 31762306a36Sopenharmony_ci " sock: %pI4:%u -> " 31862306a36Sopenharmony_ci "%pI4:%u\n" 31962306a36Sopenharmony_ci " remote node: %s\n" 32062306a36Sopenharmony_ci " page off: %zu\n" 32162306a36Sopenharmony_ci " handshake ok: %u\n" 32262306a36Sopenharmony_ci " timer: %lld usecs\n" 32362306a36Sopenharmony_ci " data ready: %lld usecs\n" 32462306a36Sopenharmony_ci " advance start: %lld usecs\n" 32562306a36Sopenharmony_ci " advance stop: %lld usecs\n" 32662306a36Sopenharmony_ci " func start: %lld usecs\n" 32762306a36Sopenharmony_ci " func stop: %lld usecs\n" 32862306a36Sopenharmony_ci " func key: 0x%08x\n" 32962306a36Sopenharmony_ci " func type: %u\n", 33062306a36Sopenharmony_ci sc, 33162306a36Sopenharmony_ci kref_read(&sc->sc_kref), 33262306a36Sopenharmony_ci &saddr, inet ? ntohs(sport) : 0, 33362306a36Sopenharmony_ci &daddr, inet ? ntohs(dport) : 0, 33462306a36Sopenharmony_ci sc->sc_node->nd_name, 33562306a36Sopenharmony_ci sc->sc_page_off, 33662306a36Sopenharmony_ci sc->sc_handshake_ok, 33762306a36Sopenharmony_ci (long long)ktime_to_us(sc->sc_tv_timer), 33862306a36Sopenharmony_ci (long long)ktime_to_us(sc->sc_tv_data_ready), 33962306a36Sopenharmony_ci (long long)ktime_to_us(sc->sc_tv_advance_start), 34062306a36Sopenharmony_ci (long long)ktime_to_us(sc->sc_tv_advance_stop), 34162306a36Sopenharmony_ci (long long)ktime_to_us(sc->sc_tv_func_start), 34262306a36Sopenharmony_ci (long long)ktime_to_us(sc->sc_tv_func_stop), 34362306a36Sopenharmony_ci sc->sc_msg_key, 34462306a36Sopenharmony_ci sc->sc_msg_type); 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic int sc_seq_show(struct seq_file *seq, void *v) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci struct o2net_sock_debug *sd = seq->private; 35062306a36Sopenharmony_ci struct o2net_sock_container *sc, *dummy_sc = sd->dbg_sock; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci spin_lock_bh(&o2net_debug_lock); 35362306a36Sopenharmony_ci sc = next_sc(dummy_sc); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci if (sc) { 35662306a36Sopenharmony_ci if (sd->dbg_ctxt == SHOW_SOCK_CONTAINERS) 35762306a36Sopenharmony_ci sc_show_sock_container(seq, sc); 35862306a36Sopenharmony_ci else 35962306a36Sopenharmony_ci sc_show_sock_stats(seq, sc); 36062306a36Sopenharmony_ci } 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci spin_unlock_bh(&o2net_debug_lock); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci return 0; 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_cistatic void sc_seq_stop(struct seq_file *seq, void *v) 36862306a36Sopenharmony_ci{ 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_cistatic const struct seq_operations sc_seq_ops = { 37262306a36Sopenharmony_ci .start = sc_seq_start, 37362306a36Sopenharmony_ci .next = sc_seq_next, 37462306a36Sopenharmony_ci .stop = sc_seq_stop, 37562306a36Sopenharmony_ci .show = sc_seq_show, 37662306a36Sopenharmony_ci}; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_cistatic int sc_common_open(struct file *file, int ctxt) 37962306a36Sopenharmony_ci{ 38062306a36Sopenharmony_ci struct o2net_sock_debug *sd; 38162306a36Sopenharmony_ci struct o2net_sock_container *dummy_sc; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci dummy_sc = kzalloc(sizeof(*dummy_sc), GFP_KERNEL); 38462306a36Sopenharmony_ci if (!dummy_sc) 38562306a36Sopenharmony_ci return -ENOMEM; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci sd = __seq_open_private(file, &sc_seq_ops, sizeof(*sd)); 38862306a36Sopenharmony_ci if (!sd) { 38962306a36Sopenharmony_ci kfree(dummy_sc); 39062306a36Sopenharmony_ci return -ENOMEM; 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci sd->dbg_ctxt = ctxt; 39462306a36Sopenharmony_ci sd->dbg_sock = dummy_sc; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci o2net_debug_add_sc(dummy_sc); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci return 0; 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_cistatic int sc_fop_release(struct inode *inode, struct file *file) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci struct seq_file *seq = file->private_data; 40462306a36Sopenharmony_ci struct o2net_sock_debug *sd = seq->private; 40562306a36Sopenharmony_ci struct o2net_sock_container *dummy_sc = sd->dbg_sock; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci o2net_debug_del_sc(dummy_sc); 40862306a36Sopenharmony_ci kfree(dummy_sc); 40962306a36Sopenharmony_ci return seq_release_private(inode, file); 41062306a36Sopenharmony_ci} 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_cistatic int stats_fop_open(struct inode *inode, struct file *file) 41362306a36Sopenharmony_ci{ 41462306a36Sopenharmony_ci return sc_common_open(file, SHOW_SOCK_STATS); 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_cistatic const struct file_operations stats_seq_fops = { 41862306a36Sopenharmony_ci .open = stats_fop_open, 41962306a36Sopenharmony_ci .read = seq_read, 42062306a36Sopenharmony_ci .llseek = seq_lseek, 42162306a36Sopenharmony_ci .release = sc_fop_release, 42262306a36Sopenharmony_ci}; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_cistatic int sc_fop_open(struct inode *inode, struct file *file) 42562306a36Sopenharmony_ci{ 42662306a36Sopenharmony_ci return sc_common_open(file, SHOW_SOCK_CONTAINERS); 42762306a36Sopenharmony_ci} 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_cistatic const struct file_operations sc_seq_fops = { 43062306a36Sopenharmony_ci .open = sc_fop_open, 43162306a36Sopenharmony_ci .read = seq_read, 43262306a36Sopenharmony_ci .llseek = seq_lseek, 43362306a36Sopenharmony_ci .release = sc_fop_release, 43462306a36Sopenharmony_ci}; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_cistatic int o2net_fill_bitmap(char *buf, int len) 43762306a36Sopenharmony_ci{ 43862306a36Sopenharmony_ci unsigned long map[BITS_TO_LONGS(O2NM_MAX_NODES)]; 43962306a36Sopenharmony_ci int i = -1, out = 0; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci o2net_fill_node_map(map, O2NM_MAX_NODES); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci while ((i = find_next_bit(map, O2NM_MAX_NODES, i + 1)) < O2NM_MAX_NODES) 44462306a36Sopenharmony_ci out += scnprintf(buf + out, PAGE_SIZE - out, "%d ", i); 44562306a36Sopenharmony_ci out += scnprintf(buf + out, PAGE_SIZE - out, "\n"); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci return out; 44862306a36Sopenharmony_ci} 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_cistatic int nodes_fop_open(struct inode *inode, struct file *file) 45162306a36Sopenharmony_ci{ 45262306a36Sopenharmony_ci char *buf; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci buf = kmalloc(PAGE_SIZE, GFP_KERNEL); 45562306a36Sopenharmony_ci if (!buf) 45662306a36Sopenharmony_ci return -ENOMEM; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci i_size_write(inode, o2net_fill_bitmap(buf, PAGE_SIZE)); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci file->private_data = buf; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci return 0; 46362306a36Sopenharmony_ci} 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_cistatic int o2net_debug_release(struct inode *inode, struct file *file) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci kfree(file->private_data); 46862306a36Sopenharmony_ci return 0; 46962306a36Sopenharmony_ci} 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_cistatic ssize_t o2net_debug_read(struct file *file, char __user *buf, 47262306a36Sopenharmony_ci size_t nbytes, loff_t *ppos) 47362306a36Sopenharmony_ci{ 47462306a36Sopenharmony_ci return simple_read_from_buffer(buf, nbytes, ppos, file->private_data, 47562306a36Sopenharmony_ci i_size_read(file->f_mapping->host)); 47662306a36Sopenharmony_ci} 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_cistatic const struct file_operations nodes_fops = { 47962306a36Sopenharmony_ci .open = nodes_fop_open, 48062306a36Sopenharmony_ci .release = o2net_debug_release, 48162306a36Sopenharmony_ci .read = o2net_debug_read, 48262306a36Sopenharmony_ci .llseek = generic_file_llseek, 48362306a36Sopenharmony_ci}; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_civoid o2net_debugfs_exit(void) 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci debugfs_remove_recursive(o2net_dentry); 48862306a36Sopenharmony_ci} 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_civoid o2net_debugfs_init(void) 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci umode_t mode = S_IFREG|S_IRUSR; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci o2net_dentry = debugfs_create_dir(O2NET_DEBUG_DIR, NULL); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci debugfs_create_file(NST_DEBUG_NAME, mode, o2net_dentry, NULL, 49762306a36Sopenharmony_ci &nst_seq_fops); 49862306a36Sopenharmony_ci debugfs_create_file(SC_DEBUG_NAME, mode, o2net_dentry, NULL, 49962306a36Sopenharmony_ci &sc_seq_fops); 50062306a36Sopenharmony_ci debugfs_create_file(STATS_DEBUG_NAME, mode, o2net_dentry, NULL, 50162306a36Sopenharmony_ci &stats_seq_fops); 50262306a36Sopenharmony_ci debugfs_create_file(NODES_DEBUG_NAME, mode, o2net_dentry, NULL, 50362306a36Sopenharmony_ci &nodes_fops); 50462306a36Sopenharmony_ci} 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci#endif /* CONFIG_DEBUG_FS */ 507