2 * debugfs interface for sunrpc
4 * (c) 2014 Jeff Layton <jlayton@primarydata.com>
7 #include <linux/debugfs.h>
8 #include <linux/sunrpc/sched.h>
9 #include <linux/sunrpc/clnt.h>
12 static struct dentry *topdir;
13 static struct dentry *rpc_clnt_dir;
15 struct rpc_clnt_iter {
16 struct rpc_clnt *clnt;
21 tasks_show(struct seq_file *f, void *v)
24 struct rpc_task *task = v;
25 struct rpc_clnt *clnt = task->tk_client;
26 const char *rpc_waitq = "none";
28 if (RPC_IS_QUEUED(task))
29 rpc_waitq = rpc_qname(task->tk_waitqueue);
32 xid = be32_to_cpu(task->tk_rqstp->rq_xid);
34 seq_printf(f, "%5u %04x %6d 0x%x 0x%x %8ld %ps %sv%u %s a:%ps q:%s\n",
35 task->tk_pid, task->tk_flags, task->tk_status,
36 clnt->cl_clid, xid, task->tk_timeout, task->tk_ops,
37 clnt->cl_program->name, clnt->cl_vers, rpc_proc_name(task),
38 task->tk_action, rpc_waitq);
43 tasks_start(struct seq_file *f, loff_t *ppos)
44 __acquires(&clnt->cl_lock)
46 struct rpc_clnt_iter *iter = f->private;
48 struct rpc_clnt *clnt = iter->clnt;
49 struct rpc_task *task;
52 spin_lock(&clnt->cl_lock);
53 list_for_each_entry(task, &clnt->cl_tasks, tk_task)
60 tasks_next(struct seq_file *f, void *v, loff_t *pos)
62 struct rpc_clnt_iter *iter = f->private;
63 struct rpc_clnt *clnt = iter->clnt;
64 struct rpc_task *task = v;
65 struct list_head *next = task->tk_task.next;
70 /* If there's another task on list, return it */
71 if (next == &clnt->cl_tasks)
73 return list_entry(next, struct rpc_task, tk_task);
77 tasks_stop(struct seq_file *f, void *v)
78 __releases(&clnt->cl_lock)
80 struct rpc_clnt_iter *iter = f->private;
81 struct rpc_clnt *clnt = iter->clnt;
83 spin_unlock(&clnt->cl_lock);
86 static const struct seq_operations tasks_seq_operations = {
93 static int tasks_open(struct inode *inode, struct file *filp)
95 int ret = seq_open_private(filp, &tasks_seq_operations,
96 sizeof(struct rpc_clnt_iter));
99 struct seq_file *seq = filp->private_data;
100 struct rpc_clnt_iter *iter = seq->private;
102 iter->clnt = inode->i_private;
104 if (!atomic_inc_not_zero(&iter->clnt->cl_count)) {
105 seq_release_private(inode, filp);
114 tasks_release(struct inode *inode, struct file *filp)
116 struct seq_file *seq = filp->private_data;
117 struct rpc_clnt_iter *iter = seq->private;
119 rpc_release_client(iter->clnt);
120 return seq_release_private(inode, filp);
123 static const struct file_operations tasks_fops = {
124 .owner = THIS_MODULE,
128 .release = tasks_release,
132 rpc_clnt_debugfs_register(struct rpc_clnt *clnt)
135 char name[9]; /* 8 for hex digits + NULL terminator */
137 /* Already registered? */
138 if (clnt->cl_debugfs)
141 len = snprintf(name, sizeof(name), "%x", clnt->cl_clid);
142 if (len >= sizeof(name))
145 /* make the per-client dir */
146 clnt->cl_debugfs = debugfs_create_dir(name, rpc_clnt_dir);
147 if (!clnt->cl_debugfs)
150 /* make tasks file */
151 if (!debugfs_create_file("tasks", S_IFREG | S_IRUSR, clnt->cl_debugfs,
152 clnt, &tasks_fops)) {
153 debugfs_remove_recursive(clnt->cl_debugfs);
154 clnt->cl_debugfs = NULL;
162 rpc_clnt_debugfs_unregister(struct rpc_clnt *clnt)
164 debugfs_remove_recursive(clnt->cl_debugfs);
165 clnt->cl_debugfs = NULL;
169 sunrpc_debugfs_exit(void)
171 debugfs_remove_recursive(topdir);
175 sunrpc_debugfs_init(void)
177 topdir = debugfs_create_dir("sunrpc", NULL);
181 rpc_clnt_dir = debugfs_create_dir("rpc_clnt", topdir);
187 debugfs_remove_recursive(topdir);