Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * debugfs interface for sunrpc
0004  *
0005  * (c) 2014 Jeff Layton <jlayton@primarydata.com>
0006  */
0007 
0008 #include <linux/debugfs.h>
0009 #include <linux/sunrpc/sched.h>
0010 #include <linux/sunrpc/clnt.h>
0011 
0012 #include "netns.h"
0013 #include "fail.h"
0014 
0015 static struct dentry *topdir;
0016 static struct dentry *rpc_clnt_dir;
0017 static struct dentry *rpc_xprt_dir;
0018 
0019 static int
0020 tasks_show(struct seq_file *f, void *v)
0021 {
0022     u32 xid = 0;
0023     struct rpc_task *task = v;
0024     struct rpc_clnt *clnt = task->tk_client;
0025     const char *rpc_waitq = "none";
0026 
0027     if (RPC_IS_QUEUED(task))
0028         rpc_waitq = rpc_qname(task->tk_waitqueue);
0029 
0030     if (task->tk_rqstp)
0031         xid = be32_to_cpu(task->tk_rqstp->rq_xid);
0032 
0033     seq_printf(f, "%5u %04x %6d 0x%x 0x%x %8ld %ps %sv%u %s a:%ps q:%s\n",
0034         task->tk_pid, task->tk_flags, task->tk_status,
0035         clnt->cl_clid, xid, rpc_task_timeout(task), task->tk_ops,
0036         clnt->cl_program->name, clnt->cl_vers, rpc_proc_name(task),
0037         task->tk_action, rpc_waitq);
0038     return 0;
0039 }
0040 
0041 static void *
0042 tasks_start(struct seq_file *f, loff_t *ppos)
0043     __acquires(&clnt->cl_lock)
0044 {
0045     struct rpc_clnt *clnt = f->private;
0046     loff_t pos = *ppos;
0047     struct rpc_task *task;
0048 
0049     spin_lock(&clnt->cl_lock);
0050     list_for_each_entry(task, &clnt->cl_tasks, tk_task)
0051         if (pos-- == 0)
0052             return task;
0053     return NULL;
0054 }
0055 
0056 static void *
0057 tasks_next(struct seq_file *f, void *v, loff_t *pos)
0058 {
0059     struct rpc_clnt *clnt = f->private;
0060     struct rpc_task *task = v;
0061     struct list_head *next = task->tk_task.next;
0062 
0063     ++*pos;
0064 
0065     /* If there's another task on list, return it */
0066     if (next == &clnt->cl_tasks)
0067         return NULL;
0068     return list_entry(next, struct rpc_task, tk_task);
0069 }
0070 
0071 static void
0072 tasks_stop(struct seq_file *f, void *v)
0073     __releases(&clnt->cl_lock)
0074 {
0075     struct rpc_clnt *clnt = f->private;
0076     spin_unlock(&clnt->cl_lock);
0077 }
0078 
0079 static const struct seq_operations tasks_seq_operations = {
0080     .start  = tasks_start,
0081     .next   = tasks_next,
0082     .stop   = tasks_stop,
0083     .show   = tasks_show,
0084 };
0085 
0086 static int tasks_open(struct inode *inode, struct file *filp)
0087 {
0088     int ret = seq_open(filp, &tasks_seq_operations);
0089     if (!ret) {
0090         struct seq_file *seq = filp->private_data;
0091         struct rpc_clnt *clnt = seq->private = inode->i_private;
0092 
0093         if (!refcount_inc_not_zero(&clnt->cl_count)) {
0094             seq_release(inode, filp);
0095             ret = -EINVAL;
0096         }
0097     }
0098 
0099     return ret;
0100 }
0101 
0102 static int
0103 tasks_release(struct inode *inode, struct file *filp)
0104 {
0105     struct seq_file *seq = filp->private_data;
0106     struct rpc_clnt *clnt = seq->private;
0107 
0108     rpc_release_client(clnt);
0109     return seq_release(inode, filp);
0110 }
0111 
0112 static const struct file_operations tasks_fops = {
0113     .owner      = THIS_MODULE,
0114     .open       = tasks_open,
0115     .read       = seq_read,
0116     .llseek     = seq_lseek,
0117     .release    = tasks_release,
0118 };
0119 
0120 static int do_xprt_debugfs(struct rpc_clnt *clnt, struct rpc_xprt *xprt, void *numv)
0121 {
0122     int len;
0123     char name[24]; /* enough for "../../rpc_xprt/ + 8 hex digits + NULL */
0124     char link[9]; /* enough for 8 hex digits + NULL */
0125     int *nump = numv;
0126 
0127     if (IS_ERR_OR_NULL(xprt->debugfs))
0128         return 0;
0129     len = snprintf(name, sizeof(name), "../../rpc_xprt/%s",
0130                xprt->debugfs->d_name.name);
0131     if (len >= sizeof(name))
0132         return -1;
0133     if (*nump == 0)
0134         strcpy(link, "xprt");
0135     else {
0136         len = snprintf(link, sizeof(link), "xprt%d", *nump);
0137         if (len >= sizeof(link))
0138             return -1;
0139     }
0140     debugfs_create_symlink(link, clnt->cl_debugfs, name);
0141     (*nump)++;
0142     return 0;
0143 }
0144 
0145 void
0146 rpc_clnt_debugfs_register(struct rpc_clnt *clnt)
0147 {
0148     int len;
0149     char name[9]; /* enough for 8 hex digits + NULL */
0150     int xprtnum = 0;
0151 
0152     len = snprintf(name, sizeof(name), "%x", clnt->cl_clid);
0153     if (len >= sizeof(name))
0154         return;
0155 
0156     /* make the per-client dir */
0157     clnt->cl_debugfs = debugfs_create_dir(name, rpc_clnt_dir);
0158 
0159     /* make tasks file */
0160     debugfs_create_file("tasks", S_IFREG | 0400, clnt->cl_debugfs, clnt,
0161                 &tasks_fops);
0162 
0163     rpc_clnt_iterate_for_each_xprt(clnt, do_xprt_debugfs, &xprtnum);
0164 }
0165 
0166 void
0167 rpc_clnt_debugfs_unregister(struct rpc_clnt *clnt)
0168 {
0169     debugfs_remove_recursive(clnt->cl_debugfs);
0170     clnt->cl_debugfs = NULL;
0171 }
0172 
0173 static int
0174 xprt_info_show(struct seq_file *f, void *v)
0175 {
0176     struct rpc_xprt *xprt = f->private;
0177 
0178     seq_printf(f, "netid: %s\n", xprt->address_strings[RPC_DISPLAY_NETID]);
0179     seq_printf(f, "addr:  %s\n", xprt->address_strings[RPC_DISPLAY_ADDR]);
0180     seq_printf(f, "port:  %s\n", xprt->address_strings[RPC_DISPLAY_PORT]);
0181     seq_printf(f, "state: 0x%lx\n", xprt->state);
0182     return 0;
0183 }
0184 
0185 static int
0186 xprt_info_open(struct inode *inode, struct file *filp)
0187 {
0188     int ret;
0189     struct rpc_xprt *xprt = inode->i_private;
0190 
0191     ret = single_open(filp, xprt_info_show, xprt);
0192 
0193     if (!ret) {
0194         if (!xprt_get(xprt)) {
0195             single_release(inode, filp);
0196             ret = -EINVAL;
0197         }
0198     }
0199     return ret;
0200 }
0201 
0202 static int
0203 xprt_info_release(struct inode *inode, struct file *filp)
0204 {
0205     struct rpc_xprt *xprt = inode->i_private;
0206 
0207     xprt_put(xprt);
0208     return single_release(inode, filp);
0209 }
0210 
0211 static const struct file_operations xprt_info_fops = {
0212     .owner      = THIS_MODULE,
0213     .open       = xprt_info_open,
0214     .read       = seq_read,
0215     .llseek     = seq_lseek,
0216     .release    = xprt_info_release,
0217 };
0218 
0219 void
0220 rpc_xprt_debugfs_register(struct rpc_xprt *xprt)
0221 {
0222     int len, id;
0223     static atomic_t cur_id;
0224     char        name[9]; /* 8 hex digits + NULL term */
0225 
0226     id = (unsigned int)atomic_inc_return(&cur_id);
0227 
0228     len = snprintf(name, sizeof(name), "%x", id);
0229     if (len >= sizeof(name))
0230         return;
0231 
0232     /* make the per-client dir */
0233     xprt->debugfs = debugfs_create_dir(name, rpc_xprt_dir);
0234 
0235     /* make tasks file */
0236     debugfs_create_file("info", S_IFREG | 0400, xprt->debugfs, xprt,
0237                 &xprt_info_fops);
0238 }
0239 
0240 void
0241 rpc_xprt_debugfs_unregister(struct rpc_xprt *xprt)
0242 {
0243     debugfs_remove_recursive(xprt->debugfs);
0244     xprt->debugfs = NULL;
0245 }
0246 
0247 #if IS_ENABLED(CONFIG_FAIL_SUNRPC)
0248 struct fail_sunrpc_attr fail_sunrpc = {
0249     .attr           = FAULT_ATTR_INITIALIZER,
0250 };
0251 EXPORT_SYMBOL_GPL(fail_sunrpc);
0252 
0253 static void fail_sunrpc_init(void)
0254 {
0255     struct dentry *dir;
0256 
0257     dir = fault_create_debugfs_attr("fail_sunrpc", NULL,
0258                     &fail_sunrpc.attr);
0259 
0260     debugfs_create_bool("ignore-client-disconnect", S_IFREG | 0600, dir,
0261                 &fail_sunrpc.ignore_client_disconnect);
0262 
0263     debugfs_create_bool("ignore-server-disconnect", S_IFREG | 0600, dir,
0264                 &fail_sunrpc.ignore_server_disconnect);
0265 
0266     debugfs_create_bool("ignore-cache-wait", S_IFREG | 0600, dir,
0267                 &fail_sunrpc.ignore_cache_wait);
0268 }
0269 #else
0270 static void fail_sunrpc_init(void)
0271 {
0272 }
0273 #endif
0274 
0275 void __exit
0276 sunrpc_debugfs_exit(void)
0277 {
0278     debugfs_remove_recursive(topdir);
0279     topdir = NULL;
0280     rpc_clnt_dir = NULL;
0281     rpc_xprt_dir = NULL;
0282 }
0283 
0284 void __init
0285 sunrpc_debugfs_init(void)
0286 {
0287     topdir = debugfs_create_dir("sunrpc", NULL);
0288 
0289     rpc_clnt_dir = debugfs_create_dir("rpc_clnt", topdir);
0290 
0291     rpc_xprt_dir = debugfs_create_dir("rpc_xprt", topdir);
0292 
0293     fail_sunrpc_init();
0294 }