xref: /linux/net/sunrpc/sysfs.c (revision 4a09651a)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2020 Anna Schumaker <Anna.Schumaker@Netapp.com>
4  */
5 #include <linux/sunrpc/clnt.h>
6 #include <linux/kobject.h>
7 #include <linux/sunrpc/addr.h>
8 
9 #include "sysfs.h"
10 
11 struct xprt_addr {
12 	const char *addr;
13 	struct rcu_head rcu;
14 };
15 
16 static void free_xprt_addr(struct rcu_head *head)
17 {
18 	struct xprt_addr *addr = container_of(head, struct xprt_addr, rcu);
19 
20 	kfree(addr->addr);
21 	kfree(addr);
22 }
23 
24 static struct kset *rpc_sunrpc_kset;
25 static struct kobject *rpc_sunrpc_client_kobj, *rpc_sunrpc_xprt_switch_kobj;
26 
27 static void rpc_sysfs_object_release(struct kobject *kobj)
28 {
29 	kfree(kobj);
30 }
31 
32 static const struct kobj_ns_type_operations *
33 rpc_sysfs_object_child_ns_type(struct kobject *kobj)
34 {
35 	return &net_ns_type_operations;
36 }
37 
38 static struct kobj_type rpc_sysfs_object_type = {
39 	.release = rpc_sysfs_object_release,
40 	.sysfs_ops = &kobj_sysfs_ops,
41 	.child_ns_type = rpc_sysfs_object_child_ns_type,
42 };
43 
44 static struct kobject *rpc_sysfs_object_alloc(const char *name,
45 					      struct kset *kset,
46 					      struct kobject *parent)
47 {
48 	struct kobject *kobj;
49 
50 	kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
51 	if (kobj) {
52 		kobj->kset = kset;
53 		if (kobject_init_and_add(kobj, &rpc_sysfs_object_type,
54 					 parent, "%s", name) == 0)
55 			return kobj;
56 		kobject_put(kobj);
57 	}
58 	return NULL;
59 }
60 
61 static inline struct rpc_xprt *
62 rpc_sysfs_xprt_kobj_get_xprt(struct kobject *kobj)
63 {
64 	struct rpc_sysfs_xprt *x = container_of(kobj,
65 		struct rpc_sysfs_xprt, kobject);
66 
67 	return xprt_get(x->xprt);
68 }
69 
70 static ssize_t rpc_sysfs_xprt_dstaddr_show(struct kobject *kobj,
71 					   struct kobj_attribute *attr,
72 					   char *buf)
73 {
74 	struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
75 	ssize_t ret;
76 
77 	if (!xprt)
78 		return 0;
79 	ret = sprintf(buf, "%s\n", xprt->address_strings[RPC_DISPLAY_ADDR]);
80 	xprt_put(xprt);
81 	return ret + 1;
82 }
83 
84 static ssize_t rpc_sysfs_xprt_info_show(struct kobject *kobj,
85 					struct kobj_attribute *attr,
86 					char *buf)
87 {
88 	struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
89 	ssize_t ret;
90 
91 	if (!xprt)
92 		return 0;
93 
94 	ret = sprintf(buf, "last_used=%lu\ncur_cong=%lu\ncong_win=%lu\n"
95 		       "max_num_slots=%u\nmin_num_slots=%u\nnum_reqs=%u\n"
96 		       "binding_q_len=%u\nsending_q_len=%u\npending_q_len=%u\n"
97 		       "backlog_q_len=%u\n", xprt->last_used, xprt->cong,
98 		       xprt->cwnd, xprt->max_reqs, xprt->min_reqs,
99 		       xprt->num_reqs, xprt->binding.qlen, xprt->sending.qlen,
100 		       xprt->pending.qlen, xprt->backlog.qlen);
101 	xprt_put(xprt);
102 	return ret + 1;
103 }
104 
105 static ssize_t rpc_sysfs_xprt_dstaddr_store(struct kobject *kobj,
106 					    struct kobj_attribute *attr,
107 					    const char *buf, size_t count)
108 {
109 	struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
110 	struct sockaddr *saddr;
111 	char *dst_addr;
112 	int port;
113 	struct xprt_addr *saved_addr;
114 	size_t buf_len;
115 
116 	if (!xprt)
117 		return 0;
118 	if (!(xprt->xprt_class->ident == XPRT_TRANSPORT_TCP ||
119 	      xprt->xprt_class->ident == XPRT_TRANSPORT_RDMA)) {
120 		xprt_put(xprt);
121 		return -EOPNOTSUPP;
122 	}
123 
124 	if (wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_KILLABLE)) {
125 		count = -EINTR;
126 		goto out_put;
127 	}
128 	saddr = (struct sockaddr *)&xprt->addr;
129 	port = rpc_get_port(saddr);
130 
131 	/* buf_len is the len until the first occurence of either
132 	 * '\n' or '\0'
133 	 */
134 	buf_len = strcspn(buf, "\n");
135 
136 	dst_addr = kstrndup(buf, buf_len, GFP_KERNEL);
137 	if (!dst_addr)
138 		goto out_err;
139 	saved_addr = kzalloc(sizeof(*saved_addr), GFP_KERNEL);
140 	if (!saved_addr)
141 		goto out_err_free;
142 	saved_addr->addr =
143 		rcu_dereference_raw(xprt->address_strings[RPC_DISPLAY_ADDR]);
144 	rcu_assign_pointer(xprt->address_strings[RPC_DISPLAY_ADDR], dst_addr);
145 	call_rcu(&saved_addr->rcu, free_xprt_addr);
146 	xprt->addrlen = rpc_pton(xprt->xprt_net, buf, buf_len, saddr,
147 				 sizeof(*saddr));
148 	rpc_set_port(saddr, port);
149 
150 	xprt_force_disconnect(xprt);
151 out:
152 	xprt_release_write(xprt, NULL);
153 out_put:
154 	xprt_put(xprt);
155 	return count;
156 out_err_free:
157 	kfree(dst_addr);
158 out_err:
159 	count = -ENOMEM;
160 	goto out;
161 }
162 
163 int rpc_sysfs_init(void)
164 {
165 	rpc_sunrpc_kset = kset_create_and_add("sunrpc", NULL, kernel_kobj);
166 	if (!rpc_sunrpc_kset)
167 		return -ENOMEM;
168 	rpc_sunrpc_client_kobj =
169 		rpc_sysfs_object_alloc("rpc-clients", rpc_sunrpc_kset, NULL);
170 	if (!rpc_sunrpc_client_kobj)
171 		goto err_client;
172 	rpc_sunrpc_xprt_switch_kobj =
173 		rpc_sysfs_object_alloc("xprt-switches", rpc_sunrpc_kset, NULL);
174 	if (!rpc_sunrpc_xprt_switch_kobj)
175 		goto err_switch;
176 	return 0;
177 err_switch:
178 	kobject_put(rpc_sunrpc_client_kobj);
179 	rpc_sunrpc_client_kobj = NULL;
180 err_client:
181 	kset_unregister(rpc_sunrpc_kset);
182 	rpc_sunrpc_kset = NULL;
183 	return -ENOMEM;
184 }
185 
186 static void rpc_sysfs_client_release(struct kobject *kobj)
187 {
188 	struct rpc_sysfs_client *c;
189 
190 	c = container_of(kobj, struct rpc_sysfs_client, kobject);
191 	kfree(c);
192 }
193 
194 static void rpc_sysfs_xprt_switch_release(struct kobject *kobj)
195 {
196 	struct rpc_sysfs_xprt_switch *xprt_switch;
197 
198 	xprt_switch = container_of(kobj, struct rpc_sysfs_xprt_switch, kobject);
199 	kfree(xprt_switch);
200 }
201 
202 static void rpc_sysfs_xprt_release(struct kobject *kobj)
203 {
204 	struct rpc_sysfs_xprt *xprt;
205 
206 	xprt = container_of(kobj, struct rpc_sysfs_xprt, kobject);
207 	kfree(xprt);
208 }
209 
210 static const void *rpc_sysfs_client_namespace(struct kobject *kobj)
211 {
212 	return container_of(kobj, struct rpc_sysfs_client, kobject)->net;
213 }
214 
215 static const void *rpc_sysfs_xprt_switch_namespace(struct kobject *kobj)
216 {
217 	return container_of(kobj, struct rpc_sysfs_xprt_switch, kobject)->net;
218 }
219 
220 static const void *rpc_sysfs_xprt_namespace(struct kobject *kobj)
221 {
222 	return container_of(kobj, struct rpc_sysfs_xprt,
223 			    kobject)->xprt->xprt_net;
224 }
225 
226 static struct kobj_attribute rpc_sysfs_xprt_dstaddr = __ATTR(dstaddr,
227 	0644, rpc_sysfs_xprt_dstaddr_show, rpc_sysfs_xprt_dstaddr_store);
228 
229 static struct kobj_attribute rpc_sysfs_xprt_info = __ATTR(xprt_info,
230 	0444, rpc_sysfs_xprt_info_show, NULL);
231 
232 static struct attribute *rpc_sysfs_xprt_attrs[] = {
233 	&rpc_sysfs_xprt_dstaddr.attr,
234 	&rpc_sysfs_xprt_info.attr,
235 	NULL,
236 };
237 
238 static struct kobj_type rpc_sysfs_client_type = {
239 	.release = rpc_sysfs_client_release,
240 	.sysfs_ops = &kobj_sysfs_ops,
241 	.namespace = rpc_sysfs_client_namespace,
242 };
243 
244 static struct kobj_type rpc_sysfs_xprt_switch_type = {
245 	.release = rpc_sysfs_xprt_switch_release,
246 	.sysfs_ops = &kobj_sysfs_ops,
247 	.namespace = rpc_sysfs_xprt_switch_namespace,
248 };
249 
250 static struct kobj_type rpc_sysfs_xprt_type = {
251 	.release = rpc_sysfs_xprt_release,
252 	.default_attrs = rpc_sysfs_xprt_attrs,
253 	.sysfs_ops = &kobj_sysfs_ops,
254 	.namespace = rpc_sysfs_xprt_namespace,
255 };
256 
257 void rpc_sysfs_exit(void)
258 {
259 	kobject_put(rpc_sunrpc_client_kobj);
260 	kobject_put(rpc_sunrpc_xprt_switch_kobj);
261 	kset_unregister(rpc_sunrpc_kset);
262 }
263 
264 static struct rpc_sysfs_client *rpc_sysfs_client_alloc(struct kobject *parent,
265 						       struct net *net,
266 						       int clid)
267 {
268 	struct rpc_sysfs_client *p;
269 
270 	p = kzalloc(sizeof(*p), GFP_KERNEL);
271 	if (p) {
272 		p->net = net;
273 		p->kobject.kset = rpc_sunrpc_kset;
274 		if (kobject_init_and_add(&p->kobject, &rpc_sysfs_client_type,
275 					 parent, "clnt-%d", clid) == 0)
276 			return p;
277 		kobject_put(&p->kobject);
278 	}
279 	return NULL;
280 }
281 
282 static struct rpc_sysfs_xprt_switch *
283 rpc_sysfs_xprt_switch_alloc(struct kobject *parent,
284 			    struct rpc_xprt_switch *xprt_switch,
285 			    struct net *net,
286 			    gfp_t gfp_flags)
287 {
288 	struct rpc_sysfs_xprt_switch *p;
289 
290 	p = kzalloc(sizeof(*p), gfp_flags);
291 	if (p) {
292 		p->net = net;
293 		p->kobject.kset = rpc_sunrpc_kset;
294 		if (kobject_init_and_add(&p->kobject,
295 					 &rpc_sysfs_xprt_switch_type,
296 					 parent, "switch-%d",
297 					 xprt_switch->xps_id) == 0)
298 			return p;
299 		kobject_put(&p->kobject);
300 	}
301 	return NULL;
302 }
303 
304 static struct rpc_sysfs_xprt *rpc_sysfs_xprt_alloc(struct kobject *parent,
305 						   struct rpc_xprt *xprt,
306 						   gfp_t gfp_flags)
307 {
308 	struct rpc_sysfs_xprt *p;
309 
310 	p = kzalloc(sizeof(*p), gfp_flags);
311 	if (!p)
312 		goto out;
313 	p->kobject.kset = rpc_sunrpc_kset;
314 	if (kobject_init_and_add(&p->kobject, &rpc_sysfs_xprt_type,
315 				 parent, "xprt-%d-%s", xprt->id,
316 				 xprt->address_strings[RPC_DISPLAY_PROTO]) == 0)
317 		return p;
318 	kobject_put(&p->kobject);
319 out:
320 	return NULL;
321 }
322 
323 void rpc_sysfs_client_setup(struct rpc_clnt *clnt,
324 			    struct rpc_xprt_switch *xprt_switch,
325 			    struct net *net)
326 {
327 	struct rpc_sysfs_client *rpc_client;
328 
329 	rpc_client = rpc_sysfs_client_alloc(rpc_sunrpc_client_kobj,
330 					    net, clnt->cl_clid);
331 	if (rpc_client) {
332 		char name[] = "switch";
333 		struct rpc_sysfs_xprt_switch *xswitch =
334 			(struct rpc_sysfs_xprt_switch *)xprt_switch->xps_sysfs;
335 		int ret;
336 
337 		clnt->cl_sysfs = rpc_client;
338 		rpc_client->clnt = clnt;
339 		rpc_client->xprt_switch = xprt_switch;
340 		kobject_uevent(&rpc_client->kobject, KOBJ_ADD);
341 		ret = sysfs_create_link_nowarn(&rpc_client->kobject,
342 					       &xswitch->kobject, name);
343 		if (ret)
344 			pr_warn("can't create link to %s in sysfs (%d)\n",
345 				name, ret);
346 	}
347 }
348 
349 void rpc_sysfs_xprt_switch_setup(struct rpc_xprt_switch *xprt_switch,
350 				 struct rpc_xprt *xprt,
351 				 gfp_t gfp_flags)
352 {
353 	struct rpc_sysfs_xprt_switch *rpc_xprt_switch;
354 	struct net *net;
355 
356 	if (xprt_switch->xps_net)
357 		net = xprt_switch->xps_net;
358 	else
359 		net = xprt->xprt_net;
360 	rpc_xprt_switch =
361 		rpc_sysfs_xprt_switch_alloc(rpc_sunrpc_xprt_switch_kobj,
362 					    xprt_switch, net, gfp_flags);
363 	if (rpc_xprt_switch) {
364 		xprt_switch->xps_sysfs = rpc_xprt_switch;
365 		rpc_xprt_switch->xprt_switch = xprt_switch;
366 		rpc_xprt_switch->xprt = xprt;
367 		kobject_uevent(&rpc_xprt_switch->kobject, KOBJ_ADD);
368 	}
369 }
370 
371 void rpc_sysfs_xprt_setup(struct rpc_xprt_switch *xprt_switch,
372 			  struct rpc_xprt *xprt,
373 			  gfp_t gfp_flags)
374 {
375 	struct rpc_sysfs_xprt *rpc_xprt;
376 	struct rpc_sysfs_xprt_switch *switch_obj =
377 		(struct rpc_sysfs_xprt_switch *)xprt_switch->xps_sysfs;
378 
379 	rpc_xprt = rpc_sysfs_xprt_alloc(&switch_obj->kobject, xprt, gfp_flags);
380 	if (rpc_xprt) {
381 		xprt->xprt_sysfs = rpc_xprt;
382 		rpc_xprt->xprt = xprt;
383 		kobject_uevent(&rpc_xprt->kobject, KOBJ_ADD);
384 	}
385 }
386 
387 void rpc_sysfs_client_destroy(struct rpc_clnt *clnt)
388 {
389 	struct rpc_sysfs_client *rpc_client = clnt->cl_sysfs;
390 
391 	if (rpc_client) {
392 		char name[] = "switch";
393 
394 		sysfs_remove_link(&rpc_client->kobject, name);
395 		kobject_uevent(&rpc_client->kobject, KOBJ_REMOVE);
396 		kobject_del(&rpc_client->kobject);
397 		kobject_put(&rpc_client->kobject);
398 		clnt->cl_sysfs = NULL;
399 	}
400 }
401 
402 void rpc_sysfs_xprt_switch_destroy(struct rpc_xprt_switch *xprt_switch)
403 {
404 	struct rpc_sysfs_xprt_switch *rpc_xprt_switch = xprt_switch->xps_sysfs;
405 
406 	if (rpc_xprt_switch) {
407 		kobject_uevent(&rpc_xprt_switch->kobject, KOBJ_REMOVE);
408 		kobject_del(&rpc_xprt_switch->kobject);
409 		kobject_put(&rpc_xprt_switch->kobject);
410 		xprt_switch->xps_sysfs = NULL;
411 	}
412 }
413 
414 void rpc_sysfs_xprt_destroy(struct rpc_xprt *xprt)
415 {
416 	struct rpc_sysfs_xprt *rpc_xprt = xprt->xprt_sysfs;
417 
418 	if (rpc_xprt) {
419 		kobject_uevent(&rpc_xprt->kobject, KOBJ_REMOVE);
420 		kobject_del(&rpc_xprt->kobject);
421 		kobject_put(&rpc_xprt->kobject);
422 		xprt->xprt_sysfs = NULL;
423 	}
424 }
425