diff options
author | Jeff Layton <jlayton@primarydata.com> | 2014-11-26 14:44:44 -0500 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@primarydata.com> | 2014-11-27 13:14:52 -0500 |
commit | 388f0c776781fe64ce951701bfe712b2182a31f2 (patch) | |
tree | 535e64ee7e52c96a16f80c2d71f2310d6f796b2b /net/sunrpc/debugfs.c | |
parent | b4b9d2ccf0be61c69213f6ae4e33377c05194ef4 (diff) |
sunrpc: add a debugfs rpc_xprt directory with an info file in it
Add a new directory heirarchy under the debugfs sunrpc/ directory:
sunrpc/
rpc_xprt/
<xprt id>/
Within that directory, we can put files that give info about the
xprts. We do have the (minor) problem that there is no succinct,
unique identifier for rpc_xprts. So we generate them synthetically
with a static atomic_t counter.
For now, this directory just holds an "info" file, but we may add
other files to it in the future.
Signed-off-by: Jeff Layton <jlayton@primarydata.com>
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Diffstat (limited to 'net/sunrpc/debugfs.c')
-rw-r--r-- | net/sunrpc/debugfs.c | 115 |
1 files changed, 108 insertions, 7 deletions
diff --git a/net/sunrpc/debugfs.c b/net/sunrpc/debugfs.c index 3d7745683ca3..e811f390f9f6 100644 --- a/net/sunrpc/debugfs.c +++ b/net/sunrpc/debugfs.c | |||
@@ -11,6 +11,7 @@ | |||
11 | 11 | ||
12 | static struct dentry *topdir; | 12 | static struct dentry *topdir; |
13 | static struct dentry *rpc_clnt_dir; | 13 | static struct dentry *rpc_clnt_dir; |
14 | static struct dentry *rpc_xprt_dir; | ||
14 | 15 | ||
15 | struct rpc_clnt_iter { | 16 | struct rpc_clnt_iter { |
16 | struct rpc_clnt *clnt; | 17 | struct rpc_clnt *clnt; |
@@ -131,8 +132,8 @@ static const struct file_operations tasks_fops = { | |||
131 | int | 132 | int |
132 | rpc_clnt_debugfs_register(struct rpc_clnt *clnt) | 133 | rpc_clnt_debugfs_register(struct rpc_clnt *clnt) |
133 | { | 134 | { |
134 | int len; | 135 | int len, err; |
135 | char name[9]; /* 8 for hex digits + NULL terminator */ | 136 | char name[24]; /* enough for "../../rpc_xprt/ + 8 hex digits + NULL */ |
136 | 137 | ||
137 | /* Already registered? */ | 138 | /* Already registered? */ |
138 | if (clnt->cl_debugfs) | 139 | if (clnt->cl_debugfs) |
@@ -148,14 +149,28 @@ rpc_clnt_debugfs_register(struct rpc_clnt *clnt) | |||
148 | return -ENOMEM; | 149 | return -ENOMEM; |
149 | 150 | ||
150 | /* make tasks file */ | 151 | /* make tasks file */ |
152 | err = -ENOMEM; | ||
151 | if (!debugfs_create_file("tasks", S_IFREG | S_IRUSR, clnt->cl_debugfs, | 153 | if (!debugfs_create_file("tasks", S_IFREG | S_IRUSR, clnt->cl_debugfs, |
152 | clnt, &tasks_fops)) { | 154 | clnt, &tasks_fops)) |
153 | debugfs_remove_recursive(clnt->cl_debugfs); | 155 | goto out_err; |
154 | clnt->cl_debugfs = NULL; | 156 | |
155 | return -ENOMEM; | 157 | err = -EINVAL; |
156 | } | 158 | rcu_read_lock(); |
159 | len = snprintf(name, sizeof(name), "../../rpc_xprt/%s", | ||
160 | rcu_dereference(clnt->cl_xprt)->debugfs->d_name.name); | ||
161 | rcu_read_unlock(); | ||
162 | if (len >= sizeof(name)) | ||
163 | goto out_err; | ||
164 | |||
165 | err = -ENOMEM; | ||
166 | if (!debugfs_create_symlink("xprt", clnt->cl_debugfs, name)) | ||
167 | goto out_err; | ||
157 | 168 | ||
158 | return 0; | 169 | return 0; |
170 | out_err: | ||
171 | debugfs_remove_recursive(clnt->cl_debugfs); | ||
172 | clnt->cl_debugfs = NULL; | ||
173 | return err; | ||
159 | } | 174 | } |
160 | 175 | ||
161 | void | 176 | void |
@@ -165,6 +180,88 @@ rpc_clnt_debugfs_unregister(struct rpc_clnt *clnt) | |||
165 | clnt->cl_debugfs = NULL; | 180 | clnt->cl_debugfs = NULL; |
166 | } | 181 | } |
167 | 182 | ||
183 | static int | ||
184 | xprt_info_show(struct seq_file *f, void *v) | ||
185 | { | ||
186 | struct rpc_xprt *xprt = f->private; | ||
187 | |||
188 | seq_printf(f, "netid: %s\n", xprt->address_strings[RPC_DISPLAY_NETID]); | ||
189 | seq_printf(f, "addr: %s\n", xprt->address_strings[RPC_DISPLAY_ADDR]); | ||
190 | seq_printf(f, "port: %s\n", xprt->address_strings[RPC_DISPLAY_PORT]); | ||
191 | seq_printf(f, "state: 0x%lx\n", xprt->state); | ||
192 | return 0; | ||
193 | } | ||
194 | |||
195 | static int | ||
196 | xprt_info_open(struct inode *inode, struct file *filp) | ||
197 | { | ||
198 | int ret; | ||
199 | struct rpc_xprt *xprt = inode->i_private; | ||
200 | |||
201 | ret = single_open(filp, xprt_info_show, xprt); | ||
202 | |||
203 | if (!ret) { | ||
204 | if (!xprt_get(xprt)) { | ||
205 | single_release(inode, filp); | ||
206 | ret = -EINVAL; | ||
207 | } | ||
208 | } | ||
209 | return ret; | ||
210 | } | ||
211 | |||
212 | static int | ||
213 | xprt_info_release(struct inode *inode, struct file *filp) | ||
214 | { | ||
215 | struct rpc_xprt *xprt = inode->i_private; | ||
216 | |||
217 | xprt_put(xprt); | ||
218 | return single_release(inode, filp); | ||
219 | } | ||
220 | |||
221 | static const struct file_operations xprt_info_fops = { | ||
222 | .owner = THIS_MODULE, | ||
223 | .open = xprt_info_open, | ||
224 | .read = seq_read, | ||
225 | .llseek = seq_lseek, | ||
226 | .release = xprt_info_release, | ||
227 | }; | ||
228 | |||
229 | int | ||
230 | rpc_xprt_debugfs_register(struct rpc_xprt *xprt) | ||
231 | { | ||
232 | int len, id; | ||
233 | static atomic_t cur_id; | ||
234 | char name[9]; /* 8 hex digits + NULL term */ | ||
235 | |||
236 | id = (unsigned int)atomic_inc_return(&cur_id); | ||
237 | |||
238 | len = snprintf(name, sizeof(name), "%x", id); | ||
239 | if (len >= sizeof(name)) | ||
240 | return -EINVAL; | ||
241 | |||
242 | /* make the per-client dir */ | ||
243 | xprt->debugfs = debugfs_create_dir(name, rpc_xprt_dir); | ||
244 | if (!xprt->debugfs) | ||
245 | return -ENOMEM; | ||
246 | |||
247 | /* make tasks file */ | ||
248 | if (!debugfs_create_file("info", S_IFREG | S_IRUSR, xprt->debugfs, | ||
249 | xprt, &xprt_info_fops)) { | ||
250 | debugfs_remove_recursive(xprt->debugfs); | ||
251 | xprt->debugfs = NULL; | ||
252 | return -ENOMEM; | ||
253 | } | ||
254 | |||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | void | ||
259 | rpc_xprt_debugfs_unregister(struct rpc_xprt *xprt) | ||
260 | { | ||
261 | debugfs_remove_recursive(xprt->debugfs); | ||
262 | xprt->debugfs = NULL; | ||
263 | } | ||
264 | |||
168 | void __exit | 265 | void __exit |
169 | sunrpc_debugfs_exit(void) | 266 | sunrpc_debugfs_exit(void) |
170 | { | 267 | { |
@@ -182,6 +279,10 @@ sunrpc_debugfs_init(void) | |||
182 | if (!rpc_clnt_dir) | 279 | if (!rpc_clnt_dir) |
183 | goto out_remove; | 280 | goto out_remove; |
184 | 281 | ||
282 | rpc_xprt_dir = debugfs_create_dir("rpc_xprt", topdir); | ||
283 | if (!rpc_xprt_dir) | ||
284 | goto out_remove; | ||
285 | |||
185 | return 0; | 286 | return 0; |
186 | out_remove: | 287 | out_remove: |
187 | debugfs_remove_recursive(topdir); | 288 | debugfs_remove_recursive(topdir); |