~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/sunrpc/debugfs.c

Version: ~ [ linux-5.8 ] ~ [ linux-5.7.14 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.57 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.138 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.193 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.232 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.232 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 }
299 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp