sunrpc: add a symlink from rpc-client directory to the xprt_switch
[linux-2.6-microblaze.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 "sysfs.h"
8
9 static struct kset *rpc_sunrpc_kset;
10 static struct kobject *rpc_sunrpc_client_kobj, *rpc_sunrpc_xprt_switch_kobj;
11
12 static void rpc_sysfs_object_release(struct kobject *kobj)
13 {
14         kfree(kobj);
15 }
16
17 static const struct kobj_ns_type_operations *
18 rpc_sysfs_object_child_ns_type(struct kobject *kobj)
19 {
20         return &net_ns_type_operations;
21 }
22
23 static struct kobj_type rpc_sysfs_object_type = {
24         .release = rpc_sysfs_object_release,
25         .sysfs_ops = &kobj_sysfs_ops,
26         .child_ns_type = rpc_sysfs_object_child_ns_type,
27 };
28
29 static struct kobject *rpc_sysfs_object_alloc(const char *name,
30                                               struct kset *kset,
31                                               struct kobject *parent)
32 {
33         struct kobject *kobj;
34
35         kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
36         if (kobj) {
37                 kobj->kset = kset;
38                 if (kobject_init_and_add(kobj, &rpc_sysfs_object_type,
39                                          parent, "%s", name) == 0)
40                         return kobj;
41                 kobject_put(kobj);
42         }
43         return NULL;
44 }
45
46 int rpc_sysfs_init(void)
47 {
48         rpc_sunrpc_kset = kset_create_and_add("sunrpc", NULL, kernel_kobj);
49         if (!rpc_sunrpc_kset)
50                 return -ENOMEM;
51         rpc_sunrpc_client_kobj =
52                 rpc_sysfs_object_alloc("rpc-clients", rpc_sunrpc_kset, NULL);
53         if (!rpc_sunrpc_client_kobj)
54                 goto err_client;
55         rpc_sunrpc_xprt_switch_kobj =
56                 rpc_sysfs_object_alloc("xprt-switches", rpc_sunrpc_kset, NULL);
57         if (!rpc_sunrpc_xprt_switch_kobj)
58                 goto err_switch;
59         return 0;
60 err_switch:
61         kobject_put(rpc_sunrpc_client_kobj);
62         rpc_sunrpc_client_kobj = NULL;
63 err_client:
64         kset_unregister(rpc_sunrpc_kset);
65         rpc_sunrpc_kset = NULL;
66         return -ENOMEM;
67 }
68
69 static void rpc_sysfs_client_release(struct kobject *kobj)
70 {
71         struct rpc_sysfs_client *c;
72
73         c = container_of(kobj, struct rpc_sysfs_client, kobject);
74         kfree(c);
75 }
76
77 static void rpc_sysfs_xprt_switch_release(struct kobject *kobj)
78 {
79         struct rpc_sysfs_xprt_switch *xprt_switch;
80
81         xprt_switch = container_of(kobj, struct rpc_sysfs_xprt_switch, kobject);
82         kfree(xprt_switch);
83 }
84
85 static const void *rpc_sysfs_client_namespace(struct kobject *kobj)
86 {
87         return container_of(kobj, struct rpc_sysfs_client, kobject)->net;
88 }
89
90 static const void *rpc_sysfs_xprt_switch_namespace(struct kobject *kobj)
91 {
92         return container_of(kobj, struct rpc_sysfs_xprt_switch, kobject)->net;
93 }
94
95 static struct kobj_type rpc_sysfs_client_type = {
96         .release = rpc_sysfs_client_release,
97         .sysfs_ops = &kobj_sysfs_ops,
98         .namespace = rpc_sysfs_client_namespace,
99 };
100
101 static struct kobj_type rpc_sysfs_xprt_switch_type = {
102         .release = rpc_sysfs_xprt_switch_release,
103         .sysfs_ops = &kobj_sysfs_ops,
104         .namespace = rpc_sysfs_xprt_switch_namespace,
105 };
106
107 void rpc_sysfs_exit(void)
108 {
109         kobject_put(rpc_sunrpc_client_kobj);
110         kobject_put(rpc_sunrpc_xprt_switch_kobj);
111         kset_unregister(rpc_sunrpc_kset);
112 }
113
114 static struct rpc_sysfs_client *rpc_sysfs_client_alloc(struct kobject *parent,
115                                                        struct net *net,
116                                                        int clid)
117 {
118         struct rpc_sysfs_client *p;
119
120         p = kzalloc(sizeof(*p), GFP_KERNEL);
121         if (p) {
122                 p->net = net;
123                 p->kobject.kset = rpc_sunrpc_kset;
124                 if (kobject_init_and_add(&p->kobject, &rpc_sysfs_client_type,
125                                          parent, "clnt-%d", clid) == 0)
126                         return p;
127                 kobject_put(&p->kobject);
128         }
129         return NULL;
130 }
131
132 static struct rpc_sysfs_xprt_switch *
133 rpc_sysfs_xprt_switch_alloc(struct kobject *parent,
134                             struct rpc_xprt_switch *xprt_switch,
135                             struct net *net,
136                             gfp_t gfp_flags)
137 {
138         struct rpc_sysfs_xprt_switch *p;
139
140         p = kzalloc(sizeof(*p), gfp_flags);
141         if (p) {
142                 p->net = net;
143                 p->kobject.kset = rpc_sunrpc_kset;
144                 if (kobject_init_and_add(&p->kobject,
145                                          &rpc_sysfs_xprt_switch_type,
146                                          parent, "switch-%d",
147                                          xprt_switch->xps_id) == 0)
148                         return p;
149                 kobject_put(&p->kobject);
150         }
151         return NULL;
152 }
153
154 void rpc_sysfs_client_setup(struct rpc_clnt *clnt,
155                             struct rpc_xprt_switch *xprt_switch,
156                             struct net *net)
157 {
158         struct rpc_sysfs_client *rpc_client;
159
160         rpc_client = rpc_sysfs_client_alloc(rpc_sunrpc_client_kobj,
161                                             net, clnt->cl_clid);
162         if (rpc_client) {
163                 char name[] = "switch";
164                 struct rpc_sysfs_xprt_switch *xswitch =
165                         (struct rpc_sysfs_xprt_switch *)xprt_switch->xps_sysfs;
166                 int ret;
167
168                 clnt->cl_sysfs = rpc_client;
169                 rpc_client->clnt = clnt;
170                 rpc_client->xprt_switch = xprt_switch;
171                 kobject_uevent(&rpc_client->kobject, KOBJ_ADD);
172                 ret = sysfs_create_link_nowarn(&rpc_client->kobject,
173                                                &xswitch->kobject, name);
174                 if (ret)
175                         pr_warn("can't create link to %s in sysfs (%d)\n",
176                                 name, ret);
177         }
178 }
179
180 void rpc_sysfs_xprt_switch_setup(struct rpc_xprt_switch *xprt_switch,
181                                  struct rpc_xprt *xprt,
182                                  gfp_t gfp_flags)
183 {
184         struct rpc_sysfs_xprt_switch *rpc_xprt_switch;
185         struct net *net;
186
187         if (xprt_switch->xps_net)
188                 net = xprt_switch->xps_net;
189         else
190                 net = xprt->xprt_net;
191         rpc_xprt_switch =
192                 rpc_sysfs_xprt_switch_alloc(rpc_sunrpc_xprt_switch_kobj,
193                                             xprt_switch, net, gfp_flags);
194         if (rpc_xprt_switch) {
195                 xprt_switch->xps_sysfs = rpc_xprt_switch;
196                 rpc_xprt_switch->xprt_switch = xprt_switch;
197                 rpc_xprt_switch->xprt = xprt;
198                 kobject_uevent(&rpc_xprt_switch->kobject, KOBJ_ADD);
199         }
200 }
201
202 void rpc_sysfs_client_destroy(struct rpc_clnt *clnt)
203 {
204         struct rpc_sysfs_client *rpc_client = clnt->cl_sysfs;
205
206         if (rpc_client) {
207                 char name[] = "switch";
208
209                 sysfs_remove_link(&rpc_client->kobject, name);
210                 kobject_uevent(&rpc_client->kobject, KOBJ_REMOVE);
211                 kobject_del(&rpc_client->kobject);
212                 kobject_put(&rpc_client->kobject);
213                 clnt->cl_sysfs = NULL;
214         }
215 }
216
217 void rpc_sysfs_xprt_switch_destroy(struct rpc_xprt_switch *xprt_switch)
218 {
219         struct rpc_sysfs_xprt_switch *rpc_xprt_switch = xprt_switch->xps_sysfs;
220
221         if (rpc_xprt_switch) {
222                 kobject_uevent(&rpc_xprt_switch->kobject, KOBJ_REMOVE);
223                 kobject_del(&rpc_xprt_switch->kobject);
224                 kobject_put(&rpc_xprt_switch->kobject);
225                 xprt_switch->xps_sysfs = NULL;
226         }
227 }