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