OSDN Git Service

b3bc76bbc2a083649e57b6ab30c0bb337e8a09a6
[uclinux-h8/linux.git] / net / sunrpc / sysfs.c
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 inline struct rpc_xprt_switch *
71 rpc_sysfs_xprt_switch_kobj_get_xprt(struct kobject *kobj)
72 {
73         struct rpc_sysfs_xprt_switch *x = container_of(kobj,
74                 struct rpc_sysfs_xprt_switch, kobject);
75
76         return xprt_switch_get(x->xprt_switch);
77 }
78
79 static ssize_t rpc_sysfs_xprt_dstaddr_show(struct kobject *kobj,
80                                            struct kobj_attribute *attr,
81                                            char *buf)
82 {
83         struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
84         ssize_t ret;
85
86         if (!xprt)
87                 return 0;
88         ret = sprintf(buf, "%s\n", xprt->address_strings[RPC_DISPLAY_ADDR]);
89         xprt_put(xprt);
90         return ret + 1;
91 }
92
93 static ssize_t rpc_sysfs_xprt_info_show(struct kobject *kobj,
94                                         struct kobj_attribute *attr,
95                                         char *buf)
96 {
97         struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
98         ssize_t ret;
99
100         if (!xprt)
101                 return 0;
102
103         ret = sprintf(buf, "last_used=%lu\ncur_cong=%lu\ncong_win=%lu\n"
104                        "max_num_slots=%u\nmin_num_slots=%u\nnum_reqs=%u\n"
105                        "binding_q_len=%u\nsending_q_len=%u\npending_q_len=%u\n"
106                        "backlog_q_len=%u\n", xprt->last_used, xprt->cong,
107                        xprt->cwnd, xprt->max_reqs, xprt->min_reqs,
108                        xprt->num_reqs, xprt->binding.qlen, xprt->sending.qlen,
109                        xprt->pending.qlen, xprt->backlog.qlen);
110         xprt_put(xprt);
111         return ret + 1;
112 }
113
114 static ssize_t rpc_sysfs_xprt_switch_info_show(struct kobject *kobj,
115                                                struct kobj_attribute *attr,
116                                                char *buf)
117 {
118         struct rpc_xprt_switch *xprt_switch =
119                 rpc_sysfs_xprt_switch_kobj_get_xprt(kobj);
120         ssize_t ret;
121
122         if (!xprt_switch)
123                 return 0;
124         ret = sprintf(buf, "num_xprts=%u\nnum_active=%u\nqueue_len=%ld\n",
125                       xprt_switch->xps_nxprts, xprt_switch->xps_nactive,
126                       atomic_long_read(&xprt_switch->xps_queuelen));
127         xprt_switch_put(xprt_switch);
128         return ret + 1;
129 }
130
131 static ssize_t rpc_sysfs_xprt_dstaddr_store(struct kobject *kobj,
132                                             struct kobj_attribute *attr,
133                                             const char *buf, size_t count)
134 {
135         struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
136         struct sockaddr *saddr;
137         char *dst_addr;
138         int port;
139         struct xprt_addr *saved_addr;
140         size_t buf_len;
141
142         if (!xprt)
143                 return 0;
144         if (!(xprt->xprt_class->ident == XPRT_TRANSPORT_TCP ||
145               xprt->xprt_class->ident == XPRT_TRANSPORT_RDMA)) {
146                 xprt_put(xprt);
147                 return -EOPNOTSUPP;
148         }
149
150         if (wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_KILLABLE)) {
151                 count = -EINTR;
152                 goto out_put;
153         }
154         saddr = (struct sockaddr *)&xprt->addr;
155         port = rpc_get_port(saddr);
156
157         /* buf_len is the len until the first occurence of either
158          * '\n' or '\0'
159          */
160         buf_len = strcspn(buf, "\n");
161
162         dst_addr = kstrndup(buf, buf_len, GFP_KERNEL);
163         if (!dst_addr)
164                 goto out_err;
165         saved_addr = kzalloc(sizeof(*saved_addr), GFP_KERNEL);
166         if (!saved_addr)
167                 goto out_err_free;
168         saved_addr->addr =
169                 rcu_dereference_raw(xprt->address_strings[RPC_DISPLAY_ADDR]);
170         rcu_assign_pointer(xprt->address_strings[RPC_DISPLAY_ADDR], dst_addr);
171         call_rcu(&saved_addr->rcu, free_xprt_addr);
172         xprt->addrlen = rpc_pton(xprt->xprt_net, buf, buf_len, saddr,
173                                  sizeof(*saddr));
174         rpc_set_port(saddr, port);
175
176         xprt_force_disconnect(xprt);
177 out:
178         xprt_release_write(xprt, NULL);
179 out_put:
180         xprt_put(xprt);
181         return count;
182 out_err_free:
183         kfree(dst_addr);
184 out_err:
185         count = -ENOMEM;
186         goto out;
187 }
188
189 int rpc_sysfs_init(void)
190 {
191         rpc_sunrpc_kset = kset_create_and_add("sunrpc", NULL, kernel_kobj);
192         if (!rpc_sunrpc_kset)
193                 return -ENOMEM;
194         rpc_sunrpc_client_kobj =
195                 rpc_sysfs_object_alloc("rpc-clients", rpc_sunrpc_kset, NULL);
196         if (!rpc_sunrpc_client_kobj)
197                 goto err_client;
198         rpc_sunrpc_xprt_switch_kobj =
199                 rpc_sysfs_object_alloc("xprt-switches", rpc_sunrpc_kset, NULL);
200         if (!rpc_sunrpc_xprt_switch_kobj)
201                 goto err_switch;
202         return 0;
203 err_switch:
204         kobject_put(rpc_sunrpc_client_kobj);
205         rpc_sunrpc_client_kobj = NULL;
206 err_client:
207         kset_unregister(rpc_sunrpc_kset);
208         rpc_sunrpc_kset = NULL;
209         return -ENOMEM;
210 }
211
212 static void rpc_sysfs_client_release(struct kobject *kobj)
213 {
214         struct rpc_sysfs_client *c;
215
216         c = container_of(kobj, struct rpc_sysfs_client, kobject);
217         kfree(c);
218 }
219
220 static void rpc_sysfs_xprt_switch_release(struct kobject *kobj)
221 {
222         struct rpc_sysfs_xprt_switch *xprt_switch;
223
224         xprt_switch = container_of(kobj, struct rpc_sysfs_xprt_switch, kobject);
225         kfree(xprt_switch);
226 }
227
228 static void rpc_sysfs_xprt_release(struct kobject *kobj)
229 {
230         struct rpc_sysfs_xprt *xprt;
231
232         xprt = container_of(kobj, struct rpc_sysfs_xprt, kobject);
233         kfree(xprt);
234 }
235
236 static const void *rpc_sysfs_client_namespace(struct kobject *kobj)
237 {
238         return container_of(kobj, struct rpc_sysfs_client, kobject)->net;
239 }
240
241 static const void *rpc_sysfs_xprt_switch_namespace(struct kobject *kobj)
242 {
243         return container_of(kobj, struct rpc_sysfs_xprt_switch, kobject)->net;
244 }
245
246 static const void *rpc_sysfs_xprt_namespace(struct kobject *kobj)
247 {
248         return container_of(kobj, struct rpc_sysfs_xprt,
249                             kobject)->xprt->xprt_net;
250 }
251
252 static struct kobj_attribute rpc_sysfs_xprt_dstaddr = __ATTR(dstaddr,
253         0644, rpc_sysfs_xprt_dstaddr_show, rpc_sysfs_xprt_dstaddr_store);
254
255 static struct kobj_attribute rpc_sysfs_xprt_info = __ATTR(xprt_info,
256         0444, rpc_sysfs_xprt_info_show, NULL);
257
258 static struct attribute *rpc_sysfs_xprt_attrs[] = {
259         &rpc_sysfs_xprt_dstaddr.attr,
260         &rpc_sysfs_xprt_info.attr,
261         NULL,
262 };
263
264 static struct kobj_attribute rpc_sysfs_xprt_switch_info =
265         __ATTR(xprt_switch_info, 0444, rpc_sysfs_xprt_switch_info_show, NULL);
266
267 static struct attribute *rpc_sysfs_xprt_switch_attrs[] = {
268         &rpc_sysfs_xprt_switch_info.attr,
269         NULL,
270 };
271
272 static struct kobj_type rpc_sysfs_client_type = {
273         .release = rpc_sysfs_client_release,
274         .sysfs_ops = &kobj_sysfs_ops,
275         .namespace = rpc_sysfs_client_namespace,
276 };
277
278 static struct kobj_type rpc_sysfs_xprt_switch_type = {
279         .release = rpc_sysfs_xprt_switch_release,
280         .default_attrs = rpc_sysfs_xprt_switch_attrs,
281         .sysfs_ops = &kobj_sysfs_ops,
282         .namespace = rpc_sysfs_xprt_switch_namespace,
283 };
284
285 static struct kobj_type rpc_sysfs_xprt_type = {
286         .release = rpc_sysfs_xprt_release,
287         .default_attrs = rpc_sysfs_xprt_attrs,
288         .sysfs_ops = &kobj_sysfs_ops,
289         .namespace = rpc_sysfs_xprt_namespace,
290 };
291
292 void rpc_sysfs_exit(void)
293 {
294         kobject_put(rpc_sunrpc_client_kobj);
295         kobject_put(rpc_sunrpc_xprt_switch_kobj);
296         kset_unregister(rpc_sunrpc_kset);
297 }
298
299 static struct rpc_sysfs_client *rpc_sysfs_client_alloc(struct kobject *parent,
300                                                        struct net *net,
301                                                        int clid)
302 {
303         struct rpc_sysfs_client *p;
304
305         p = kzalloc(sizeof(*p), GFP_KERNEL);
306         if (p) {
307                 p->net = net;
308                 p->kobject.kset = rpc_sunrpc_kset;
309                 if (kobject_init_and_add(&p->kobject, &rpc_sysfs_client_type,
310                                          parent, "clnt-%d", clid) == 0)
311                         return p;
312                 kobject_put(&p->kobject);
313         }
314         return NULL;
315 }
316
317 static struct rpc_sysfs_xprt_switch *
318 rpc_sysfs_xprt_switch_alloc(struct kobject *parent,
319                             struct rpc_xprt_switch *xprt_switch,
320                             struct net *net,
321                             gfp_t gfp_flags)
322 {
323         struct rpc_sysfs_xprt_switch *p;
324
325         p = kzalloc(sizeof(*p), gfp_flags);
326         if (p) {
327                 p->net = net;
328                 p->kobject.kset = rpc_sunrpc_kset;
329                 if (kobject_init_and_add(&p->kobject,
330                                          &rpc_sysfs_xprt_switch_type,
331                                          parent, "switch-%d",
332                                          xprt_switch->xps_id) == 0)
333                         return p;
334                 kobject_put(&p->kobject);
335         }
336         return NULL;
337 }
338
339 static struct rpc_sysfs_xprt *rpc_sysfs_xprt_alloc(struct kobject *parent,
340                                                    struct rpc_xprt *xprt,
341                                                    gfp_t gfp_flags)
342 {
343         struct rpc_sysfs_xprt *p;
344
345         p = kzalloc(sizeof(*p), gfp_flags);
346         if (!p)
347                 goto out;
348         p->kobject.kset = rpc_sunrpc_kset;
349         if (kobject_init_and_add(&p->kobject, &rpc_sysfs_xprt_type,
350                                  parent, "xprt-%d-%s", xprt->id,
351                                  xprt->address_strings[RPC_DISPLAY_PROTO]) == 0)
352                 return p;
353         kobject_put(&p->kobject);
354 out:
355         return NULL;
356 }
357
358 void rpc_sysfs_client_setup(struct rpc_clnt *clnt,
359                             struct rpc_xprt_switch *xprt_switch,
360                             struct net *net)
361 {
362         struct rpc_sysfs_client *rpc_client;
363
364         rpc_client = rpc_sysfs_client_alloc(rpc_sunrpc_client_kobj,
365                                             net, clnt->cl_clid);
366         if (rpc_client) {
367                 char name[] = "switch";
368                 struct rpc_sysfs_xprt_switch *xswitch =
369                         (struct rpc_sysfs_xprt_switch *)xprt_switch->xps_sysfs;
370                 int ret;
371
372                 clnt->cl_sysfs = rpc_client;
373                 rpc_client->clnt = clnt;
374                 rpc_client->xprt_switch = xprt_switch;
375                 kobject_uevent(&rpc_client->kobject, KOBJ_ADD);
376                 ret = sysfs_create_link_nowarn(&rpc_client->kobject,
377                                                &xswitch->kobject, name);
378                 if (ret)
379                         pr_warn("can't create link to %s in sysfs (%d)\n",
380                                 name, ret);
381         }
382 }
383
384 void rpc_sysfs_xprt_switch_setup(struct rpc_xprt_switch *xprt_switch,
385                                  struct rpc_xprt *xprt,
386                                  gfp_t gfp_flags)
387 {
388         struct rpc_sysfs_xprt_switch *rpc_xprt_switch;
389         struct net *net;
390
391         if (xprt_switch->xps_net)
392                 net = xprt_switch->xps_net;
393         else
394                 net = xprt->xprt_net;
395         rpc_xprt_switch =
396                 rpc_sysfs_xprt_switch_alloc(rpc_sunrpc_xprt_switch_kobj,
397                                             xprt_switch, net, gfp_flags);
398         if (rpc_xprt_switch) {
399                 xprt_switch->xps_sysfs = rpc_xprt_switch;
400                 rpc_xprt_switch->xprt_switch = xprt_switch;
401                 rpc_xprt_switch->xprt = xprt;
402                 kobject_uevent(&rpc_xprt_switch->kobject, KOBJ_ADD);
403         }
404 }
405
406 void rpc_sysfs_xprt_setup(struct rpc_xprt_switch *xprt_switch,
407                           struct rpc_xprt *xprt,
408                           gfp_t gfp_flags)
409 {
410         struct rpc_sysfs_xprt *rpc_xprt;
411         struct rpc_sysfs_xprt_switch *switch_obj =
412                 (struct rpc_sysfs_xprt_switch *)xprt_switch->xps_sysfs;
413
414         rpc_xprt = rpc_sysfs_xprt_alloc(&switch_obj->kobject, xprt, gfp_flags);
415         if (rpc_xprt) {
416                 xprt->xprt_sysfs = rpc_xprt;
417                 rpc_xprt->xprt = xprt;
418                 kobject_uevent(&rpc_xprt->kobject, KOBJ_ADD);
419         }
420 }
421
422 void rpc_sysfs_client_destroy(struct rpc_clnt *clnt)
423 {
424         struct rpc_sysfs_client *rpc_client = clnt->cl_sysfs;
425
426         if (rpc_client) {
427                 char name[] = "switch";
428
429                 sysfs_remove_link(&rpc_client->kobject, name);
430                 kobject_uevent(&rpc_client->kobject, KOBJ_REMOVE);
431                 kobject_del(&rpc_client->kobject);
432                 kobject_put(&rpc_client->kobject);
433                 clnt->cl_sysfs = NULL;
434         }
435 }
436
437 void rpc_sysfs_xprt_switch_destroy(struct rpc_xprt_switch *xprt_switch)
438 {
439         struct rpc_sysfs_xprt_switch *rpc_xprt_switch = xprt_switch->xps_sysfs;
440
441         if (rpc_xprt_switch) {
442                 kobject_uevent(&rpc_xprt_switch->kobject, KOBJ_REMOVE);
443                 kobject_del(&rpc_xprt_switch->kobject);
444                 kobject_put(&rpc_xprt_switch->kobject);
445                 xprt_switch->xps_sysfs = NULL;
446         }
447 }
448
449 void rpc_sysfs_xprt_destroy(struct rpc_xprt *xprt)
450 {
451         struct rpc_sysfs_xprt *rpc_xprt = xprt->xprt_sysfs;
452
453         if (rpc_xprt) {
454                 kobject_uevent(&rpc_xprt->kobject, KOBJ_REMOVE);
455                 kobject_del(&rpc_xprt->kobject);
456                 kobject_put(&rpc_xprt->kobject);
457                 xprt->xprt_sysfs = NULL;
458         }
459 }