xref: /openbmc/linux/net/sunrpc/debugfs.c (revision b4b9d2cc)
1b4b9d2ccSJeff Layton /**
2b4b9d2ccSJeff Layton  * debugfs interface for sunrpc
3b4b9d2ccSJeff Layton  *
4b4b9d2ccSJeff Layton  * (c) 2014 Jeff Layton <jlayton@primarydata.com>
5b4b9d2ccSJeff Layton  */
6b4b9d2ccSJeff Layton 
7b4b9d2ccSJeff Layton #include <linux/debugfs.h>
8b4b9d2ccSJeff Layton #include <linux/sunrpc/sched.h>
9b4b9d2ccSJeff Layton #include <linux/sunrpc/clnt.h>
10b4b9d2ccSJeff Layton #include "netns.h"
11b4b9d2ccSJeff Layton 
12b4b9d2ccSJeff Layton static struct dentry *topdir;
13b4b9d2ccSJeff Layton static struct dentry *rpc_clnt_dir;
14b4b9d2ccSJeff Layton 
15b4b9d2ccSJeff Layton struct rpc_clnt_iter {
16b4b9d2ccSJeff Layton 	struct rpc_clnt	*clnt;
17b4b9d2ccSJeff Layton 	loff_t		pos;
18b4b9d2ccSJeff Layton };
19b4b9d2ccSJeff Layton 
20b4b9d2ccSJeff Layton static int
21b4b9d2ccSJeff Layton tasks_show(struct seq_file *f, void *v)
22b4b9d2ccSJeff Layton {
23b4b9d2ccSJeff Layton 	u32 xid = 0;
24b4b9d2ccSJeff Layton 	struct rpc_task *task = v;
25b4b9d2ccSJeff Layton 	struct rpc_clnt *clnt = task->tk_client;
26b4b9d2ccSJeff Layton 	const char *rpc_waitq = "none";
27b4b9d2ccSJeff Layton 
28b4b9d2ccSJeff Layton 	if (RPC_IS_QUEUED(task))
29b4b9d2ccSJeff Layton 		rpc_waitq = rpc_qname(task->tk_waitqueue);
30b4b9d2ccSJeff Layton 
31b4b9d2ccSJeff Layton 	if (task->tk_rqstp)
32b4b9d2ccSJeff Layton 		xid = be32_to_cpu(task->tk_rqstp->rq_xid);
33b4b9d2ccSJeff Layton 
34b4b9d2ccSJeff Layton 	seq_printf(f, "%5u %04x %6d 0x%x 0x%x %8ld %ps %sv%u %s a:%ps q:%s\n",
35b4b9d2ccSJeff Layton 		task->tk_pid, task->tk_flags, task->tk_status,
36b4b9d2ccSJeff Layton 		clnt->cl_clid, xid, task->tk_timeout, task->tk_ops,
37b4b9d2ccSJeff Layton 		clnt->cl_program->name, clnt->cl_vers, rpc_proc_name(task),
38b4b9d2ccSJeff Layton 		task->tk_action, rpc_waitq);
39b4b9d2ccSJeff Layton 	return 0;
40b4b9d2ccSJeff Layton }
41b4b9d2ccSJeff Layton 
42b4b9d2ccSJeff Layton static void *
43b4b9d2ccSJeff Layton tasks_start(struct seq_file *f, loff_t *ppos)
44b4b9d2ccSJeff Layton 	__acquires(&clnt->cl_lock)
45b4b9d2ccSJeff Layton {
46b4b9d2ccSJeff Layton 	struct rpc_clnt_iter *iter = f->private;
47b4b9d2ccSJeff Layton 	loff_t pos = *ppos;
48b4b9d2ccSJeff Layton 	struct rpc_clnt *clnt = iter->clnt;
49b4b9d2ccSJeff Layton 	struct rpc_task *task;
50b4b9d2ccSJeff Layton 
51b4b9d2ccSJeff Layton 	iter->pos = pos + 1;
52b4b9d2ccSJeff Layton 	spin_lock(&clnt->cl_lock);
53b4b9d2ccSJeff Layton 	list_for_each_entry(task, &clnt->cl_tasks, tk_task)
54b4b9d2ccSJeff Layton 		if (pos-- == 0)
55b4b9d2ccSJeff Layton 			return task;
56b4b9d2ccSJeff Layton 	return NULL;
57b4b9d2ccSJeff Layton }
58b4b9d2ccSJeff Layton 
59b4b9d2ccSJeff Layton static void *
60b4b9d2ccSJeff Layton tasks_next(struct seq_file *f, void *v, loff_t *pos)
61b4b9d2ccSJeff Layton {
62b4b9d2ccSJeff Layton 	struct rpc_clnt_iter *iter = f->private;
63b4b9d2ccSJeff Layton 	struct rpc_clnt *clnt = iter->clnt;
64b4b9d2ccSJeff Layton 	struct rpc_task *task = v;
65b4b9d2ccSJeff Layton 	struct list_head *next = task->tk_task.next;
66b4b9d2ccSJeff Layton 
67b4b9d2ccSJeff Layton 	++iter->pos;
68b4b9d2ccSJeff Layton 	++*pos;
69b4b9d2ccSJeff Layton 
70b4b9d2ccSJeff Layton 	/* If there's another task on list, return it */
71b4b9d2ccSJeff Layton 	if (next == &clnt->cl_tasks)
72b4b9d2ccSJeff Layton 		return NULL;
73b4b9d2ccSJeff Layton 	return list_entry(next, struct rpc_task, tk_task);
74b4b9d2ccSJeff Layton }
75b4b9d2ccSJeff Layton 
76b4b9d2ccSJeff Layton static void
77b4b9d2ccSJeff Layton tasks_stop(struct seq_file *f, void *v)
78b4b9d2ccSJeff Layton 	__releases(&clnt->cl_lock)
79b4b9d2ccSJeff Layton {
80b4b9d2ccSJeff Layton 	struct rpc_clnt_iter *iter = f->private;
81b4b9d2ccSJeff Layton 	struct rpc_clnt *clnt = iter->clnt;
82b4b9d2ccSJeff Layton 
83b4b9d2ccSJeff Layton 	spin_unlock(&clnt->cl_lock);
84b4b9d2ccSJeff Layton }
85b4b9d2ccSJeff Layton 
86b4b9d2ccSJeff Layton static const struct seq_operations tasks_seq_operations = {
87b4b9d2ccSJeff Layton 	.start	= tasks_start,
88b4b9d2ccSJeff Layton 	.next	= tasks_next,
89b4b9d2ccSJeff Layton 	.stop	= tasks_stop,
90b4b9d2ccSJeff Layton 	.show	= tasks_show,
91b4b9d2ccSJeff Layton };
92b4b9d2ccSJeff Layton 
93b4b9d2ccSJeff Layton static int tasks_open(struct inode *inode, struct file *filp)
94b4b9d2ccSJeff Layton {
95b4b9d2ccSJeff Layton 	int ret = seq_open_private(filp, &tasks_seq_operations,
96b4b9d2ccSJeff Layton 					sizeof(struct rpc_clnt_iter));
97b4b9d2ccSJeff Layton 
98b4b9d2ccSJeff Layton 	if (!ret) {
99b4b9d2ccSJeff Layton 		struct seq_file *seq = filp->private_data;
100b4b9d2ccSJeff Layton 		struct rpc_clnt_iter *iter = seq->private;
101b4b9d2ccSJeff Layton 
102b4b9d2ccSJeff Layton 		iter->clnt = inode->i_private;
103b4b9d2ccSJeff Layton 
104b4b9d2ccSJeff Layton 		if (!atomic_inc_not_zero(&iter->clnt->cl_count)) {
105b4b9d2ccSJeff Layton 			seq_release_private(inode, filp);
106b4b9d2ccSJeff Layton 			ret = -EINVAL;
107b4b9d2ccSJeff Layton 		}
108b4b9d2ccSJeff Layton 	}
109b4b9d2ccSJeff Layton 
110b4b9d2ccSJeff Layton 	return ret;
111b4b9d2ccSJeff Layton }
112b4b9d2ccSJeff Layton 
113b4b9d2ccSJeff Layton static int
114b4b9d2ccSJeff Layton tasks_release(struct inode *inode, struct file *filp)
115b4b9d2ccSJeff Layton {
116b4b9d2ccSJeff Layton 	struct seq_file *seq = filp->private_data;
117b4b9d2ccSJeff Layton 	struct rpc_clnt_iter *iter = seq->private;
118b4b9d2ccSJeff Layton 
119b4b9d2ccSJeff Layton 	rpc_release_client(iter->clnt);
120b4b9d2ccSJeff Layton 	return seq_release_private(inode, filp);
121b4b9d2ccSJeff Layton }
122b4b9d2ccSJeff Layton 
123b4b9d2ccSJeff Layton static const struct file_operations tasks_fops = {
124b4b9d2ccSJeff Layton 	.owner		= THIS_MODULE,
125b4b9d2ccSJeff Layton 	.open		= tasks_open,
126b4b9d2ccSJeff Layton 	.read		= seq_read,
127b4b9d2ccSJeff Layton 	.llseek		= seq_lseek,
128b4b9d2ccSJeff Layton 	.release	= tasks_release,
129b4b9d2ccSJeff Layton };
130b4b9d2ccSJeff Layton 
131b4b9d2ccSJeff Layton int
132b4b9d2ccSJeff Layton rpc_clnt_debugfs_register(struct rpc_clnt *clnt)
133b4b9d2ccSJeff Layton {
134b4b9d2ccSJeff Layton 	int len;
135b4b9d2ccSJeff Layton 	char name[9]; /* 8 for hex digits + NULL terminator */
136b4b9d2ccSJeff Layton 
137b4b9d2ccSJeff Layton 	/* Already registered? */
138b4b9d2ccSJeff Layton 	if (clnt->cl_debugfs)
139b4b9d2ccSJeff Layton 		return 0;
140b4b9d2ccSJeff Layton 
141b4b9d2ccSJeff Layton 	len = snprintf(name, sizeof(name), "%x", clnt->cl_clid);
142b4b9d2ccSJeff Layton 	if (len >= sizeof(name))
143b4b9d2ccSJeff Layton 		return -EINVAL;
144b4b9d2ccSJeff Layton 
145b4b9d2ccSJeff Layton 	/* make the per-client dir */
146b4b9d2ccSJeff Layton 	clnt->cl_debugfs = debugfs_create_dir(name, rpc_clnt_dir);
147b4b9d2ccSJeff Layton 	if (!clnt->cl_debugfs)
148b4b9d2ccSJeff Layton 		return -ENOMEM;
149b4b9d2ccSJeff Layton 
150b4b9d2ccSJeff Layton 	/* make tasks file */
151b4b9d2ccSJeff Layton 	if (!debugfs_create_file("tasks", S_IFREG | S_IRUSR, clnt->cl_debugfs,
152b4b9d2ccSJeff Layton 				 clnt, &tasks_fops)) {
153b4b9d2ccSJeff Layton 		debugfs_remove_recursive(clnt->cl_debugfs);
154b4b9d2ccSJeff Layton 		clnt->cl_debugfs = NULL;
155b4b9d2ccSJeff Layton 		return -ENOMEM;
156b4b9d2ccSJeff Layton 	}
157b4b9d2ccSJeff Layton 
158b4b9d2ccSJeff Layton 	return 0;
159b4b9d2ccSJeff Layton }
160b4b9d2ccSJeff Layton 
161b4b9d2ccSJeff Layton void
162b4b9d2ccSJeff Layton rpc_clnt_debugfs_unregister(struct rpc_clnt *clnt)
163b4b9d2ccSJeff Layton {
164b4b9d2ccSJeff Layton 	debugfs_remove_recursive(clnt->cl_debugfs);
165b4b9d2ccSJeff Layton 	clnt->cl_debugfs = NULL;
166b4b9d2ccSJeff Layton }
167b4b9d2ccSJeff Layton 
168b4b9d2ccSJeff Layton void __exit
169b4b9d2ccSJeff Layton sunrpc_debugfs_exit(void)
170b4b9d2ccSJeff Layton {
171b4b9d2ccSJeff Layton 	debugfs_remove_recursive(topdir);
172b4b9d2ccSJeff Layton }
173b4b9d2ccSJeff Layton 
174b4b9d2ccSJeff Layton int __init
175b4b9d2ccSJeff Layton sunrpc_debugfs_init(void)
176b4b9d2ccSJeff Layton {
177b4b9d2ccSJeff Layton 	topdir = debugfs_create_dir("sunrpc", NULL);
178b4b9d2ccSJeff Layton 	if (!topdir)
179b4b9d2ccSJeff Layton 		goto out;
180b4b9d2ccSJeff Layton 
181b4b9d2ccSJeff Layton 	rpc_clnt_dir = debugfs_create_dir("rpc_clnt", topdir);
182b4b9d2ccSJeff Layton 	if (!rpc_clnt_dir)
183b4b9d2ccSJeff Layton 		goto out_remove;
184b4b9d2ccSJeff Layton 
185b4b9d2ccSJeff Layton 	return 0;
186b4b9d2ccSJeff Layton out_remove:
187b4b9d2ccSJeff Layton 	debugfs_remove_recursive(topdir);
188b4b9d2ccSJeff Layton 	topdir = NULL;
189b4b9d2ccSJeff Layton out:
190b4b9d2ccSJeff Layton 	return -ENOMEM;
191b4b9d2ccSJeff Layton }
192