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