174678748SOlga Kornievskaia // SPDX-License-Identifier: GPL-2.0
274678748SOlga Kornievskaia /*
374678748SOlga Kornievskaia * Copyright (c) 2020 Anna Schumaker <Anna.Schumaker@Netapp.com>
474678748SOlga Kornievskaia */
5c441f125SOlga Kornievskaia #include <linux/sunrpc/clnt.h>
674678748SOlga Kornievskaia #include <linux/kobject.h>
7587bc725SOlga Kornievskaia #include <linux/sunrpc/addr.h>
8c1830a63SOlga Kornievskaia #include <linux/sunrpc/xprtsock.h>
9587bc725SOlga Kornievskaia
10c5a382ebSOlga Kornievskaia #include "sysfs.h"
1174678748SOlga Kornievskaia
12587bc725SOlga Kornievskaia struct xprt_addr {
13587bc725SOlga Kornievskaia const char *addr;
14587bc725SOlga Kornievskaia struct rcu_head rcu;
15587bc725SOlga Kornievskaia };
16587bc725SOlga Kornievskaia
free_xprt_addr(struct rcu_head * head)17587bc725SOlga Kornievskaia static void free_xprt_addr(struct rcu_head *head)
18587bc725SOlga Kornievskaia {
19587bc725SOlga Kornievskaia struct xprt_addr *addr = container_of(head, struct xprt_addr, rcu);
20587bc725SOlga Kornievskaia
21587bc725SOlga Kornievskaia kfree(addr->addr);
22587bc725SOlga Kornievskaia kfree(addr);
23587bc725SOlga Kornievskaia }
24587bc725SOlga Kornievskaia
2574678748SOlga Kornievskaia static struct kset *rpc_sunrpc_kset;
26baea9944SOlga Kornievskaia static struct kobject *rpc_sunrpc_client_kobj, *rpc_sunrpc_xprt_switch_kobj;
27c441f125SOlga Kornievskaia
rpc_sysfs_object_release(struct kobject * kobj)28c441f125SOlga Kornievskaia static void rpc_sysfs_object_release(struct kobject *kobj)
29c441f125SOlga Kornievskaia {
30c441f125SOlga Kornievskaia kfree(kobj);
31c441f125SOlga Kornievskaia }
32c441f125SOlga Kornievskaia
33c441f125SOlga Kornievskaia static const struct kobj_ns_type_operations *
rpc_sysfs_object_child_ns_type(const struct kobject * kobj)3402a476d9SGreg Kroah-Hartman rpc_sysfs_object_child_ns_type(const struct kobject *kobj)
35c441f125SOlga Kornievskaia {
36c441f125SOlga Kornievskaia return &net_ns_type_operations;
37c441f125SOlga Kornievskaia }
38c441f125SOlga Kornievskaia
39d67307b4SThomas Weißschuh static const struct kobj_type rpc_sysfs_object_type = {
40c441f125SOlga Kornievskaia .release = rpc_sysfs_object_release,
41c441f125SOlga Kornievskaia .sysfs_ops = &kobj_sysfs_ops,
42c441f125SOlga Kornievskaia .child_ns_type = rpc_sysfs_object_child_ns_type,
43c441f125SOlga Kornievskaia };
44c441f125SOlga Kornievskaia
rpc_sysfs_object_alloc(const char * name,struct kset * kset,struct kobject * parent)45c441f125SOlga Kornievskaia static struct kobject *rpc_sysfs_object_alloc(const char *name,
46c441f125SOlga Kornievskaia struct kset *kset,
47c441f125SOlga Kornievskaia struct kobject *parent)
48c441f125SOlga Kornievskaia {
49c441f125SOlga Kornievskaia struct kobject *kobj;
50c441f125SOlga Kornievskaia
51c441f125SOlga Kornievskaia kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
52c441f125SOlga Kornievskaia if (kobj) {
53c441f125SOlga Kornievskaia kobj->kset = kset;
54c441f125SOlga Kornievskaia if (kobject_init_and_add(kobj, &rpc_sysfs_object_type,
55c441f125SOlga Kornievskaia parent, "%s", name) == 0)
56c441f125SOlga Kornievskaia return kobj;
57c441f125SOlga Kornievskaia kobject_put(kobj);
58c441f125SOlga Kornievskaia }
59c441f125SOlga Kornievskaia return NULL;
60c441f125SOlga Kornievskaia }
6174678748SOlga Kornievskaia
62587bc725SOlga Kornievskaia static inline struct rpc_xprt *
rpc_sysfs_xprt_kobj_get_xprt(struct kobject * kobj)63587bc725SOlga Kornievskaia rpc_sysfs_xprt_kobj_get_xprt(struct kobject *kobj)
64587bc725SOlga Kornievskaia {
65587bc725SOlga Kornievskaia struct rpc_sysfs_xprt *x = container_of(kobj,
66587bc725SOlga Kornievskaia struct rpc_sysfs_xprt, kobject);
67587bc725SOlga Kornievskaia
68587bc725SOlga Kornievskaia return xprt_get(x->xprt);
69587bc725SOlga Kornievskaia }
70587bc725SOlga Kornievskaia
710e559035SOlga Kornievskaia static inline struct rpc_xprt_switch *
rpc_sysfs_xprt_kobj_get_xprt_switch(struct kobject * kobj)725b7eb784SOlga Kornievskaia rpc_sysfs_xprt_kobj_get_xprt_switch(struct kobject *kobj)
735b7eb784SOlga Kornievskaia {
745b7eb784SOlga Kornievskaia struct rpc_sysfs_xprt *x = container_of(kobj,
755b7eb784SOlga Kornievskaia struct rpc_sysfs_xprt, kobject);
765b7eb784SOlga Kornievskaia
775b7eb784SOlga Kornievskaia return xprt_switch_get(x->xprt_switch);
785b7eb784SOlga Kornievskaia }
795b7eb784SOlga Kornievskaia
805b7eb784SOlga Kornievskaia static inline struct rpc_xprt_switch *
rpc_sysfs_xprt_switch_kobj_get_xprt(struct kobject * kobj)810e559035SOlga Kornievskaia rpc_sysfs_xprt_switch_kobj_get_xprt(struct kobject *kobj)
820e559035SOlga Kornievskaia {
830e559035SOlga Kornievskaia struct rpc_sysfs_xprt_switch *x = container_of(kobj,
840e559035SOlga Kornievskaia struct rpc_sysfs_xprt_switch, kobject);
850e559035SOlga Kornievskaia
860e559035SOlga Kornievskaia return xprt_switch_get(x->xprt_switch);
870e559035SOlga Kornievskaia }
880e559035SOlga Kornievskaia
rpc_sysfs_xprt_dstaddr_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)89587bc725SOlga Kornievskaia static ssize_t rpc_sysfs_xprt_dstaddr_show(struct kobject *kobj,
90587bc725SOlga Kornievskaia struct kobj_attribute *attr,
91587bc725SOlga Kornievskaia char *buf)
92587bc725SOlga Kornievskaia {
93587bc725SOlga Kornievskaia struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
94587bc725SOlga Kornievskaia ssize_t ret;
95587bc725SOlga Kornievskaia
96ebbe7887STrond Myklebust if (!xprt) {
97ebbe7887STrond Myklebust ret = sprintf(buf, "<closed>\n");
98ebbe7887STrond Myklebust goto out;
99ebbe7887STrond Myklebust }
100587bc725SOlga Kornievskaia ret = sprintf(buf, "%s\n", xprt->address_strings[RPC_DISPLAY_ADDR]);
101587bc725SOlga Kornievskaia xprt_put(xprt);
102ebbe7887STrond Myklebust out:
103421ab1beSTrond Myklebust return ret;
104587bc725SOlga Kornievskaia }
105587bc725SOlga Kornievskaia
rpc_sysfs_xprt_srcaddr_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)106e44773daSAnna Schumaker static ssize_t rpc_sysfs_xprt_srcaddr_show(struct kobject *kobj,
107e44773daSAnna Schumaker struct kobj_attribute *attr,
108e44773daSAnna Schumaker char *buf)
109e44773daSAnna Schumaker {
110e44773daSAnna Schumaker struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
111421ab1beSTrond Myklebust size_t buflen = PAGE_SIZE;
112ebbe7887STrond Myklebust ssize_t ret;
113e44773daSAnna Schumaker
11417f09d3fSAnna Schumaker if (!xprt || !xprt_connected(xprt)) {
115ebbe7887STrond Myklebust ret = sprintf(buf, "<closed>\n");
116421ab1beSTrond Myklebust } else if (xprt->ops->get_srcaddr) {
117421ab1beSTrond Myklebust ret = xprt->ops->get_srcaddr(xprt, buf, buflen);
118421ab1beSTrond Myklebust if (ret > 0) {
119421ab1beSTrond Myklebust if (ret < buflen - 1) {
120421ab1beSTrond Myklebust buf[ret] = '\n';
121421ab1beSTrond Myklebust ret++;
122421ab1beSTrond Myklebust buf[ret] = '\0';
12317f09d3fSAnna Schumaker }
124ebbe7887STrond Myklebust } else
125ebbe7887STrond Myklebust ret = sprintf(buf, "<closed>\n");
126ebbe7887STrond Myklebust } else
127ebbe7887STrond Myklebust ret = sprintf(buf, "<not a socket>\n");
128e44773daSAnna Schumaker xprt_put(xprt);
129421ab1beSTrond Myklebust return ret;
130e44773daSAnna Schumaker }
131e44773daSAnna Schumaker
rpc_sysfs_xprt_info_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)1324a09651aSOlga Kornievskaia static ssize_t rpc_sysfs_xprt_info_show(struct kobject *kobj,
133421ab1beSTrond Myklebust struct kobj_attribute *attr, char *buf)
1344a09651aSOlga Kornievskaia {
1354a09651aSOlga Kornievskaia struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
136421ab1beSTrond Myklebust unsigned short srcport = 0;
137421ab1beSTrond Myklebust size_t buflen = PAGE_SIZE;
1384a09651aSOlga Kornievskaia ssize_t ret;
1394a09651aSOlga Kornievskaia
14017f09d3fSAnna Schumaker if (!xprt || !xprt_connected(xprt)) {
141ebbe7887STrond Myklebust ret = sprintf(buf, "<closed>\n");
142ebbe7887STrond Myklebust goto out;
14317f09d3fSAnna Schumaker }
1444a09651aSOlga Kornievskaia
145421ab1beSTrond Myklebust if (xprt->ops->get_srcport)
146421ab1beSTrond Myklebust srcport = xprt->ops->get_srcport(xprt);
147421ab1beSTrond Myklebust
148421ab1beSTrond Myklebust ret = snprintf(buf, buflen,
149421ab1beSTrond Myklebust "last_used=%lu\ncur_cong=%lu\ncong_win=%lu\n"
1504a09651aSOlga Kornievskaia "max_num_slots=%u\nmin_num_slots=%u\nnum_reqs=%u\n"
1514a09651aSOlga Kornievskaia "binding_q_len=%u\nsending_q_len=%u\npending_q_len=%u\n"
1526a284059SOlga Kornievskaia "backlog_q_len=%u\nmain_xprt=%d\nsrc_port=%u\n"
15369f2cd6dSAnna Schumaker "tasks_queuelen=%ld\ndst_port=%s\n",
154c1830a63SOlga Kornievskaia xprt->last_used, xprt->cong, xprt->cwnd, xprt->max_reqs,
155c1830a63SOlga Kornievskaia xprt->min_reqs, xprt->num_reqs, xprt->binding.qlen,
156c1830a63SOlga Kornievskaia xprt->sending.qlen, xprt->pending.qlen,
157421ab1beSTrond Myklebust xprt->backlog.qlen, xprt->main, srcport,
15869f2cd6dSAnna Schumaker atomic_long_read(&xprt->queuelen),
159421ab1beSTrond Myklebust xprt->address_strings[RPC_DISPLAY_PORT]);
160ebbe7887STrond Myklebust out:
1614a09651aSOlga Kornievskaia xprt_put(xprt);
162421ab1beSTrond Myklebust return ret;
1634a09651aSOlga Kornievskaia }
1644a09651aSOlga Kornievskaia
rpc_sysfs_xprt_state_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)165681d5699SOlga Kornievskaia static ssize_t rpc_sysfs_xprt_state_show(struct kobject *kobj,
166681d5699SOlga Kornievskaia struct kobj_attribute *attr,
167681d5699SOlga Kornievskaia char *buf)
168681d5699SOlga Kornievskaia {
169681d5699SOlga Kornievskaia struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
170681d5699SOlga Kornievskaia ssize_t ret;
171681d5699SOlga Kornievskaia int locked, connected, connecting, close_wait, bound, binding,
1726f081693SOlga Kornievskaia closing, congested, cwnd_wait, write_space, offline, remove;
173681d5699SOlga Kornievskaia
174ebbe7887STrond Myklebust if (!(xprt && xprt->state)) {
175681d5699SOlga Kornievskaia ret = sprintf(buf, "state=CLOSED\n");
176681d5699SOlga Kornievskaia } else {
177681d5699SOlga Kornievskaia locked = test_bit(XPRT_LOCKED, &xprt->state);
178681d5699SOlga Kornievskaia connected = test_bit(XPRT_CONNECTED, &xprt->state);
179681d5699SOlga Kornievskaia connecting = test_bit(XPRT_CONNECTING, &xprt->state);
180681d5699SOlga Kornievskaia close_wait = test_bit(XPRT_CLOSE_WAIT, &xprt->state);
181681d5699SOlga Kornievskaia bound = test_bit(XPRT_BOUND, &xprt->state);
182681d5699SOlga Kornievskaia binding = test_bit(XPRT_BINDING, &xprt->state);
183681d5699SOlga Kornievskaia closing = test_bit(XPRT_CLOSING, &xprt->state);
184681d5699SOlga Kornievskaia congested = test_bit(XPRT_CONGESTED, &xprt->state);
185681d5699SOlga Kornievskaia cwnd_wait = test_bit(XPRT_CWND_WAIT, &xprt->state);
186681d5699SOlga Kornievskaia write_space = test_bit(XPRT_WRITE_SPACE, &xprt->state);
1875b7eb784SOlga Kornievskaia offline = test_bit(XPRT_OFFLINE, &xprt->state);
1886f081693SOlga Kornievskaia remove = test_bit(XPRT_REMOVE, &xprt->state);
189681d5699SOlga Kornievskaia
1906f081693SOlga Kornievskaia ret = sprintf(buf, "state=%s %s %s %s %s %s %s %s %s %s %s %s\n",
191681d5699SOlga Kornievskaia locked ? "LOCKED" : "",
192681d5699SOlga Kornievskaia connected ? "CONNECTED" : "",
193681d5699SOlga Kornievskaia connecting ? "CONNECTING" : "",
194681d5699SOlga Kornievskaia close_wait ? "CLOSE_WAIT" : "",
195681d5699SOlga Kornievskaia bound ? "BOUND" : "",
196681d5699SOlga Kornievskaia binding ? "BOUNDING" : "",
197681d5699SOlga Kornievskaia closing ? "CLOSING" : "",
198681d5699SOlga Kornievskaia congested ? "CONGESTED" : "",
199681d5699SOlga Kornievskaia cwnd_wait ? "CWND_WAIT" : "",
2005b7eb784SOlga Kornievskaia write_space ? "WRITE_SPACE" : "",
2016f081693SOlga Kornievskaia offline ? "OFFLINE" : "",
2026f081693SOlga Kornievskaia remove ? "REMOVE" : "");
203681d5699SOlga Kornievskaia }
204681d5699SOlga Kornievskaia
205681d5699SOlga Kornievskaia xprt_put(xprt);
206421ab1beSTrond Myklebust return ret;
207681d5699SOlga Kornievskaia }
208681d5699SOlga Kornievskaia
rpc_sysfs_xprt_switch_info_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)2090e559035SOlga Kornievskaia static ssize_t rpc_sysfs_xprt_switch_info_show(struct kobject *kobj,
2100e559035SOlga Kornievskaia struct kobj_attribute *attr,
2110e559035SOlga Kornievskaia char *buf)
2120e559035SOlga Kornievskaia {
2130e559035SOlga Kornievskaia struct rpc_xprt_switch *xprt_switch =
2140e559035SOlga Kornievskaia rpc_sysfs_xprt_switch_kobj_get_xprt(kobj);
2150e559035SOlga Kornievskaia ssize_t ret;
2160e559035SOlga Kornievskaia
2170e559035SOlga Kornievskaia if (!xprt_switch)
2180e559035SOlga Kornievskaia return 0;
219df205d0aSOlga Kornievskaia ret = sprintf(buf, "num_xprts=%u\nnum_active=%u\n"
220df205d0aSOlga Kornievskaia "num_unique_destaddr=%u\nqueue_len=%ld\n",
2210e559035SOlga Kornievskaia xprt_switch->xps_nxprts, xprt_switch->xps_nactive,
222df205d0aSOlga Kornievskaia xprt_switch->xps_nunique_destaddr_xprts,
2230e559035SOlga Kornievskaia atomic_long_read(&xprt_switch->xps_queuelen));
2240e559035SOlga Kornievskaia xprt_switch_put(xprt_switch);
225421ab1beSTrond Myklebust return ret;
2260e559035SOlga Kornievskaia }
2270e559035SOlga Kornievskaia
rpc_sysfs_xprt_dstaddr_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)228587bc725SOlga Kornievskaia static ssize_t rpc_sysfs_xprt_dstaddr_store(struct kobject *kobj,
229587bc725SOlga Kornievskaia struct kobj_attribute *attr,
230587bc725SOlga Kornievskaia const char *buf, size_t count)
231587bc725SOlga Kornievskaia {
232587bc725SOlga Kornievskaia struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
233587bc725SOlga Kornievskaia struct sockaddr *saddr;
234587bc725SOlga Kornievskaia char *dst_addr;
235587bc725SOlga Kornievskaia int port;
236587bc725SOlga Kornievskaia struct xprt_addr *saved_addr;
237587bc725SOlga Kornievskaia size_t buf_len;
238587bc725SOlga Kornievskaia
239587bc725SOlga Kornievskaia if (!xprt)
240587bc725SOlga Kornievskaia return 0;
241587bc725SOlga Kornievskaia if (!(xprt->xprt_class->ident == XPRT_TRANSPORT_TCP ||
242*75eb6af7SChuck Lever xprt->xprt_class->ident == XPRT_TRANSPORT_TCP_TLS ||
243587bc725SOlga Kornievskaia xprt->xprt_class->ident == XPRT_TRANSPORT_RDMA)) {
244587bc725SOlga Kornievskaia xprt_put(xprt);
245587bc725SOlga Kornievskaia return -EOPNOTSUPP;
246587bc725SOlga Kornievskaia }
247587bc725SOlga Kornievskaia
248587bc725SOlga Kornievskaia if (wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_KILLABLE)) {
249587bc725SOlga Kornievskaia count = -EINTR;
250587bc725SOlga Kornievskaia goto out_put;
251587bc725SOlga Kornievskaia }
252587bc725SOlga Kornievskaia saddr = (struct sockaddr *)&xprt->addr;
253587bc725SOlga Kornievskaia port = rpc_get_port(saddr);
254587bc725SOlga Kornievskaia
255587bc725SOlga Kornievskaia /* buf_len is the len until the first occurence of either
256587bc725SOlga Kornievskaia * '\n' or '\0'
257587bc725SOlga Kornievskaia */
258587bc725SOlga Kornievskaia buf_len = strcspn(buf, "\n");
259587bc725SOlga Kornievskaia
260587bc725SOlga Kornievskaia dst_addr = kstrndup(buf, buf_len, GFP_KERNEL);
261587bc725SOlga Kornievskaia if (!dst_addr)
262587bc725SOlga Kornievskaia goto out_err;
263587bc725SOlga Kornievskaia saved_addr = kzalloc(sizeof(*saved_addr), GFP_KERNEL);
264587bc725SOlga Kornievskaia if (!saved_addr)
265587bc725SOlga Kornievskaia goto out_err_free;
266587bc725SOlga Kornievskaia saved_addr->addr =
267587bc725SOlga Kornievskaia rcu_dereference_raw(xprt->address_strings[RPC_DISPLAY_ADDR]);
268587bc725SOlga Kornievskaia rcu_assign_pointer(xprt->address_strings[RPC_DISPLAY_ADDR], dst_addr);
269587bc725SOlga Kornievskaia call_rcu(&saved_addr->rcu, free_xprt_addr);
270587bc725SOlga Kornievskaia xprt->addrlen = rpc_pton(xprt->xprt_net, buf, buf_len, saddr,
271587bc725SOlga Kornievskaia sizeof(*saddr));
272587bc725SOlga Kornievskaia rpc_set_port(saddr, port);
273587bc725SOlga Kornievskaia
274587bc725SOlga Kornievskaia xprt_force_disconnect(xprt);
275587bc725SOlga Kornievskaia out:
276587bc725SOlga Kornievskaia xprt_release_write(xprt, NULL);
277587bc725SOlga Kornievskaia out_put:
278587bc725SOlga Kornievskaia xprt_put(xprt);
279587bc725SOlga Kornievskaia return count;
280587bc725SOlga Kornievskaia out_err_free:
281587bc725SOlga Kornievskaia kfree(dst_addr);
282587bc725SOlga Kornievskaia out_err:
283587bc725SOlga Kornievskaia count = -ENOMEM;
284587bc725SOlga Kornievskaia goto out;
285587bc725SOlga Kornievskaia }
286587bc725SOlga Kornievskaia
rpc_sysfs_xprt_state_change(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)2875b7eb784SOlga Kornievskaia static ssize_t rpc_sysfs_xprt_state_change(struct kobject *kobj,
2885b7eb784SOlga Kornievskaia struct kobj_attribute *attr,
2895b7eb784SOlga Kornievskaia const char *buf, size_t count)
2905b7eb784SOlga Kornievskaia {
2915b7eb784SOlga Kornievskaia struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
2926f081693SOlga Kornievskaia int offline = 0, online = 0, remove = 0;
2935b7eb784SOlga Kornievskaia struct rpc_xprt_switch *xps = rpc_sysfs_xprt_kobj_get_xprt_switch(kobj);
2945b7eb784SOlga Kornievskaia
295bfc48f1bSXin Xiong if (!xprt || !xps) {
296bfc48f1bSXin Xiong count = 0;
297bfc48f1bSXin Xiong goto out_put;
298bfc48f1bSXin Xiong }
2995b7eb784SOlga Kornievskaia
3005b7eb784SOlga Kornievskaia if (!strncmp(buf, "offline", 7))
3015b7eb784SOlga Kornievskaia offline = 1;
3025b7eb784SOlga Kornievskaia else if (!strncmp(buf, "online", 6))
3035b7eb784SOlga Kornievskaia online = 1;
3046f081693SOlga Kornievskaia else if (!strncmp(buf, "remove", 6))
3056f081693SOlga Kornievskaia remove = 1;
306776d794fSXiyu Yang else {
307776d794fSXiyu Yang count = -EINVAL;
308776d794fSXiyu Yang goto out_put;
309776d794fSXiyu Yang }
3105b7eb784SOlga Kornievskaia
3115b7eb784SOlga Kornievskaia if (wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_KILLABLE)) {
3125b7eb784SOlga Kornievskaia count = -EINTR;
3135b7eb784SOlga Kornievskaia goto out_put;
3145b7eb784SOlga Kornievskaia }
3155b7eb784SOlga Kornievskaia if (xprt->main) {
3165b7eb784SOlga Kornievskaia count = -EINVAL;
3175b7eb784SOlga Kornievskaia goto release_tasks;
3185b7eb784SOlga Kornievskaia }
3195b7eb784SOlga Kornievskaia if (offline) {
3207ffcdaa6SOlga Kornievskaia xprt_set_offline_locked(xprt, xps);
3215b7eb784SOlga Kornievskaia } else if (online) {
3227ffcdaa6SOlga Kornievskaia xprt_set_online_locked(xprt, xps);
3236f081693SOlga Kornievskaia } else if (remove) {
3247ffcdaa6SOlga Kornievskaia if (test_bit(XPRT_OFFLINE, &xprt->state))
3257ffcdaa6SOlga Kornievskaia xprt_delete_locked(xprt, xps);
3267ffcdaa6SOlga Kornievskaia else
3276f081693SOlga Kornievskaia count = -EINVAL;
3286f081693SOlga Kornievskaia }
3295b7eb784SOlga Kornievskaia
3305b7eb784SOlga Kornievskaia release_tasks:
3315b7eb784SOlga Kornievskaia xprt_release_write(xprt, NULL);
3325b7eb784SOlga Kornievskaia out_put:
3335b7eb784SOlga Kornievskaia xprt_put(xprt);
3345b7eb784SOlga Kornievskaia xprt_switch_put(xps);
3355b7eb784SOlga Kornievskaia return count;
3365b7eb784SOlga Kornievskaia }
3375b7eb784SOlga Kornievskaia
rpc_sysfs_init(void)33874678748SOlga Kornievskaia int rpc_sysfs_init(void)
33974678748SOlga Kornievskaia {
34074678748SOlga Kornievskaia rpc_sunrpc_kset = kset_create_and_add("sunrpc", NULL, kernel_kobj);
34174678748SOlga Kornievskaia if (!rpc_sunrpc_kset)
34274678748SOlga Kornievskaia return -ENOMEM;
343baea9944SOlga Kornievskaia rpc_sunrpc_client_kobj =
344baea9944SOlga Kornievskaia rpc_sysfs_object_alloc("rpc-clients", rpc_sunrpc_kset, NULL);
345baea9944SOlga Kornievskaia if (!rpc_sunrpc_client_kobj)
346baea9944SOlga Kornievskaia goto err_client;
347baea9944SOlga Kornievskaia rpc_sunrpc_xprt_switch_kobj =
348baea9944SOlga Kornievskaia rpc_sysfs_object_alloc("xprt-switches", rpc_sunrpc_kset, NULL);
349baea9944SOlga Kornievskaia if (!rpc_sunrpc_xprt_switch_kobj)
350baea9944SOlga Kornievskaia goto err_switch;
35174678748SOlga Kornievskaia return 0;
352baea9944SOlga Kornievskaia err_switch:
353baea9944SOlga Kornievskaia kobject_put(rpc_sunrpc_client_kobj);
354baea9944SOlga Kornievskaia rpc_sunrpc_client_kobj = NULL;
355baea9944SOlga Kornievskaia err_client:
356baea9944SOlga Kornievskaia kset_unregister(rpc_sunrpc_kset);
357baea9944SOlga Kornievskaia rpc_sunrpc_kset = NULL;
358baea9944SOlga Kornievskaia return -ENOMEM;
35974678748SOlga Kornievskaia }
36074678748SOlga Kornievskaia
rpc_sysfs_client_release(struct kobject * kobj)361c5a382ebSOlga Kornievskaia static void rpc_sysfs_client_release(struct kobject *kobj)
362c5a382ebSOlga Kornievskaia {
363c5a382ebSOlga Kornievskaia struct rpc_sysfs_client *c;
364c5a382ebSOlga Kornievskaia
365c5a382ebSOlga Kornievskaia c = container_of(kobj, struct rpc_sysfs_client, kobject);
366c5a382ebSOlga Kornievskaia kfree(c);
367c5a382ebSOlga Kornievskaia }
368c5a382ebSOlga Kornievskaia
rpc_sysfs_xprt_switch_release(struct kobject * kobj)369baea9944SOlga Kornievskaia static void rpc_sysfs_xprt_switch_release(struct kobject *kobj)
370baea9944SOlga Kornievskaia {
371baea9944SOlga Kornievskaia struct rpc_sysfs_xprt_switch *xprt_switch;
372baea9944SOlga Kornievskaia
373baea9944SOlga Kornievskaia xprt_switch = container_of(kobj, struct rpc_sysfs_xprt_switch, kobject);
374baea9944SOlga Kornievskaia kfree(xprt_switch);
375baea9944SOlga Kornievskaia }
376baea9944SOlga Kornievskaia
rpc_sysfs_xprt_release(struct kobject * kobj)377d408ebe0SOlga Kornievskaia static void rpc_sysfs_xprt_release(struct kobject *kobj)
378d408ebe0SOlga Kornievskaia {
379d408ebe0SOlga Kornievskaia struct rpc_sysfs_xprt *xprt;
380d408ebe0SOlga Kornievskaia
381d408ebe0SOlga Kornievskaia xprt = container_of(kobj, struct rpc_sysfs_xprt, kobject);
382d408ebe0SOlga Kornievskaia kfree(xprt);
383d408ebe0SOlga Kornievskaia }
384d408ebe0SOlga Kornievskaia
rpc_sysfs_client_namespace(const struct kobject * kobj)38502a476d9SGreg Kroah-Hartman static const void *rpc_sysfs_client_namespace(const struct kobject *kobj)
386c5a382ebSOlga Kornievskaia {
387c5a382ebSOlga Kornievskaia return container_of(kobj, struct rpc_sysfs_client, kobject)->net;
388c5a382ebSOlga Kornievskaia }
389c5a382ebSOlga Kornievskaia
rpc_sysfs_xprt_switch_namespace(const struct kobject * kobj)39002a476d9SGreg Kroah-Hartman static const void *rpc_sysfs_xprt_switch_namespace(const struct kobject *kobj)
391baea9944SOlga Kornievskaia {
392baea9944SOlga Kornievskaia return container_of(kobj, struct rpc_sysfs_xprt_switch, kobject)->net;
393baea9944SOlga Kornievskaia }
394baea9944SOlga Kornievskaia
rpc_sysfs_xprt_namespace(const struct kobject * kobj)39502a476d9SGreg Kroah-Hartman static const void *rpc_sysfs_xprt_namespace(const struct kobject *kobj)
396d408ebe0SOlga Kornievskaia {
397d408ebe0SOlga Kornievskaia return container_of(kobj, struct rpc_sysfs_xprt,
398d408ebe0SOlga Kornievskaia kobject)->xprt->xprt_net;
399d408ebe0SOlga Kornievskaia }
400d408ebe0SOlga Kornievskaia
401587bc725SOlga Kornievskaia static struct kobj_attribute rpc_sysfs_xprt_dstaddr = __ATTR(dstaddr,
402587bc725SOlga Kornievskaia 0644, rpc_sysfs_xprt_dstaddr_show, rpc_sysfs_xprt_dstaddr_store);
403587bc725SOlga Kornievskaia
404e44773daSAnna Schumaker static struct kobj_attribute rpc_sysfs_xprt_srcaddr = __ATTR(srcaddr,
405e44773daSAnna Schumaker 0644, rpc_sysfs_xprt_srcaddr_show, NULL);
406e44773daSAnna Schumaker
4074a09651aSOlga Kornievskaia static struct kobj_attribute rpc_sysfs_xprt_info = __ATTR(xprt_info,
4084a09651aSOlga Kornievskaia 0444, rpc_sysfs_xprt_info_show, NULL);
4094a09651aSOlga Kornievskaia
410681d5699SOlga Kornievskaia static struct kobj_attribute rpc_sysfs_xprt_change_state = __ATTR(xprt_state,
4115b7eb784SOlga Kornievskaia 0644, rpc_sysfs_xprt_state_show, rpc_sysfs_xprt_state_change);
412681d5699SOlga Kornievskaia
413587bc725SOlga Kornievskaia static struct attribute *rpc_sysfs_xprt_attrs[] = {
414587bc725SOlga Kornievskaia &rpc_sysfs_xprt_dstaddr.attr,
415e44773daSAnna Schumaker &rpc_sysfs_xprt_srcaddr.attr,
4164a09651aSOlga Kornievskaia &rpc_sysfs_xprt_info.attr,
417681d5699SOlga Kornievskaia &rpc_sysfs_xprt_change_state.attr,
418587bc725SOlga Kornievskaia NULL,
419587bc725SOlga Kornievskaia };
42086439fa2SGreg Kroah-Hartman ATTRIBUTE_GROUPS(rpc_sysfs_xprt);
421587bc725SOlga Kornievskaia
4220e559035SOlga Kornievskaia static struct kobj_attribute rpc_sysfs_xprt_switch_info =
4230e559035SOlga Kornievskaia __ATTR(xprt_switch_info, 0444, rpc_sysfs_xprt_switch_info_show, NULL);
4240e559035SOlga Kornievskaia
4250e559035SOlga Kornievskaia static struct attribute *rpc_sysfs_xprt_switch_attrs[] = {
4260e559035SOlga Kornievskaia &rpc_sysfs_xprt_switch_info.attr,
4270e559035SOlga Kornievskaia NULL,
4280e559035SOlga Kornievskaia };
42986439fa2SGreg Kroah-Hartman ATTRIBUTE_GROUPS(rpc_sysfs_xprt_switch);
4300e559035SOlga Kornievskaia
431d67307b4SThomas Weißschuh static const struct kobj_type rpc_sysfs_client_type = {
432c5a382ebSOlga Kornievskaia .release = rpc_sysfs_client_release,
433c5a382ebSOlga Kornievskaia .sysfs_ops = &kobj_sysfs_ops,
434c5a382ebSOlga Kornievskaia .namespace = rpc_sysfs_client_namespace,
435c5a382ebSOlga Kornievskaia };
436c5a382ebSOlga Kornievskaia
437d67307b4SThomas Weißschuh static const struct kobj_type rpc_sysfs_xprt_switch_type = {
438baea9944SOlga Kornievskaia .release = rpc_sysfs_xprt_switch_release,
43986439fa2SGreg Kroah-Hartman .default_groups = rpc_sysfs_xprt_switch_groups,
440baea9944SOlga Kornievskaia .sysfs_ops = &kobj_sysfs_ops,
441baea9944SOlga Kornievskaia .namespace = rpc_sysfs_xprt_switch_namespace,
442baea9944SOlga Kornievskaia };
443baea9944SOlga Kornievskaia
444d67307b4SThomas Weißschuh static const struct kobj_type rpc_sysfs_xprt_type = {
445d408ebe0SOlga Kornievskaia .release = rpc_sysfs_xprt_release,
44686439fa2SGreg Kroah-Hartman .default_groups = rpc_sysfs_xprt_groups,
447d408ebe0SOlga Kornievskaia .sysfs_ops = &kobj_sysfs_ops,
448d408ebe0SOlga Kornievskaia .namespace = rpc_sysfs_xprt_namespace,
449d408ebe0SOlga Kornievskaia };
450d408ebe0SOlga Kornievskaia
rpc_sysfs_exit(void)45174678748SOlga Kornievskaia void rpc_sysfs_exit(void)
45274678748SOlga Kornievskaia {
453c441f125SOlga Kornievskaia kobject_put(rpc_sunrpc_client_kobj);
454baea9944SOlga Kornievskaia kobject_put(rpc_sunrpc_xprt_switch_kobj);
45574678748SOlga Kornievskaia kset_unregister(rpc_sunrpc_kset);
45674678748SOlga Kornievskaia }
457c5a382ebSOlga Kornievskaia
rpc_sysfs_client_alloc(struct kobject * parent,struct net * net,int clid)458c5a382ebSOlga Kornievskaia static struct rpc_sysfs_client *rpc_sysfs_client_alloc(struct kobject *parent,
459c5a382ebSOlga Kornievskaia struct net *net,
460c5a382ebSOlga Kornievskaia int clid)
461c5a382ebSOlga Kornievskaia {
462c5a382ebSOlga Kornievskaia struct rpc_sysfs_client *p;
463c5a382ebSOlga Kornievskaia
464c5a382ebSOlga Kornievskaia p = kzalloc(sizeof(*p), GFP_KERNEL);
465c5a382ebSOlga Kornievskaia if (p) {
466c5a382ebSOlga Kornievskaia p->net = net;
467c5a382ebSOlga Kornievskaia p->kobject.kset = rpc_sunrpc_kset;
468c5a382ebSOlga Kornievskaia if (kobject_init_and_add(&p->kobject, &rpc_sysfs_client_type,
469c5a382ebSOlga Kornievskaia parent, "clnt-%d", clid) == 0)
470c5a382ebSOlga Kornievskaia return p;
471c5a382ebSOlga Kornievskaia kobject_put(&p->kobject);
472c5a382ebSOlga Kornievskaia }
473c5a382ebSOlga Kornievskaia return NULL;
474c5a382ebSOlga Kornievskaia }
475c5a382ebSOlga Kornievskaia
476baea9944SOlga Kornievskaia static struct rpc_sysfs_xprt_switch *
rpc_sysfs_xprt_switch_alloc(struct kobject * parent,struct rpc_xprt_switch * xprt_switch,struct net * net,gfp_t gfp_flags)477baea9944SOlga Kornievskaia rpc_sysfs_xprt_switch_alloc(struct kobject *parent,
478baea9944SOlga Kornievskaia struct rpc_xprt_switch *xprt_switch,
479baea9944SOlga Kornievskaia struct net *net,
480baea9944SOlga Kornievskaia gfp_t gfp_flags)
481baea9944SOlga Kornievskaia {
482baea9944SOlga Kornievskaia struct rpc_sysfs_xprt_switch *p;
483baea9944SOlga Kornievskaia
484baea9944SOlga Kornievskaia p = kzalloc(sizeof(*p), gfp_flags);
485baea9944SOlga Kornievskaia if (p) {
486baea9944SOlga Kornievskaia p->net = net;
487baea9944SOlga Kornievskaia p->kobject.kset = rpc_sunrpc_kset;
488baea9944SOlga Kornievskaia if (kobject_init_and_add(&p->kobject,
489baea9944SOlga Kornievskaia &rpc_sysfs_xprt_switch_type,
490baea9944SOlga Kornievskaia parent, "switch-%d",
491baea9944SOlga Kornievskaia xprt_switch->xps_id) == 0)
492baea9944SOlga Kornievskaia return p;
493baea9944SOlga Kornievskaia kobject_put(&p->kobject);
494baea9944SOlga Kornievskaia }
495baea9944SOlga Kornievskaia return NULL;
496baea9944SOlga Kornievskaia }
497baea9944SOlga Kornievskaia
rpc_sysfs_xprt_alloc(struct kobject * parent,struct rpc_xprt * xprt,gfp_t gfp_flags)498d408ebe0SOlga Kornievskaia static struct rpc_sysfs_xprt *rpc_sysfs_xprt_alloc(struct kobject *parent,
499d408ebe0SOlga Kornievskaia struct rpc_xprt *xprt,
500d408ebe0SOlga Kornievskaia gfp_t gfp_flags)
501d408ebe0SOlga Kornievskaia {
502d408ebe0SOlga Kornievskaia struct rpc_sysfs_xprt *p;
503d408ebe0SOlga Kornievskaia
504d408ebe0SOlga Kornievskaia p = kzalloc(sizeof(*p), gfp_flags);
505d408ebe0SOlga Kornievskaia if (!p)
506d408ebe0SOlga Kornievskaia goto out;
507d408ebe0SOlga Kornievskaia p->kobject.kset = rpc_sunrpc_kset;
508d408ebe0SOlga Kornievskaia if (kobject_init_and_add(&p->kobject, &rpc_sysfs_xprt_type,
509d408ebe0SOlga Kornievskaia parent, "xprt-%d-%s", xprt->id,
510d408ebe0SOlga Kornievskaia xprt->address_strings[RPC_DISPLAY_PROTO]) == 0)
511d408ebe0SOlga Kornievskaia return p;
512d408ebe0SOlga Kornievskaia kobject_put(&p->kobject);
513d408ebe0SOlga Kornievskaia out:
514d408ebe0SOlga Kornievskaia return NULL;
515d408ebe0SOlga Kornievskaia }
516d408ebe0SOlga Kornievskaia
rpc_sysfs_client_setup(struct rpc_clnt * clnt,struct rpc_xprt_switch * xprt_switch,struct net * net)5172a338a54SOlga Kornievskaia void rpc_sysfs_client_setup(struct rpc_clnt *clnt,
5182a338a54SOlga Kornievskaia struct rpc_xprt_switch *xprt_switch,
5192a338a54SOlga Kornievskaia struct net *net)
520c5a382ebSOlga Kornievskaia {
521c5a382ebSOlga Kornievskaia struct rpc_sysfs_client *rpc_client;
522cbdeaee9SZhang Xiaoxu struct rpc_sysfs_xprt_switch *xswitch =
523cbdeaee9SZhang Xiaoxu (struct rpc_sysfs_xprt_switch *)xprt_switch->xps_sysfs;
524cbdeaee9SZhang Xiaoxu
525cbdeaee9SZhang Xiaoxu if (!xswitch)
526cbdeaee9SZhang Xiaoxu return;
527c5a382ebSOlga Kornievskaia
5282a338a54SOlga Kornievskaia rpc_client = rpc_sysfs_client_alloc(rpc_sunrpc_client_kobj,
5292a338a54SOlga Kornievskaia net, clnt->cl_clid);
530c5a382ebSOlga Kornievskaia if (rpc_client) {
5312a338a54SOlga Kornievskaia char name[] = "switch";
5322a338a54SOlga Kornievskaia int ret;
5332a338a54SOlga Kornievskaia
534c5a382ebSOlga Kornievskaia clnt->cl_sysfs = rpc_client;
5352a338a54SOlga Kornievskaia rpc_client->clnt = clnt;
5362a338a54SOlga Kornievskaia rpc_client->xprt_switch = xprt_switch;
537c5a382ebSOlga Kornievskaia kobject_uevent(&rpc_client->kobject, KOBJ_ADD);
5382a338a54SOlga Kornievskaia ret = sysfs_create_link_nowarn(&rpc_client->kobject,
5392a338a54SOlga Kornievskaia &xswitch->kobject, name);
5402a338a54SOlga Kornievskaia if (ret)
5412a338a54SOlga Kornievskaia pr_warn("can't create link to %s in sysfs (%d)\n",
5422a338a54SOlga Kornievskaia name, ret);
543c5a382ebSOlga Kornievskaia }
544c5a382ebSOlga Kornievskaia }
545c5a382ebSOlga Kornievskaia
rpc_sysfs_xprt_switch_setup(struct rpc_xprt_switch * xprt_switch,struct rpc_xprt * xprt,gfp_t gfp_flags)546baea9944SOlga Kornievskaia void rpc_sysfs_xprt_switch_setup(struct rpc_xprt_switch *xprt_switch,
547baea9944SOlga Kornievskaia struct rpc_xprt *xprt,
548baea9944SOlga Kornievskaia gfp_t gfp_flags)
549baea9944SOlga Kornievskaia {
550baea9944SOlga Kornievskaia struct rpc_sysfs_xprt_switch *rpc_xprt_switch;
551baea9944SOlga Kornievskaia struct net *net;
552baea9944SOlga Kornievskaia
553baea9944SOlga Kornievskaia if (xprt_switch->xps_net)
554baea9944SOlga Kornievskaia net = xprt_switch->xps_net;
555baea9944SOlga Kornievskaia else
556baea9944SOlga Kornievskaia net = xprt->xprt_net;
557baea9944SOlga Kornievskaia rpc_xprt_switch =
558baea9944SOlga Kornievskaia rpc_sysfs_xprt_switch_alloc(rpc_sunrpc_xprt_switch_kobj,
559baea9944SOlga Kornievskaia xprt_switch, net, gfp_flags);
560baea9944SOlga Kornievskaia if (rpc_xprt_switch) {
561baea9944SOlga Kornievskaia xprt_switch->xps_sysfs = rpc_xprt_switch;
562baea9944SOlga Kornievskaia rpc_xprt_switch->xprt_switch = xprt_switch;
563baea9944SOlga Kornievskaia rpc_xprt_switch->xprt = xprt;
564baea9944SOlga Kornievskaia kobject_uevent(&rpc_xprt_switch->kobject, KOBJ_ADD);
565cbdeaee9SZhang Xiaoxu } else {
566cbdeaee9SZhang Xiaoxu xprt_switch->xps_sysfs = NULL;
567baea9944SOlga Kornievskaia }
568baea9944SOlga Kornievskaia }
569baea9944SOlga Kornievskaia
rpc_sysfs_xprt_setup(struct rpc_xprt_switch * xprt_switch,struct rpc_xprt * xprt,gfp_t gfp_flags)570d408ebe0SOlga Kornievskaia void rpc_sysfs_xprt_setup(struct rpc_xprt_switch *xprt_switch,
571d408ebe0SOlga Kornievskaia struct rpc_xprt *xprt,
572d408ebe0SOlga Kornievskaia gfp_t gfp_flags)
573d408ebe0SOlga Kornievskaia {
574d408ebe0SOlga Kornievskaia struct rpc_sysfs_xprt *rpc_xprt;
575d408ebe0SOlga Kornievskaia struct rpc_sysfs_xprt_switch *switch_obj =
576d408ebe0SOlga Kornievskaia (struct rpc_sysfs_xprt_switch *)xprt_switch->xps_sysfs;
577d408ebe0SOlga Kornievskaia
578cbdeaee9SZhang Xiaoxu if (!switch_obj)
579cbdeaee9SZhang Xiaoxu return;
580cbdeaee9SZhang Xiaoxu
581d408ebe0SOlga Kornievskaia rpc_xprt = rpc_sysfs_xprt_alloc(&switch_obj->kobject, xprt, gfp_flags);
582d408ebe0SOlga Kornievskaia if (rpc_xprt) {
583d408ebe0SOlga Kornievskaia xprt->xprt_sysfs = rpc_xprt;
584d408ebe0SOlga Kornievskaia rpc_xprt->xprt = xprt;
5855b7eb784SOlga Kornievskaia rpc_xprt->xprt_switch = xprt_switch;
586d408ebe0SOlga Kornievskaia kobject_uevent(&rpc_xprt->kobject, KOBJ_ADD);
587d408ebe0SOlga Kornievskaia }
588d408ebe0SOlga Kornievskaia }
589d408ebe0SOlga Kornievskaia
rpc_sysfs_client_destroy(struct rpc_clnt * clnt)590c5a382ebSOlga Kornievskaia void rpc_sysfs_client_destroy(struct rpc_clnt *clnt)
591c5a382ebSOlga Kornievskaia {
592c5a382ebSOlga Kornievskaia struct rpc_sysfs_client *rpc_client = clnt->cl_sysfs;
593c5a382ebSOlga Kornievskaia
594c5a382ebSOlga Kornievskaia if (rpc_client) {
5952a338a54SOlga Kornievskaia char name[] = "switch";
5962a338a54SOlga Kornievskaia
5972a338a54SOlga Kornievskaia sysfs_remove_link(&rpc_client->kobject, name);
598c5a382ebSOlga Kornievskaia kobject_uevent(&rpc_client->kobject, KOBJ_REMOVE);
599c5a382ebSOlga Kornievskaia kobject_del(&rpc_client->kobject);
600c5a382ebSOlga Kornievskaia kobject_put(&rpc_client->kobject);
601c5a382ebSOlga Kornievskaia clnt->cl_sysfs = NULL;
602c5a382ebSOlga Kornievskaia }
603c5a382ebSOlga Kornievskaia }
604baea9944SOlga Kornievskaia
rpc_sysfs_xprt_switch_destroy(struct rpc_xprt_switch * xprt_switch)605baea9944SOlga Kornievskaia void rpc_sysfs_xprt_switch_destroy(struct rpc_xprt_switch *xprt_switch)
606baea9944SOlga Kornievskaia {
607baea9944SOlga Kornievskaia struct rpc_sysfs_xprt_switch *rpc_xprt_switch = xprt_switch->xps_sysfs;
608baea9944SOlga Kornievskaia
609baea9944SOlga Kornievskaia if (rpc_xprt_switch) {
610baea9944SOlga Kornievskaia kobject_uevent(&rpc_xprt_switch->kobject, KOBJ_REMOVE);
611baea9944SOlga Kornievskaia kobject_del(&rpc_xprt_switch->kobject);
612baea9944SOlga Kornievskaia kobject_put(&rpc_xprt_switch->kobject);
613baea9944SOlga Kornievskaia xprt_switch->xps_sysfs = NULL;
614baea9944SOlga Kornievskaia }
615baea9944SOlga Kornievskaia }
616d408ebe0SOlga Kornievskaia
rpc_sysfs_xprt_destroy(struct rpc_xprt * xprt)617d408ebe0SOlga Kornievskaia void rpc_sysfs_xprt_destroy(struct rpc_xprt *xprt)
618d408ebe0SOlga Kornievskaia {
619d408ebe0SOlga Kornievskaia struct rpc_sysfs_xprt *rpc_xprt = xprt->xprt_sysfs;
620d408ebe0SOlga Kornievskaia
621d408ebe0SOlga Kornievskaia if (rpc_xprt) {
622d408ebe0SOlga Kornievskaia kobject_uevent(&rpc_xprt->kobject, KOBJ_REMOVE);
623d408ebe0SOlga Kornievskaia kobject_del(&rpc_xprt->kobject);
624d408ebe0SOlga Kornievskaia kobject_put(&rpc_xprt->kobject);
625d408ebe0SOlga Kornievskaia xprt->xprt_sysfs = NULL;
626d408ebe0SOlga Kornievskaia }
627d408ebe0SOlga Kornievskaia }
628