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

debugfs.c (6596B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * debugfs interface for sunrpc
      4 *
      5 * (c) 2014 Jeff Layton <jlayton@primarydata.com>
      6 */
      7
      8#include <linux/debugfs.h>
      9#include <linux/sunrpc/sched.h>
     10#include <linux/sunrpc/clnt.h>
     11
     12#include "netns.h"
     13#include "fail.h"
     14
     15static struct dentry *topdir;
     16static struct dentry *rpc_clnt_dir;
     17static struct dentry *rpc_xprt_dir;
     18
     19static int
     20tasks_show(struct seq_file *f, void *v)
     21{
     22	u32 xid = 0;
     23	struct rpc_task *task = v;
     24	struct rpc_clnt *clnt = task->tk_client;
     25	const char *rpc_waitq = "none";
     26
     27	if (RPC_IS_QUEUED(task))
     28		rpc_waitq = rpc_qname(task->tk_waitqueue);
     29
     30	if (task->tk_rqstp)
     31		xid = be32_to_cpu(task->tk_rqstp->rq_xid);
     32
     33	seq_printf(f, "%5u %04x %6d 0x%x 0x%x %8ld %ps %sv%u %s a:%ps q:%s\n",
     34		task->tk_pid, task->tk_flags, task->tk_status,
     35		clnt->cl_clid, xid, rpc_task_timeout(task), task->tk_ops,
     36		clnt->cl_program->name, clnt->cl_vers, rpc_proc_name(task),
     37		task->tk_action, rpc_waitq);
     38	return 0;
     39}
     40
     41static void *
     42tasks_start(struct seq_file *f, loff_t *ppos)
     43	__acquires(&clnt->cl_lock)
     44{
     45	struct rpc_clnt *clnt = f->private;
     46	loff_t pos = *ppos;
     47	struct rpc_task *task;
     48
     49	spin_lock(&clnt->cl_lock);
     50	list_for_each_entry(task, &clnt->cl_tasks, tk_task)
     51		if (pos-- == 0)
     52			return task;
     53	return NULL;
     54}
     55
     56static void *
     57tasks_next(struct seq_file *f, void *v, loff_t *pos)
     58{
     59	struct rpc_clnt *clnt = f->private;
     60	struct rpc_task *task = v;
     61	struct list_head *next = task->tk_task.next;
     62
     63	++*pos;
     64
     65	/* If there's another task on list, return it */
     66	if (next == &clnt->cl_tasks)
     67		return NULL;
     68	return list_entry(next, struct rpc_task, tk_task);
     69}
     70
     71static void
     72tasks_stop(struct seq_file *f, void *v)
     73	__releases(&clnt->cl_lock)
     74{
     75	struct rpc_clnt *clnt = f->private;
     76	spin_unlock(&clnt->cl_lock);
     77}
     78
     79static const struct seq_operations tasks_seq_operations = {
     80	.start	= tasks_start,
     81	.next	= tasks_next,
     82	.stop	= tasks_stop,
     83	.show	= tasks_show,
     84};
     85
     86static int tasks_open(struct inode *inode, struct file *filp)
     87{
     88	int ret = seq_open(filp, &tasks_seq_operations);
     89	if (!ret) {
     90		struct seq_file *seq = filp->private_data;
     91		struct rpc_clnt *clnt = seq->private = inode->i_private;
     92
     93		if (!refcount_inc_not_zero(&clnt->cl_count)) {
     94			seq_release(inode, filp);
     95			ret = -EINVAL;
     96		}
     97	}
     98
     99	return ret;
    100}
    101
    102static int
    103tasks_release(struct inode *inode, struct file *filp)
    104{
    105	struct seq_file *seq = filp->private_data;
    106	struct rpc_clnt *clnt = seq->private;
    107
    108	rpc_release_client(clnt);
    109	return seq_release(inode, filp);
    110}
    111
    112static const struct file_operations tasks_fops = {
    113	.owner		= THIS_MODULE,
    114	.open		= tasks_open,
    115	.read		= seq_read,
    116	.llseek		= seq_lseek,
    117	.release	= tasks_release,
    118};
    119
    120static int do_xprt_debugfs(struct rpc_clnt *clnt, struct rpc_xprt *xprt, void *numv)
    121{
    122	int len;
    123	char name[24]; /* enough for "../../rpc_xprt/ + 8 hex digits + NULL */
    124	char link[9]; /* enough for 8 hex digits + NULL */
    125	int *nump = numv;
    126
    127	if (IS_ERR_OR_NULL(xprt->debugfs))
    128		return 0;
    129	len = snprintf(name, sizeof(name), "../../rpc_xprt/%s",
    130		       xprt->debugfs->d_name.name);
    131	if (len >= sizeof(name))
    132		return -1;
    133	if (*nump == 0)
    134		strcpy(link, "xprt");
    135	else {
    136		len = snprintf(link, sizeof(link), "xprt%d", *nump);
    137		if (len >= sizeof(link))
    138			return -1;
    139	}
    140	debugfs_create_symlink(link, clnt->cl_debugfs, name);
    141	(*nump)++;
    142	return 0;
    143}
    144
    145void
    146rpc_clnt_debugfs_register(struct rpc_clnt *clnt)
    147{
    148	int len;
    149	char name[9]; /* enough for 8 hex digits + NULL */
    150	int xprtnum = 0;
    151
    152	len = snprintf(name, sizeof(name), "%x", clnt->cl_clid);
    153	if (len >= sizeof(name))
    154		return;
    155
    156	/* make the per-client dir */
    157	clnt->cl_debugfs = debugfs_create_dir(name, rpc_clnt_dir);
    158
    159	/* make tasks file */
    160	debugfs_create_file("tasks", S_IFREG | 0400, clnt->cl_debugfs, clnt,
    161			    &tasks_fops);
    162
    163	rpc_clnt_iterate_for_each_xprt(clnt, do_xprt_debugfs, &xprtnum);
    164}
    165
    166void
    167rpc_clnt_debugfs_unregister(struct rpc_clnt *clnt)
    168{
    169	debugfs_remove_recursive(clnt->cl_debugfs);
    170	clnt->cl_debugfs = NULL;
    171}
    172
    173static int
    174xprt_info_show(struct seq_file *f, void *v)
    175{
    176	struct rpc_xprt *xprt = f->private;
    177
    178	seq_printf(f, "netid: %s\n", xprt->address_strings[RPC_DISPLAY_NETID]);
    179	seq_printf(f, "addr:  %s\n", xprt->address_strings[RPC_DISPLAY_ADDR]);
    180	seq_printf(f, "port:  %s\n", xprt->address_strings[RPC_DISPLAY_PORT]);
    181	seq_printf(f, "state: 0x%lx\n", xprt->state);
    182	return 0;
    183}
    184
    185static int
    186xprt_info_open(struct inode *inode, struct file *filp)
    187{
    188	int ret;
    189	struct rpc_xprt *xprt = inode->i_private;
    190
    191	ret = single_open(filp, xprt_info_show, xprt);
    192
    193	if (!ret) {
    194		if (!xprt_get(xprt)) {
    195			single_release(inode, filp);
    196			ret = -EINVAL;
    197		}
    198	}
    199	return ret;
    200}
    201
    202static int
    203xprt_info_release(struct inode *inode, struct file *filp)
    204{
    205	struct rpc_xprt *xprt = inode->i_private;
    206
    207	xprt_put(xprt);
    208	return single_release(inode, filp);
    209}
    210
    211static const struct file_operations xprt_info_fops = {
    212	.owner		= THIS_MODULE,
    213	.open		= xprt_info_open,
    214	.read		= seq_read,
    215	.llseek		= seq_lseek,
    216	.release	= xprt_info_release,
    217};
    218
    219void
    220rpc_xprt_debugfs_register(struct rpc_xprt *xprt)
    221{
    222	int len, id;
    223	static atomic_t	cur_id;
    224	char		name[9]; /* 8 hex digits + NULL term */
    225
    226	id = (unsigned int)atomic_inc_return(&cur_id);
    227
    228	len = snprintf(name, sizeof(name), "%x", id);
    229	if (len >= sizeof(name))
    230		return;
    231
    232	/* make the per-client dir */
    233	xprt->debugfs = debugfs_create_dir(name, rpc_xprt_dir);
    234
    235	/* make tasks file */
    236	debugfs_create_file("info", S_IFREG | 0400, xprt->debugfs, xprt,
    237			    &xprt_info_fops);
    238}
    239
    240void
    241rpc_xprt_debugfs_unregister(struct rpc_xprt *xprt)
    242{
    243	debugfs_remove_recursive(xprt->debugfs);
    244	xprt->debugfs = NULL;
    245}
    246
    247#if IS_ENABLED(CONFIG_FAIL_SUNRPC)
    248struct fail_sunrpc_attr fail_sunrpc = {
    249	.attr			= FAULT_ATTR_INITIALIZER,
    250};
    251EXPORT_SYMBOL_GPL(fail_sunrpc);
    252
    253static void fail_sunrpc_init(void)
    254{
    255	struct dentry *dir;
    256
    257	dir = fault_create_debugfs_attr("fail_sunrpc", NULL,
    258					&fail_sunrpc.attr);
    259
    260	debugfs_create_bool("ignore-client-disconnect", S_IFREG | 0600, dir,
    261			    &fail_sunrpc.ignore_client_disconnect);
    262
    263	debugfs_create_bool("ignore-server-disconnect", S_IFREG | 0600, dir,
    264			    &fail_sunrpc.ignore_server_disconnect);
    265
    266	debugfs_create_bool("ignore-cache-wait", S_IFREG | 0600, dir,
    267			    &fail_sunrpc.ignore_cache_wait);
    268}
    269#else
    270static void fail_sunrpc_init(void)
    271{
    272}
    273#endif
    274
    275void __exit
    276sunrpc_debugfs_exit(void)
    277{
    278	debugfs_remove_recursive(topdir);
    279	topdir = NULL;
    280	rpc_clnt_dir = NULL;
    281	rpc_xprt_dir = NULL;
    282}
    283
    284void __init
    285sunrpc_debugfs_init(void)
    286{
    287	topdir = debugfs_create_dir("sunrpc", NULL);
    288
    289	rpc_clnt_dir = debugfs_create_dir("rpc_clnt", topdir);
    290
    291	rpc_xprt_dir = debugfs_create_dir("rpc_xprt", topdir);
    292
    293	fail_sunrpc_init();
    294}