Blame view

net/sunrpc/debugfs.c 7.16 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
b6580ab39   Trond Myklebust   SUNRPC: Remove wa...
2
  /*
b4b9d2ccf   Jeff Layton   sunrpc: add debug...
3
4
5
6
7
8
9
10
11
12
13
14
   * debugfs interface for sunrpc
   *
   * (c) 2014 Jeff Layton <jlayton@primarydata.com>
   */
  
  #include <linux/debugfs.h>
  #include <linux/sunrpc/sched.h>
  #include <linux/sunrpc/clnt.h>
  #include "netns.h"
  
  static struct dentry *topdir;
  static struct dentry *rpc_clnt_dir;
388f0c776   Jeff Layton   sunrpc: add a deb...
15
  static struct dentry *rpc_xprt_dir;
b4b9d2ccf   Jeff Layton   sunrpc: add debug...
16

4a0682583   Chuck Lever   SUNRPC: Transport...
17
  unsigned int rpc_inject_disconnect;
b4b9d2ccf   Jeff Layton   sunrpc: add debug...
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
  static int
  tasks_show(struct seq_file *f, void *v)
  {
  	u32 xid = 0;
  	struct rpc_task *task = v;
  	struct rpc_clnt *clnt = task->tk_client;
  	const char *rpc_waitq = "none";
  
  	if (RPC_IS_QUEUED(task))
  		rpc_waitq = rpc_qname(task->tk_waitqueue);
  
  	if (task->tk_rqstp)
  		xid = be32_to_cpu(task->tk_rqstp->rq_xid);
  
  	seq_printf(f, "%5u %04x %6d 0x%x 0x%x %8ld %ps %sv%u %s a:%ps q:%s
  ",
  		task->tk_pid, task->tk_flags, task->tk_status,
5efd1876e   Trond Myklebust   SUNRPC: Fix up tr...
35
  		clnt->cl_clid, xid, rpc_task_timeout(task), task->tk_ops,
b4b9d2ccf   Jeff Layton   sunrpc: add debug...
36
37
38
39
40
41
42
43
44
  		clnt->cl_program->name, clnt->cl_vers, rpc_proc_name(task),
  		task->tk_action, rpc_waitq);
  	return 0;
  }
  
  static void *
  tasks_start(struct seq_file *f, loff_t *ppos)
  	__acquires(&clnt->cl_lock)
  {
3f373e81b   Kinglong Mee   sunrpc: record rp...
45
  	struct rpc_clnt *clnt = f->private;
b4b9d2ccf   Jeff Layton   sunrpc: add debug...
46
  	loff_t pos = *ppos;
b4b9d2ccf   Jeff Layton   sunrpc: add debug...
47
  	struct rpc_task *task;
b4b9d2ccf   Jeff Layton   sunrpc: add debug...
48
49
50
51
52
53
54
55
56
57
  	spin_lock(&clnt->cl_lock);
  	list_for_each_entry(task, &clnt->cl_tasks, tk_task)
  		if (pos-- == 0)
  			return task;
  	return NULL;
  }
  
  static void *
  tasks_next(struct seq_file *f, void *v, loff_t *pos)
  {
3f373e81b   Kinglong Mee   sunrpc: record rp...
58
  	struct rpc_clnt *clnt = f->private;
b4b9d2ccf   Jeff Layton   sunrpc: add debug...
59
60
  	struct rpc_task *task = v;
  	struct list_head *next = task->tk_task.next;
b4b9d2ccf   Jeff Layton   sunrpc: add debug...
61
62
63
64
65
66
67
68
69
70
71
72
  	++*pos;
  
  	/* If there's another task on list, return it */
  	if (next == &clnt->cl_tasks)
  		return NULL;
  	return list_entry(next, struct rpc_task, tk_task);
  }
  
  static void
  tasks_stop(struct seq_file *f, void *v)
  	__releases(&clnt->cl_lock)
  {
3f373e81b   Kinglong Mee   sunrpc: record rp...
73
  	struct rpc_clnt *clnt = f->private;
b4b9d2ccf   Jeff Layton   sunrpc: add debug...
74
75
76
77
78
79
80
81
82
83
84
85
  	spin_unlock(&clnt->cl_lock);
  }
  
  static const struct seq_operations tasks_seq_operations = {
  	.start	= tasks_start,
  	.next	= tasks_next,
  	.stop	= tasks_stop,
  	.show	= tasks_show,
  };
  
  static int tasks_open(struct inode *inode, struct file *filp)
  {
3f373e81b   Kinglong Mee   sunrpc: record rp...
86
  	int ret = seq_open(filp, &tasks_seq_operations);
b4b9d2ccf   Jeff Layton   sunrpc: add debug...
87
88
  	if (!ret) {
  		struct seq_file *seq = filp->private_data;
3f373e81b   Kinglong Mee   sunrpc: record rp...
89
  		struct rpc_clnt *clnt = seq->private = inode->i_private;
b4b9d2ccf   Jeff Layton   sunrpc: add debug...
90

3f373e81b   Kinglong Mee   sunrpc: record rp...
91
92
  		if (!atomic_inc_not_zero(&clnt->cl_count)) {
  			seq_release(inode, filp);
b4b9d2ccf   Jeff Layton   sunrpc: add debug...
93
94
95
96
97
98
99
100
101
102
103
  			ret = -EINVAL;
  		}
  	}
  
  	return ret;
  }
  
  static int
  tasks_release(struct inode *inode, struct file *filp)
  {
  	struct seq_file *seq = filp->private_data;
3f373e81b   Kinglong Mee   sunrpc: record rp...
104
  	struct rpc_clnt *clnt = seq->private;
b4b9d2ccf   Jeff Layton   sunrpc: add debug...
105

3f373e81b   Kinglong Mee   sunrpc: record rp...
106
107
  	rpc_release_client(clnt);
  	return seq_release(inode, filp);
b4b9d2ccf   Jeff Layton   sunrpc: add debug...
108
109
110
111
112
113
114
115
116
  }
  
  static const struct file_operations tasks_fops = {
  	.owner		= THIS_MODULE,
  	.open		= tasks_open,
  	.read		= seq_read,
  	.llseek		= seq_lseek,
  	.release	= tasks_release,
  };
2f34b8bfa   NeilBrown   SUNRPC: add links...
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
  static int do_xprt_debugfs(struct rpc_clnt *clnt, struct rpc_xprt *xprt, void *numv)
  {
  	int len;
  	char name[24]; /* enough for "../../rpc_xprt/ + 8 hex digits + NULL */
  	char link[9]; /* enough for 8 hex digits + NULL */
  	int *nump = numv;
  
  	if (IS_ERR_OR_NULL(xprt->debugfs))
  		return 0;
  	len = snprintf(name, sizeof(name), "../../rpc_xprt/%s",
  		       xprt->debugfs->d_name.name);
  	if (len > sizeof(name))
  		return -1;
  	if (*nump == 0)
  		strcpy(link, "xprt");
  	else {
  		len = snprintf(link, sizeof(link), "xprt%d", *nump);
  		if (len > sizeof(link))
  			return -1;
  	}
6860c981b   Linus Torvalds   Merge tag 'nfs-fo...
137
  	debugfs_create_symlink(link, clnt->cl_debugfs, name);
2f34b8bfa   NeilBrown   SUNRPC: add links...
138
139
140
  	(*nump)++;
  	return 0;
  }
f9c72d10d   Jeff Layton   sunrpc: make debu...
141
  void
b4b9d2ccf   Jeff Layton   sunrpc: add debug...
142
143
  rpc_clnt_debugfs_register(struct rpc_clnt *clnt)
  {
f9c72d10d   Jeff Layton   sunrpc: make debu...
144
  	int len;
2f34b8bfa   NeilBrown   SUNRPC: add links...
145
146
  	char name[9]; /* enough for 8 hex digits + NULL */
  	int xprtnum = 0;
b4b9d2ccf   Jeff Layton   sunrpc: add debug...
147

b4b9d2ccf   Jeff Layton   sunrpc: add debug...
148
149
  	len = snprintf(name, sizeof(name), "%x", clnt->cl_clid);
  	if (len >= sizeof(name))
f9c72d10d   Jeff Layton   sunrpc: make debu...
150
  		return;
b4b9d2ccf   Jeff Layton   sunrpc: add debug...
151
152
153
  
  	/* make the per-client dir */
  	clnt->cl_debugfs = debugfs_create_dir(name, rpc_clnt_dir);
b4b9d2ccf   Jeff Layton   sunrpc: add debug...
154
155
  
  	/* make tasks file */
0a0762c6c   Greg Kroah-Hartman   sunrpc: no need t...
156
157
  	debugfs_create_file("tasks", S_IFREG | 0400, clnt->cl_debugfs, clnt,
  			    &tasks_fops);
388f0c776   Jeff Layton   sunrpc: add a deb...
158

6860c981b   Linus Torvalds   Merge tag 'nfs-fo...
159
  	rpc_clnt_iterate_for_each_xprt(clnt, do_xprt_debugfs, &xprtnum);
b4b9d2ccf   Jeff Layton   sunrpc: add debug...
160
161
162
163
164
165
166
167
  }
  
  void
  rpc_clnt_debugfs_unregister(struct rpc_clnt *clnt)
  {
  	debugfs_remove_recursive(clnt->cl_debugfs);
  	clnt->cl_debugfs = NULL;
  }
388f0c776   Jeff Layton   sunrpc: add a deb...
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
  static int
  xprt_info_show(struct seq_file *f, void *v)
  {
  	struct rpc_xprt *xprt = f->private;
  
  	seq_printf(f, "netid: %s
  ", xprt->address_strings[RPC_DISPLAY_NETID]);
  	seq_printf(f, "addr:  %s
  ", xprt->address_strings[RPC_DISPLAY_ADDR]);
  	seq_printf(f, "port:  %s
  ", xprt->address_strings[RPC_DISPLAY_PORT]);
  	seq_printf(f, "state: 0x%lx
  ", xprt->state);
  	return 0;
  }
  
  static int
  xprt_info_open(struct inode *inode, struct file *filp)
  {
  	int ret;
  	struct rpc_xprt *xprt = inode->i_private;
  
  	ret = single_open(filp, xprt_info_show, xprt);
  
  	if (!ret) {
  		if (!xprt_get(xprt)) {
  			single_release(inode, filp);
  			ret = -EINVAL;
  		}
  	}
  	return ret;
  }
  
  static int
  xprt_info_release(struct inode *inode, struct file *filp)
  {
  	struct rpc_xprt *xprt = inode->i_private;
  
  	xprt_put(xprt);
  	return single_release(inode, filp);
  }
  
  static const struct file_operations xprt_info_fops = {
  	.owner		= THIS_MODULE,
  	.open		= xprt_info_open,
  	.read		= seq_read,
  	.llseek		= seq_lseek,
  	.release	= xprt_info_release,
  };
f9c72d10d   Jeff Layton   sunrpc: make debu...
217
  void
388f0c776   Jeff Layton   sunrpc: add a deb...
218
219
220
221
222
223
224
225
226
227
  rpc_xprt_debugfs_register(struct rpc_xprt *xprt)
  {
  	int len, id;
  	static atomic_t	cur_id;
  	char		name[9]; /* 8 hex digits + NULL term */
  
  	id = (unsigned int)atomic_inc_return(&cur_id);
  
  	len = snprintf(name, sizeof(name), "%x", id);
  	if (len >= sizeof(name))
f9c72d10d   Jeff Layton   sunrpc: make debu...
228
  		return;
388f0c776   Jeff Layton   sunrpc: add a deb...
229
230
231
  
  	/* make the per-client dir */
  	xprt->debugfs = debugfs_create_dir(name, rpc_xprt_dir);
388f0c776   Jeff Layton   sunrpc: add a deb...
232
233
  
  	/* make tasks file */
0a0762c6c   Greg Kroah-Hartman   sunrpc: no need t...
234
235
  	debugfs_create_file("info", S_IFREG | 0400, xprt->debugfs, xprt,
  			    &xprt_info_fops);
4a0682583   Chuck Lever   SUNRPC: Transport...
236
237
  
  	atomic_set(&xprt->inject_disconnect, rpc_inject_disconnect);
388f0c776   Jeff Layton   sunrpc: add a deb...
238
239
240
241
242
243
244
245
  }
  
  void
  rpc_xprt_debugfs_unregister(struct rpc_xprt *xprt)
  {
  	debugfs_remove_recursive(xprt->debugfs);
  	xprt->debugfs = NULL;
  }
4a0682583   Chuck Lever   SUNRPC: Transport...
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
  static int
  fault_open(struct inode *inode, struct file *filp)
  {
  	filp->private_data = kmalloc(128, GFP_KERNEL);
  	if (!filp->private_data)
  		return -ENOMEM;
  	return 0;
  }
  
  static int
  fault_release(struct inode *inode, struct file *filp)
  {
  	kfree(filp->private_data);
  	return 0;
  }
  
  static ssize_t
  fault_disconnect_read(struct file *filp, char __user *user_buf,
  		      size_t len, loff_t *offset)
  {
  	char *buffer = (char *)filp->private_data;
  	size_t size;
  
  	size = sprintf(buffer, "%u
  ", rpc_inject_disconnect);
  	return simple_read_from_buffer(user_buf, len, offset, buffer, size);
  }
  
  static ssize_t
  fault_disconnect_write(struct file *filp, const char __user *user_buf,
  		       size_t len, loff_t *offset)
  {
  	char buffer[16];
5fd23f7e1   Chuck Lever   SUNRPC: Address k...
279
280
  	if (len >= sizeof(buffer))
  		len = sizeof(buffer) - 1;
4a0682583   Chuck Lever   SUNRPC: Transport...
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
  	if (copy_from_user(buffer, user_buf, len))
  		return -EFAULT;
  	buffer[len] = '\0';
  	if (kstrtouint(buffer, 10, &rpc_inject_disconnect))
  		return -EINVAL;
  	return len;
  }
  
  static const struct file_operations fault_disconnect_fops = {
  	.owner		= THIS_MODULE,
  	.open		= fault_open,
  	.read		= fault_disconnect_read,
  	.write		= fault_disconnect_write,
  	.release	= fault_release,
  };
b4b9d2ccf   Jeff Layton   sunrpc: add debug...
296
297
298
299
  void __exit
  sunrpc_debugfs_exit(void)
  {
  	debugfs_remove_recursive(topdir);
f9c72d10d   Jeff Layton   sunrpc: make debu...
300
301
302
  	topdir = NULL;
  	rpc_clnt_dir = NULL;
  	rpc_xprt_dir = NULL;
b4b9d2ccf   Jeff Layton   sunrpc: add debug...
303
  }
f9c72d10d   Jeff Layton   sunrpc: make debu...
304
  void __init
b4b9d2ccf   Jeff Layton   sunrpc: add debug...
305
306
  sunrpc_debugfs_init(void)
  {
0a0762c6c   Greg Kroah-Hartman   sunrpc: no need t...
307
  	struct dentry *rpc_fault_dir;
b4b9d2ccf   Jeff Layton   sunrpc: add debug...
308

0a0762c6c   Greg Kroah-Hartman   sunrpc: no need t...
309
  	topdir = debugfs_create_dir("sunrpc", NULL);
4a0682583   Chuck Lever   SUNRPC: Transport...
310

b4b9d2ccf   Jeff Layton   sunrpc: add debug...
311
  	rpc_clnt_dir = debugfs_create_dir("rpc_clnt", topdir);
b4b9d2ccf   Jeff Layton   sunrpc: add debug...
312

388f0c776   Jeff Layton   sunrpc: add a deb...
313
  	rpc_xprt_dir = debugfs_create_dir("rpc_xprt", topdir);
388f0c776   Jeff Layton   sunrpc: add a deb...
314

0a0762c6c   Greg Kroah-Hartman   sunrpc: no need t...
315
316
317
318
  	rpc_fault_dir = debugfs_create_dir("inject_fault", topdir);
  
  	debugfs_create_file("disconnect", S_IFREG | 0400, rpc_fault_dir, NULL,
  			    &fault_disconnect_fops);
b4b9d2ccf   Jeff Layton   sunrpc: add debug...
319
  }