debugfs.c 8.0 KB

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