root/net/sunrpc/debugfs.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. tasks_show
  2. tasks_start
  3. tasks_next
  4. tasks_stop
  5. tasks_open
  6. tasks_release
  7. do_xprt_debugfs
  8. rpc_clnt_debugfs_register
  9. rpc_clnt_debugfs_unregister
  10. xprt_info_show
  11. xprt_info_open
  12. xprt_info_release
  13. rpc_xprt_debugfs_register
  14. rpc_xprt_debugfs_unregister
  15. fault_open
  16. fault_release
  17. fault_disconnect_read
  18. fault_disconnect_write
  19. sunrpc_debugfs_exit
  20. sunrpc_debugfs_init

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

/* [<][>][^][v][top][bottom][index][help] */