cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

netdebug.c (12664B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * netdebug.c
      4 *
      5 * debug functionality for o2net
      6 *
      7 * Copyright (C) 2005, 2008 Oracle.  All rights reserved.
      8 */
      9
     10#ifdef CONFIG_DEBUG_FS
     11
     12#include <linux/module.h>
     13#include <linux/types.h>
     14#include <linux/slab.h>
     15#include <linux/idr.h>
     16#include <linux/kref.h>
     17#include <linux/seq_file.h>
     18#include <linux/debugfs.h>
     19
     20#include <linux/uaccess.h>
     21
     22#include "tcp.h"
     23#include "nodemanager.h"
     24#define MLOG_MASK_PREFIX ML_TCP
     25#include "masklog.h"
     26
     27#include "tcp_internal.h"
     28
     29#define O2NET_DEBUG_DIR		"o2net"
     30#define SC_DEBUG_NAME		"sock_containers"
     31#define NST_DEBUG_NAME		"send_tracking"
     32#define STATS_DEBUG_NAME	"stats"
     33#define NODES_DEBUG_NAME	"connected_nodes"
     34
     35#define SHOW_SOCK_CONTAINERS	0
     36#define SHOW_SOCK_STATS		1
     37
     38static struct dentry *o2net_dentry;
     39
     40static DEFINE_SPINLOCK(o2net_debug_lock);
     41
     42static LIST_HEAD(sock_containers);
     43static LIST_HEAD(send_tracking);
     44
     45void o2net_debug_add_nst(struct o2net_send_tracking *nst)
     46{
     47	spin_lock(&o2net_debug_lock);
     48	list_add(&nst->st_net_debug_item, &send_tracking);
     49	spin_unlock(&o2net_debug_lock);
     50}
     51
     52void o2net_debug_del_nst(struct o2net_send_tracking *nst)
     53{
     54	spin_lock(&o2net_debug_lock);
     55	if (!list_empty(&nst->st_net_debug_item))
     56		list_del_init(&nst->st_net_debug_item);
     57	spin_unlock(&o2net_debug_lock);
     58}
     59
     60static struct o2net_send_tracking
     61			*next_nst(struct o2net_send_tracking *nst_start)
     62{
     63	struct o2net_send_tracking *nst, *ret = NULL;
     64
     65	assert_spin_locked(&o2net_debug_lock);
     66
     67	list_for_each_entry(nst, &nst_start->st_net_debug_item,
     68			    st_net_debug_item) {
     69		/* discover the head of the list */
     70		if (&nst->st_net_debug_item == &send_tracking)
     71			break;
     72
     73		/* use st_task to detect real nsts in the list */
     74		if (nst->st_task != NULL) {
     75			ret = nst;
     76			break;
     77		}
     78	}
     79
     80	return ret;
     81}
     82
     83static void *nst_seq_start(struct seq_file *seq, loff_t *pos)
     84{
     85	struct o2net_send_tracking *nst, *dummy_nst = seq->private;
     86
     87	spin_lock(&o2net_debug_lock);
     88	nst = next_nst(dummy_nst);
     89	spin_unlock(&o2net_debug_lock);
     90
     91	return nst;
     92}
     93
     94static void *nst_seq_next(struct seq_file *seq, void *v, loff_t *pos)
     95{
     96	struct o2net_send_tracking *nst, *dummy_nst = seq->private;
     97
     98	spin_lock(&o2net_debug_lock);
     99	nst = next_nst(dummy_nst);
    100	list_del_init(&dummy_nst->st_net_debug_item);
    101	if (nst)
    102		list_add(&dummy_nst->st_net_debug_item,
    103			 &nst->st_net_debug_item);
    104	spin_unlock(&o2net_debug_lock);
    105
    106	return nst; /* unused, just needs to be null when done */
    107}
    108
    109static int nst_seq_show(struct seq_file *seq, void *v)
    110{
    111	struct o2net_send_tracking *nst, *dummy_nst = seq->private;
    112	ktime_t now;
    113	s64 sock, send, status;
    114
    115	spin_lock(&o2net_debug_lock);
    116	nst = next_nst(dummy_nst);
    117	if (!nst)
    118		goto out;
    119
    120	now = ktime_get();
    121	sock = ktime_to_us(ktime_sub(now, nst->st_sock_time));
    122	send = ktime_to_us(ktime_sub(now, nst->st_send_time));
    123	status = ktime_to_us(ktime_sub(now, nst->st_status_time));
    124
    125	/* get_task_comm isn't exported.  oh well. */
    126	seq_printf(seq, "%p:\n"
    127		   "  pid:          %lu\n"
    128		   "  tgid:         %lu\n"
    129		   "  process name: %s\n"
    130		   "  node:         %u\n"
    131		   "  sc:           %p\n"
    132		   "  message id:   %d\n"
    133		   "  message type: %u\n"
    134		   "  message key:  0x%08x\n"
    135		   "  sock acquiry: %lld usecs ago\n"
    136		   "  send start:   %lld usecs ago\n"
    137		   "  wait start:   %lld usecs ago\n",
    138		   nst, (unsigned long)task_pid_nr(nst->st_task),
    139		   (unsigned long)nst->st_task->tgid,
    140		   nst->st_task->comm, nst->st_node,
    141		   nst->st_sc, nst->st_id, nst->st_msg_type,
    142		   nst->st_msg_key,
    143		   (long long)sock,
    144		   (long long)send,
    145		   (long long)status);
    146
    147out:
    148	spin_unlock(&o2net_debug_lock);
    149
    150	return 0;
    151}
    152
    153static void nst_seq_stop(struct seq_file *seq, void *v)
    154{
    155}
    156
    157static const struct seq_operations nst_seq_ops = {
    158	.start = nst_seq_start,
    159	.next = nst_seq_next,
    160	.stop = nst_seq_stop,
    161	.show = nst_seq_show,
    162};
    163
    164static int nst_fop_open(struct inode *inode, struct file *file)
    165{
    166	struct o2net_send_tracking *dummy_nst;
    167
    168	dummy_nst = __seq_open_private(file, &nst_seq_ops, sizeof(*dummy_nst));
    169	if (!dummy_nst)
    170		return -ENOMEM;
    171	o2net_debug_add_nst(dummy_nst);
    172
    173	return 0;
    174}
    175
    176static int nst_fop_release(struct inode *inode, struct file *file)
    177{
    178	struct seq_file *seq = file->private_data;
    179	struct o2net_send_tracking *dummy_nst = seq->private;
    180
    181	o2net_debug_del_nst(dummy_nst);
    182	return seq_release_private(inode, file);
    183}
    184
    185static const struct file_operations nst_seq_fops = {
    186	.open = nst_fop_open,
    187	.read = seq_read,
    188	.llseek = seq_lseek,
    189	.release = nst_fop_release,
    190};
    191
    192void o2net_debug_add_sc(struct o2net_sock_container *sc)
    193{
    194	spin_lock(&o2net_debug_lock);
    195	list_add(&sc->sc_net_debug_item, &sock_containers);
    196	spin_unlock(&o2net_debug_lock);
    197}
    198
    199void o2net_debug_del_sc(struct o2net_sock_container *sc)
    200{
    201	spin_lock(&o2net_debug_lock);
    202	list_del_init(&sc->sc_net_debug_item);
    203	spin_unlock(&o2net_debug_lock);
    204}
    205
    206struct o2net_sock_debug {
    207	int dbg_ctxt;
    208	struct o2net_sock_container *dbg_sock;
    209};
    210
    211static struct o2net_sock_container
    212			*next_sc(struct o2net_sock_container *sc_start)
    213{
    214	struct o2net_sock_container *sc, *ret = NULL;
    215
    216	assert_spin_locked(&o2net_debug_lock);
    217
    218	list_for_each_entry(sc, &sc_start->sc_net_debug_item,
    219			    sc_net_debug_item) {
    220		/* discover the head of the list miscast as a sc */
    221		if (&sc->sc_net_debug_item == &sock_containers)
    222			break;
    223
    224		/* use sc_page to detect real scs in the list */
    225		if (sc->sc_page != NULL) {
    226			ret = sc;
    227			break;
    228		}
    229	}
    230
    231	return ret;
    232}
    233
    234static void *sc_seq_start(struct seq_file *seq, loff_t *pos)
    235{
    236	struct o2net_sock_debug *sd = seq->private;
    237	struct o2net_sock_container *sc, *dummy_sc = sd->dbg_sock;
    238
    239	spin_lock(&o2net_debug_lock);
    240	sc = next_sc(dummy_sc);
    241	spin_unlock(&o2net_debug_lock);
    242
    243	return sc;
    244}
    245
    246static void *sc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
    247{
    248	struct o2net_sock_debug *sd = seq->private;
    249	struct o2net_sock_container *sc, *dummy_sc = sd->dbg_sock;
    250
    251	spin_lock(&o2net_debug_lock);
    252	sc = next_sc(dummy_sc);
    253	list_del_init(&dummy_sc->sc_net_debug_item);
    254	if (sc)
    255		list_add(&dummy_sc->sc_net_debug_item, &sc->sc_net_debug_item);
    256	spin_unlock(&o2net_debug_lock);
    257
    258	return sc; /* unused, just needs to be null when done */
    259}
    260
    261#ifdef CONFIG_OCFS2_FS_STATS
    262# define sc_send_count(_s)		((_s)->sc_send_count)
    263# define sc_recv_count(_s)		((_s)->sc_recv_count)
    264# define sc_tv_acquiry_total_ns(_s)	(ktime_to_ns((_s)->sc_tv_acquiry_total))
    265# define sc_tv_send_total_ns(_s)	(ktime_to_ns((_s)->sc_tv_send_total))
    266# define sc_tv_status_total_ns(_s)	(ktime_to_ns((_s)->sc_tv_status_total))
    267# define sc_tv_process_total_ns(_s)	(ktime_to_ns((_s)->sc_tv_process_total))
    268#else
    269# define sc_send_count(_s)		(0U)
    270# define sc_recv_count(_s)		(0U)
    271# define sc_tv_acquiry_total_ns(_s)	(0LL)
    272# define sc_tv_send_total_ns(_s)	(0LL)
    273# define sc_tv_status_total_ns(_s)	(0LL)
    274# define sc_tv_process_total_ns(_s)	(0LL)
    275#endif
    276
    277/* So that debugfs.ocfs2 can determine which format is being used */
    278#define O2NET_STATS_STR_VERSION		1
    279static void sc_show_sock_stats(struct seq_file *seq,
    280			       struct o2net_sock_container *sc)
    281{
    282	if (!sc)
    283		return;
    284
    285	seq_printf(seq, "%d,%u,%lu,%lld,%lld,%lld,%lu,%lld\n", O2NET_STATS_STR_VERSION,
    286		   sc->sc_node->nd_num, (unsigned long)sc_send_count(sc),
    287		   (long long)sc_tv_acquiry_total_ns(sc),
    288		   (long long)sc_tv_send_total_ns(sc),
    289		   (long long)sc_tv_status_total_ns(sc),
    290		   (unsigned long)sc_recv_count(sc),
    291		   (long long)sc_tv_process_total_ns(sc));
    292}
    293
    294static void sc_show_sock_container(struct seq_file *seq,
    295				   struct o2net_sock_container *sc)
    296{
    297	struct inet_sock *inet = NULL;
    298	__be32 saddr = 0, daddr = 0;
    299	__be16 sport = 0, dport = 0;
    300
    301	if (!sc)
    302		return;
    303
    304	if (sc->sc_sock) {
    305		inet = inet_sk(sc->sc_sock->sk);
    306		/* the stack's structs aren't sparse endian clean */
    307		saddr = (__force __be32)inet->inet_saddr;
    308		daddr = (__force __be32)inet->inet_daddr;
    309		sport = (__force __be16)inet->inet_sport;
    310		dport = (__force __be16)inet->inet_dport;
    311	}
    312
    313	/* XXX sigh, inet-> doesn't have sparse annotation so any
    314	 * use of it here generates a warning with -Wbitwise */
    315	seq_printf(seq, "%p:\n"
    316		   "  krefs:           %d\n"
    317		   "  sock:            %pI4:%u -> "
    318				      "%pI4:%u\n"
    319		   "  remote node:     %s\n"
    320		   "  page off:        %zu\n"
    321		   "  handshake ok:    %u\n"
    322		   "  timer:           %lld usecs\n"
    323		   "  data ready:      %lld usecs\n"
    324		   "  advance start:   %lld usecs\n"
    325		   "  advance stop:    %lld usecs\n"
    326		   "  func start:      %lld usecs\n"
    327		   "  func stop:       %lld usecs\n"
    328		   "  func key:        0x%08x\n"
    329		   "  func type:       %u\n",
    330		   sc,
    331		   kref_read(&sc->sc_kref),
    332		   &saddr, inet ? ntohs(sport) : 0,
    333		   &daddr, inet ? ntohs(dport) : 0,
    334		   sc->sc_node->nd_name,
    335		   sc->sc_page_off,
    336		   sc->sc_handshake_ok,
    337		   (long long)ktime_to_us(sc->sc_tv_timer),
    338		   (long long)ktime_to_us(sc->sc_tv_data_ready),
    339		   (long long)ktime_to_us(sc->sc_tv_advance_start),
    340		   (long long)ktime_to_us(sc->sc_tv_advance_stop),
    341		   (long long)ktime_to_us(sc->sc_tv_func_start),
    342		   (long long)ktime_to_us(sc->sc_tv_func_stop),
    343		   sc->sc_msg_key,
    344		   sc->sc_msg_type);
    345}
    346
    347static int sc_seq_show(struct seq_file *seq, void *v)
    348{
    349	struct o2net_sock_debug *sd = seq->private;
    350	struct o2net_sock_container *sc, *dummy_sc = sd->dbg_sock;
    351
    352	spin_lock(&o2net_debug_lock);
    353	sc = next_sc(dummy_sc);
    354
    355	if (sc) {
    356		if (sd->dbg_ctxt == SHOW_SOCK_CONTAINERS)
    357			sc_show_sock_container(seq, sc);
    358		else
    359			sc_show_sock_stats(seq, sc);
    360	}
    361
    362	spin_unlock(&o2net_debug_lock);
    363
    364	return 0;
    365}
    366
    367static void sc_seq_stop(struct seq_file *seq, void *v)
    368{
    369}
    370
    371static const struct seq_operations sc_seq_ops = {
    372	.start = sc_seq_start,
    373	.next = sc_seq_next,
    374	.stop = sc_seq_stop,
    375	.show = sc_seq_show,
    376};
    377
    378static int sc_common_open(struct file *file, int ctxt)
    379{
    380	struct o2net_sock_debug *sd;
    381	struct o2net_sock_container *dummy_sc;
    382
    383	dummy_sc = kzalloc(sizeof(*dummy_sc), GFP_KERNEL);
    384	if (!dummy_sc)
    385		return -ENOMEM;
    386
    387	sd = __seq_open_private(file, &sc_seq_ops, sizeof(*sd));
    388	if (!sd) {
    389		kfree(dummy_sc);
    390		return -ENOMEM;
    391	}
    392
    393	sd->dbg_ctxt = ctxt;
    394	sd->dbg_sock = dummy_sc;
    395
    396	o2net_debug_add_sc(dummy_sc);
    397
    398	return 0;
    399}
    400
    401static int sc_fop_release(struct inode *inode, struct file *file)
    402{
    403	struct seq_file *seq = file->private_data;
    404	struct o2net_sock_debug *sd = seq->private;
    405	struct o2net_sock_container *dummy_sc = sd->dbg_sock;
    406
    407	o2net_debug_del_sc(dummy_sc);
    408	kfree(dummy_sc);
    409	return seq_release_private(inode, file);
    410}
    411
    412static int stats_fop_open(struct inode *inode, struct file *file)
    413{
    414	return sc_common_open(file, SHOW_SOCK_STATS);
    415}
    416
    417static const struct file_operations stats_seq_fops = {
    418	.open = stats_fop_open,
    419	.read = seq_read,
    420	.llseek = seq_lseek,
    421	.release = sc_fop_release,
    422};
    423
    424static int sc_fop_open(struct inode *inode, struct file *file)
    425{
    426	return sc_common_open(file, SHOW_SOCK_CONTAINERS);
    427}
    428
    429static const struct file_operations sc_seq_fops = {
    430	.open = sc_fop_open,
    431	.read = seq_read,
    432	.llseek = seq_lseek,
    433	.release = sc_fop_release,
    434};
    435
    436static int o2net_fill_bitmap(char *buf, int len)
    437{
    438	unsigned long map[BITS_TO_LONGS(O2NM_MAX_NODES)];
    439	int i = -1, out = 0;
    440
    441	o2net_fill_node_map(map, sizeof(map));
    442
    443	while ((i = find_next_bit(map, O2NM_MAX_NODES, i + 1)) < O2NM_MAX_NODES)
    444		out += scnprintf(buf + out, PAGE_SIZE - out, "%d ", i);
    445	out += scnprintf(buf + out, PAGE_SIZE - out, "\n");
    446
    447	return out;
    448}
    449
    450static int nodes_fop_open(struct inode *inode, struct file *file)
    451{
    452	char *buf;
    453
    454	buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
    455	if (!buf)
    456		return -ENOMEM;
    457
    458	i_size_write(inode, o2net_fill_bitmap(buf, PAGE_SIZE));
    459
    460	file->private_data = buf;
    461
    462	return 0;
    463}
    464
    465static int o2net_debug_release(struct inode *inode, struct file *file)
    466{
    467	kfree(file->private_data);
    468	return 0;
    469}
    470
    471static ssize_t o2net_debug_read(struct file *file, char __user *buf,
    472				size_t nbytes, loff_t *ppos)
    473{
    474	return simple_read_from_buffer(buf, nbytes, ppos, file->private_data,
    475				       i_size_read(file->f_mapping->host));
    476}
    477
    478static const struct file_operations nodes_fops = {
    479	.open		= nodes_fop_open,
    480	.release	= o2net_debug_release,
    481	.read		= o2net_debug_read,
    482	.llseek		= generic_file_llseek,
    483};
    484
    485void o2net_debugfs_exit(void)
    486{
    487	debugfs_remove_recursive(o2net_dentry);
    488}
    489
    490void o2net_debugfs_init(void)
    491{
    492	umode_t mode = S_IFREG|S_IRUSR;
    493
    494	o2net_dentry = debugfs_create_dir(O2NET_DEBUG_DIR, NULL);
    495
    496	debugfs_create_file(NST_DEBUG_NAME, mode, o2net_dentry, NULL,
    497			    &nst_seq_fops);
    498	debugfs_create_file(SC_DEBUG_NAME, mode, o2net_dentry, NULL,
    499			    &sc_seq_fops);
    500	debugfs_create_file(STATS_DEBUG_NAME, mode, o2net_dentry, NULL,
    501			    &stats_seq_fops);
    502	debugfs_create_file(NODES_DEBUG_NAME, mode, o2net_dentry, NULL,
    503			    &nodes_fops);
    504}
    505
    506#endif	/* CONFIG_DEBUG_FS */