xref: /openbmc/linux/net/sunrpc/sysfs.c (revision c1830a63)
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 
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 
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 *
34c441f125SOlga Kornievskaia rpc_sysfs_object_child_ns_type(struct kobject *kobj)
35c441f125SOlga Kornievskaia {
36c441f125SOlga Kornievskaia 	return &net_ns_type_operations;
37c441f125SOlga Kornievskaia }
38c441f125SOlga Kornievskaia 
39c441f125SOlga Kornievskaia static 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 
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 *
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 *
720e559035SOlga Kornievskaia rpc_sysfs_xprt_switch_kobj_get_xprt(struct kobject *kobj)
730e559035SOlga Kornievskaia {
740e559035SOlga Kornievskaia 	struct rpc_sysfs_xprt_switch *x = container_of(kobj,
750e559035SOlga Kornievskaia 		struct rpc_sysfs_xprt_switch, kobject);
760e559035SOlga Kornievskaia 
770e559035SOlga Kornievskaia 	return xprt_switch_get(x->xprt_switch);
780e559035SOlga Kornievskaia }
790e559035SOlga Kornievskaia 
80587bc725SOlga Kornievskaia static ssize_t rpc_sysfs_xprt_dstaddr_show(struct kobject *kobj,
81587bc725SOlga Kornievskaia 					   struct kobj_attribute *attr,
82587bc725SOlga Kornievskaia 					   char *buf)
83587bc725SOlga Kornievskaia {
84587bc725SOlga Kornievskaia 	struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
85587bc725SOlga Kornievskaia 	ssize_t ret;
86587bc725SOlga Kornievskaia 
87587bc725SOlga Kornievskaia 	if (!xprt)
88587bc725SOlga Kornievskaia 		return 0;
89587bc725SOlga Kornievskaia 	ret = sprintf(buf, "%s\n", xprt->address_strings[RPC_DISPLAY_ADDR]);
90587bc725SOlga Kornievskaia 	xprt_put(xprt);
91587bc725SOlga Kornievskaia 	return ret + 1;
92587bc725SOlga Kornievskaia }
93587bc725SOlga Kornievskaia 
944a09651aSOlga Kornievskaia static ssize_t rpc_sysfs_xprt_info_show(struct kobject *kobj,
954a09651aSOlga Kornievskaia 					struct kobj_attribute *attr,
964a09651aSOlga Kornievskaia 					char *buf)
974a09651aSOlga Kornievskaia {
984a09651aSOlga Kornievskaia 	struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
994a09651aSOlga Kornievskaia 	ssize_t ret;
1004a09651aSOlga Kornievskaia 
1014a09651aSOlga Kornievskaia 	if (!xprt)
1024a09651aSOlga Kornievskaia 		return 0;
1034a09651aSOlga Kornievskaia 
1044a09651aSOlga Kornievskaia 	ret = sprintf(buf, "last_used=%lu\ncur_cong=%lu\ncong_win=%lu\n"
1054a09651aSOlga Kornievskaia 		       "max_num_slots=%u\nmin_num_slots=%u\nnum_reqs=%u\n"
1064a09651aSOlga Kornievskaia 		       "binding_q_len=%u\nsending_q_len=%u\npending_q_len=%u\n"
107c1830a63SOlga Kornievskaia 		       "backlog_q_len=%u\nmain_xprt=%d\nsrc_port=%u\n",
108c1830a63SOlga Kornievskaia 		       xprt->last_used, xprt->cong, xprt->cwnd, xprt->max_reqs,
109c1830a63SOlga Kornievskaia 		       xprt->min_reqs, xprt->num_reqs, xprt->binding.qlen,
110c1830a63SOlga Kornievskaia 		       xprt->sending.qlen, xprt->pending.qlen,
111c1830a63SOlga Kornievskaia 		       xprt->backlog.qlen, xprt->main,
112c1830a63SOlga Kornievskaia 		       (xprt->xprt_class->ident == XPRT_TRANSPORT_TCP) ?
113c1830a63SOlga Kornievskaia 		       get_srcport(xprt) : 0);
1144a09651aSOlga Kornievskaia 	xprt_put(xprt);
1154a09651aSOlga Kornievskaia 	return ret + 1;
1164a09651aSOlga Kornievskaia }
1174a09651aSOlga Kornievskaia 
118*681d5699SOlga Kornievskaia static ssize_t rpc_sysfs_xprt_state_show(struct kobject *kobj,
119*681d5699SOlga Kornievskaia 					 struct kobj_attribute *attr,
120*681d5699SOlga Kornievskaia 					 char *buf)
121*681d5699SOlga Kornievskaia {
122*681d5699SOlga Kornievskaia 	struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
123*681d5699SOlga Kornievskaia 	ssize_t ret;
124*681d5699SOlga Kornievskaia 	int locked, connected, connecting, close_wait, bound, binding,
125*681d5699SOlga Kornievskaia 	    closing, congested, cwnd_wait, write_space;
126*681d5699SOlga Kornievskaia 
127*681d5699SOlga Kornievskaia 	if (!xprt)
128*681d5699SOlga Kornievskaia 		return 0;
129*681d5699SOlga Kornievskaia 
130*681d5699SOlga Kornievskaia 	if (!xprt->state) {
131*681d5699SOlga Kornievskaia 		ret = sprintf(buf, "state=CLOSED\n");
132*681d5699SOlga Kornievskaia 	} else {
133*681d5699SOlga Kornievskaia 		locked = test_bit(XPRT_LOCKED, &xprt->state);
134*681d5699SOlga Kornievskaia 		connected = test_bit(XPRT_CONNECTED, &xprt->state);
135*681d5699SOlga Kornievskaia 		connecting = test_bit(XPRT_CONNECTING, &xprt->state);
136*681d5699SOlga Kornievskaia 		close_wait = test_bit(XPRT_CLOSE_WAIT, &xprt->state);
137*681d5699SOlga Kornievskaia 		bound = test_bit(XPRT_BOUND, &xprt->state);
138*681d5699SOlga Kornievskaia 		binding = test_bit(XPRT_BINDING, &xprt->state);
139*681d5699SOlga Kornievskaia 		closing = test_bit(XPRT_CLOSING, &xprt->state);
140*681d5699SOlga Kornievskaia 		congested = test_bit(XPRT_CONGESTED, &xprt->state);
141*681d5699SOlga Kornievskaia 		cwnd_wait = test_bit(XPRT_CWND_WAIT, &xprt->state);
142*681d5699SOlga Kornievskaia 		write_space = test_bit(XPRT_WRITE_SPACE, &xprt->state);
143*681d5699SOlga Kornievskaia 
144*681d5699SOlga Kornievskaia 		ret = sprintf(buf, "state=%s %s %s %s %s %s %s %s %s %s\n",
145*681d5699SOlga Kornievskaia 			      locked ? "LOCKED" : "",
146*681d5699SOlga Kornievskaia 			      connected ? "CONNECTED" : "",
147*681d5699SOlga Kornievskaia 			      connecting ? "CONNECTING" : "",
148*681d5699SOlga Kornievskaia 			      close_wait ? "CLOSE_WAIT" : "",
149*681d5699SOlga Kornievskaia 			      bound ? "BOUND" : "",
150*681d5699SOlga Kornievskaia 			      binding ? "BOUNDING" : "",
151*681d5699SOlga Kornievskaia 			      closing ? "CLOSING" : "",
152*681d5699SOlga Kornievskaia 			      congested ? "CONGESTED" : "",
153*681d5699SOlga Kornievskaia 			      cwnd_wait ? "CWND_WAIT" : "",
154*681d5699SOlga Kornievskaia 			      write_space ? "WRITE_SPACE" : "");
155*681d5699SOlga Kornievskaia 	}
156*681d5699SOlga Kornievskaia 
157*681d5699SOlga Kornievskaia 	xprt_put(xprt);
158*681d5699SOlga Kornievskaia 	return ret + 1;
159*681d5699SOlga Kornievskaia }
160*681d5699SOlga Kornievskaia 
1610e559035SOlga Kornievskaia static ssize_t rpc_sysfs_xprt_switch_info_show(struct kobject *kobj,
1620e559035SOlga Kornievskaia 					       struct kobj_attribute *attr,
1630e559035SOlga Kornievskaia 					       char *buf)
1640e559035SOlga Kornievskaia {
1650e559035SOlga Kornievskaia 	struct rpc_xprt_switch *xprt_switch =
1660e559035SOlga Kornievskaia 		rpc_sysfs_xprt_switch_kobj_get_xprt(kobj);
1670e559035SOlga Kornievskaia 	ssize_t ret;
1680e559035SOlga Kornievskaia 
1690e559035SOlga Kornievskaia 	if (!xprt_switch)
1700e559035SOlga Kornievskaia 		return 0;
1710e559035SOlga Kornievskaia 	ret = sprintf(buf, "num_xprts=%u\nnum_active=%u\nqueue_len=%ld\n",
1720e559035SOlga Kornievskaia 		      xprt_switch->xps_nxprts, xprt_switch->xps_nactive,
1730e559035SOlga Kornievskaia 		      atomic_long_read(&xprt_switch->xps_queuelen));
1740e559035SOlga Kornievskaia 	xprt_switch_put(xprt_switch);
1750e559035SOlga Kornievskaia 	return ret + 1;
1760e559035SOlga Kornievskaia }
1770e559035SOlga Kornievskaia 
178587bc725SOlga Kornievskaia static ssize_t rpc_sysfs_xprt_dstaddr_store(struct kobject *kobj,
179587bc725SOlga Kornievskaia 					    struct kobj_attribute *attr,
180587bc725SOlga Kornievskaia 					    const char *buf, size_t count)
181587bc725SOlga Kornievskaia {
182587bc725SOlga Kornievskaia 	struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
183587bc725SOlga Kornievskaia 	struct sockaddr *saddr;
184587bc725SOlga Kornievskaia 	char *dst_addr;
185587bc725SOlga Kornievskaia 	int port;
186587bc725SOlga Kornievskaia 	struct xprt_addr *saved_addr;
187587bc725SOlga Kornievskaia 	size_t buf_len;
188587bc725SOlga Kornievskaia 
189587bc725SOlga Kornievskaia 	if (!xprt)
190587bc725SOlga Kornievskaia 		return 0;
191587bc725SOlga Kornievskaia 	if (!(xprt->xprt_class->ident == XPRT_TRANSPORT_TCP ||
192587bc725SOlga Kornievskaia 	      xprt->xprt_class->ident == XPRT_TRANSPORT_RDMA)) {
193587bc725SOlga Kornievskaia 		xprt_put(xprt);
194587bc725SOlga Kornievskaia 		return -EOPNOTSUPP;
195587bc725SOlga Kornievskaia 	}
196587bc725SOlga Kornievskaia 
197587bc725SOlga Kornievskaia 	if (wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_KILLABLE)) {
198587bc725SOlga Kornievskaia 		count = -EINTR;
199587bc725SOlga Kornievskaia 		goto out_put;
200587bc725SOlga Kornievskaia 	}
201587bc725SOlga Kornievskaia 	saddr = (struct sockaddr *)&xprt->addr;
202587bc725SOlga Kornievskaia 	port = rpc_get_port(saddr);
203587bc725SOlga Kornievskaia 
204587bc725SOlga Kornievskaia 	/* buf_len is the len until the first occurence of either
205587bc725SOlga Kornievskaia 	 * '\n' or '\0'
206587bc725SOlga Kornievskaia 	 */
207587bc725SOlga Kornievskaia 	buf_len = strcspn(buf, "\n");
208587bc725SOlga Kornievskaia 
209587bc725SOlga Kornievskaia 	dst_addr = kstrndup(buf, buf_len, GFP_KERNEL);
210587bc725SOlga Kornievskaia 	if (!dst_addr)
211587bc725SOlga Kornievskaia 		goto out_err;
212587bc725SOlga Kornievskaia 	saved_addr = kzalloc(sizeof(*saved_addr), GFP_KERNEL);
213587bc725SOlga Kornievskaia 	if (!saved_addr)
214587bc725SOlga Kornievskaia 		goto out_err_free;
215587bc725SOlga Kornievskaia 	saved_addr->addr =
216587bc725SOlga Kornievskaia 		rcu_dereference_raw(xprt->address_strings[RPC_DISPLAY_ADDR]);
217587bc725SOlga Kornievskaia 	rcu_assign_pointer(xprt->address_strings[RPC_DISPLAY_ADDR], dst_addr);
218587bc725SOlga Kornievskaia 	call_rcu(&saved_addr->rcu, free_xprt_addr);
219587bc725SOlga Kornievskaia 	xprt->addrlen = rpc_pton(xprt->xprt_net, buf, buf_len, saddr,
220587bc725SOlga Kornievskaia 				 sizeof(*saddr));
221587bc725SOlga Kornievskaia 	rpc_set_port(saddr, port);
222587bc725SOlga Kornievskaia 
223587bc725SOlga Kornievskaia 	xprt_force_disconnect(xprt);
224587bc725SOlga Kornievskaia out:
225587bc725SOlga Kornievskaia 	xprt_release_write(xprt, NULL);
226587bc725SOlga Kornievskaia out_put:
227587bc725SOlga Kornievskaia 	xprt_put(xprt);
228587bc725SOlga Kornievskaia 	return count;
229587bc725SOlga Kornievskaia out_err_free:
230587bc725SOlga Kornievskaia 	kfree(dst_addr);
231587bc725SOlga Kornievskaia out_err:
232587bc725SOlga Kornievskaia 	count = -ENOMEM;
233587bc725SOlga Kornievskaia 	goto out;
234587bc725SOlga Kornievskaia }
235587bc725SOlga Kornievskaia 
23674678748SOlga Kornievskaia int rpc_sysfs_init(void)
23774678748SOlga Kornievskaia {
23874678748SOlga Kornievskaia 	rpc_sunrpc_kset = kset_create_and_add("sunrpc", NULL, kernel_kobj);
23974678748SOlga Kornievskaia 	if (!rpc_sunrpc_kset)
24074678748SOlga Kornievskaia 		return -ENOMEM;
241baea9944SOlga Kornievskaia 	rpc_sunrpc_client_kobj =
242baea9944SOlga Kornievskaia 		rpc_sysfs_object_alloc("rpc-clients", rpc_sunrpc_kset, NULL);
243baea9944SOlga Kornievskaia 	if (!rpc_sunrpc_client_kobj)
244baea9944SOlga Kornievskaia 		goto err_client;
245baea9944SOlga Kornievskaia 	rpc_sunrpc_xprt_switch_kobj =
246baea9944SOlga Kornievskaia 		rpc_sysfs_object_alloc("xprt-switches", rpc_sunrpc_kset, NULL);
247baea9944SOlga Kornievskaia 	if (!rpc_sunrpc_xprt_switch_kobj)
248baea9944SOlga Kornievskaia 		goto err_switch;
24974678748SOlga Kornievskaia 	return 0;
250baea9944SOlga Kornievskaia err_switch:
251baea9944SOlga Kornievskaia 	kobject_put(rpc_sunrpc_client_kobj);
252baea9944SOlga Kornievskaia 	rpc_sunrpc_client_kobj = NULL;
253baea9944SOlga Kornievskaia err_client:
254baea9944SOlga Kornievskaia 	kset_unregister(rpc_sunrpc_kset);
255baea9944SOlga Kornievskaia 	rpc_sunrpc_kset = NULL;
256baea9944SOlga Kornievskaia 	return -ENOMEM;
25774678748SOlga Kornievskaia }
25874678748SOlga Kornievskaia 
259c5a382ebSOlga Kornievskaia static void rpc_sysfs_client_release(struct kobject *kobj)
260c5a382ebSOlga Kornievskaia {
261c5a382ebSOlga Kornievskaia 	struct rpc_sysfs_client *c;
262c5a382ebSOlga Kornievskaia 
263c5a382ebSOlga Kornievskaia 	c = container_of(kobj, struct rpc_sysfs_client, kobject);
264c5a382ebSOlga Kornievskaia 	kfree(c);
265c5a382ebSOlga Kornievskaia }
266c5a382ebSOlga Kornievskaia 
267baea9944SOlga Kornievskaia static void rpc_sysfs_xprt_switch_release(struct kobject *kobj)
268baea9944SOlga Kornievskaia {
269baea9944SOlga Kornievskaia 	struct rpc_sysfs_xprt_switch *xprt_switch;
270baea9944SOlga Kornievskaia 
271baea9944SOlga Kornievskaia 	xprt_switch = container_of(kobj, struct rpc_sysfs_xprt_switch, kobject);
272baea9944SOlga Kornievskaia 	kfree(xprt_switch);
273baea9944SOlga Kornievskaia }
274baea9944SOlga Kornievskaia 
275d408ebe0SOlga Kornievskaia static void rpc_sysfs_xprt_release(struct kobject *kobj)
276d408ebe0SOlga Kornievskaia {
277d408ebe0SOlga Kornievskaia 	struct rpc_sysfs_xprt *xprt;
278d408ebe0SOlga Kornievskaia 
279d408ebe0SOlga Kornievskaia 	xprt = container_of(kobj, struct rpc_sysfs_xprt, kobject);
280d408ebe0SOlga Kornievskaia 	kfree(xprt);
281d408ebe0SOlga Kornievskaia }
282d408ebe0SOlga Kornievskaia 
283c5a382ebSOlga Kornievskaia static const void *rpc_sysfs_client_namespace(struct kobject *kobj)
284c5a382ebSOlga Kornievskaia {
285c5a382ebSOlga Kornievskaia 	return container_of(kobj, struct rpc_sysfs_client, kobject)->net;
286c5a382ebSOlga Kornievskaia }
287c5a382ebSOlga Kornievskaia 
288baea9944SOlga Kornievskaia static const void *rpc_sysfs_xprt_switch_namespace(struct kobject *kobj)
289baea9944SOlga Kornievskaia {
290baea9944SOlga Kornievskaia 	return container_of(kobj, struct rpc_sysfs_xprt_switch, kobject)->net;
291baea9944SOlga Kornievskaia }
292baea9944SOlga Kornievskaia 
293d408ebe0SOlga Kornievskaia static const void *rpc_sysfs_xprt_namespace(struct kobject *kobj)
294d408ebe0SOlga Kornievskaia {
295d408ebe0SOlga Kornievskaia 	return container_of(kobj, struct rpc_sysfs_xprt,
296d408ebe0SOlga Kornievskaia 			    kobject)->xprt->xprt_net;
297d408ebe0SOlga Kornievskaia }
298d408ebe0SOlga Kornievskaia 
299587bc725SOlga Kornievskaia static struct kobj_attribute rpc_sysfs_xprt_dstaddr = __ATTR(dstaddr,
300587bc725SOlga Kornievskaia 	0644, rpc_sysfs_xprt_dstaddr_show, rpc_sysfs_xprt_dstaddr_store);
301587bc725SOlga Kornievskaia 
3024a09651aSOlga Kornievskaia static struct kobj_attribute rpc_sysfs_xprt_info = __ATTR(xprt_info,
3034a09651aSOlga Kornievskaia 	0444, rpc_sysfs_xprt_info_show, NULL);
3044a09651aSOlga Kornievskaia 
305*681d5699SOlga Kornievskaia static struct kobj_attribute rpc_sysfs_xprt_change_state = __ATTR(xprt_state,
306*681d5699SOlga Kornievskaia 	0644, rpc_sysfs_xprt_state_show, NULL);
307*681d5699SOlga Kornievskaia 
308587bc725SOlga Kornievskaia static struct attribute *rpc_sysfs_xprt_attrs[] = {
309587bc725SOlga Kornievskaia 	&rpc_sysfs_xprt_dstaddr.attr,
3104a09651aSOlga Kornievskaia 	&rpc_sysfs_xprt_info.attr,
311*681d5699SOlga Kornievskaia 	&rpc_sysfs_xprt_change_state.attr,
312587bc725SOlga Kornievskaia 	NULL,
313587bc725SOlga Kornievskaia };
314587bc725SOlga Kornievskaia 
3150e559035SOlga Kornievskaia static struct kobj_attribute rpc_sysfs_xprt_switch_info =
3160e559035SOlga Kornievskaia 	__ATTR(xprt_switch_info, 0444, rpc_sysfs_xprt_switch_info_show, NULL);
3170e559035SOlga Kornievskaia 
3180e559035SOlga Kornievskaia static struct attribute *rpc_sysfs_xprt_switch_attrs[] = {
3190e559035SOlga Kornievskaia 	&rpc_sysfs_xprt_switch_info.attr,
3200e559035SOlga Kornievskaia 	NULL,
3210e559035SOlga Kornievskaia };
3220e559035SOlga Kornievskaia 
323c5a382ebSOlga Kornievskaia static struct kobj_type rpc_sysfs_client_type = {
324c5a382ebSOlga Kornievskaia 	.release = rpc_sysfs_client_release,
325c5a382ebSOlga Kornievskaia 	.sysfs_ops = &kobj_sysfs_ops,
326c5a382ebSOlga Kornievskaia 	.namespace = rpc_sysfs_client_namespace,
327c5a382ebSOlga Kornievskaia };
328c5a382ebSOlga Kornievskaia 
329baea9944SOlga Kornievskaia static struct kobj_type rpc_sysfs_xprt_switch_type = {
330baea9944SOlga Kornievskaia 	.release = rpc_sysfs_xprt_switch_release,
3310e559035SOlga Kornievskaia 	.default_attrs = rpc_sysfs_xprt_switch_attrs,
332baea9944SOlga Kornievskaia 	.sysfs_ops = &kobj_sysfs_ops,
333baea9944SOlga Kornievskaia 	.namespace = rpc_sysfs_xprt_switch_namespace,
334baea9944SOlga Kornievskaia };
335baea9944SOlga Kornievskaia 
336d408ebe0SOlga Kornievskaia static struct kobj_type rpc_sysfs_xprt_type = {
337d408ebe0SOlga Kornievskaia 	.release = rpc_sysfs_xprt_release,
338587bc725SOlga Kornievskaia 	.default_attrs = rpc_sysfs_xprt_attrs,
339d408ebe0SOlga Kornievskaia 	.sysfs_ops = &kobj_sysfs_ops,
340d408ebe0SOlga Kornievskaia 	.namespace = rpc_sysfs_xprt_namespace,
341d408ebe0SOlga Kornievskaia };
342d408ebe0SOlga Kornievskaia 
34374678748SOlga Kornievskaia void rpc_sysfs_exit(void)
34474678748SOlga Kornievskaia {
345c441f125SOlga Kornievskaia 	kobject_put(rpc_sunrpc_client_kobj);
346baea9944SOlga Kornievskaia 	kobject_put(rpc_sunrpc_xprt_switch_kobj);
34774678748SOlga Kornievskaia 	kset_unregister(rpc_sunrpc_kset);
34874678748SOlga Kornievskaia }
349c5a382ebSOlga Kornievskaia 
350c5a382ebSOlga Kornievskaia static struct rpc_sysfs_client *rpc_sysfs_client_alloc(struct kobject *parent,
351c5a382ebSOlga Kornievskaia 						       struct net *net,
352c5a382ebSOlga Kornievskaia 						       int clid)
353c5a382ebSOlga Kornievskaia {
354c5a382ebSOlga Kornievskaia 	struct rpc_sysfs_client *p;
355c5a382ebSOlga Kornievskaia 
356c5a382ebSOlga Kornievskaia 	p = kzalloc(sizeof(*p), GFP_KERNEL);
357c5a382ebSOlga Kornievskaia 	if (p) {
358c5a382ebSOlga Kornievskaia 		p->net = net;
359c5a382ebSOlga Kornievskaia 		p->kobject.kset = rpc_sunrpc_kset;
360c5a382ebSOlga Kornievskaia 		if (kobject_init_and_add(&p->kobject, &rpc_sysfs_client_type,
361c5a382ebSOlga Kornievskaia 					 parent, "clnt-%d", clid) == 0)
362c5a382ebSOlga Kornievskaia 			return p;
363c5a382ebSOlga Kornievskaia 		kobject_put(&p->kobject);
364c5a382ebSOlga Kornievskaia 	}
365c5a382ebSOlga Kornievskaia 	return NULL;
366c5a382ebSOlga Kornievskaia }
367c5a382ebSOlga Kornievskaia 
368baea9944SOlga Kornievskaia static struct rpc_sysfs_xprt_switch *
369baea9944SOlga Kornievskaia rpc_sysfs_xprt_switch_alloc(struct kobject *parent,
370baea9944SOlga Kornievskaia 			    struct rpc_xprt_switch *xprt_switch,
371baea9944SOlga Kornievskaia 			    struct net *net,
372baea9944SOlga Kornievskaia 			    gfp_t gfp_flags)
373baea9944SOlga Kornievskaia {
374baea9944SOlga Kornievskaia 	struct rpc_sysfs_xprt_switch *p;
375baea9944SOlga Kornievskaia 
376baea9944SOlga Kornievskaia 	p = kzalloc(sizeof(*p), gfp_flags);
377baea9944SOlga Kornievskaia 	if (p) {
378baea9944SOlga Kornievskaia 		p->net = net;
379baea9944SOlga Kornievskaia 		p->kobject.kset = rpc_sunrpc_kset;
380baea9944SOlga Kornievskaia 		if (kobject_init_and_add(&p->kobject,
381baea9944SOlga Kornievskaia 					 &rpc_sysfs_xprt_switch_type,
382baea9944SOlga Kornievskaia 					 parent, "switch-%d",
383baea9944SOlga Kornievskaia 					 xprt_switch->xps_id) == 0)
384baea9944SOlga Kornievskaia 			return p;
385baea9944SOlga Kornievskaia 		kobject_put(&p->kobject);
386baea9944SOlga Kornievskaia 	}
387baea9944SOlga Kornievskaia 	return NULL;
388baea9944SOlga Kornievskaia }
389baea9944SOlga Kornievskaia 
390d408ebe0SOlga Kornievskaia static struct rpc_sysfs_xprt *rpc_sysfs_xprt_alloc(struct kobject *parent,
391d408ebe0SOlga Kornievskaia 						   struct rpc_xprt *xprt,
392d408ebe0SOlga Kornievskaia 						   gfp_t gfp_flags)
393d408ebe0SOlga Kornievskaia {
394d408ebe0SOlga Kornievskaia 	struct rpc_sysfs_xprt *p;
395d408ebe0SOlga Kornievskaia 
396d408ebe0SOlga Kornievskaia 	p = kzalloc(sizeof(*p), gfp_flags);
397d408ebe0SOlga Kornievskaia 	if (!p)
398d408ebe0SOlga Kornievskaia 		goto out;
399d408ebe0SOlga Kornievskaia 	p->kobject.kset = rpc_sunrpc_kset;
400d408ebe0SOlga Kornievskaia 	if (kobject_init_and_add(&p->kobject, &rpc_sysfs_xprt_type,
401d408ebe0SOlga Kornievskaia 				 parent, "xprt-%d-%s", xprt->id,
402d408ebe0SOlga Kornievskaia 				 xprt->address_strings[RPC_DISPLAY_PROTO]) == 0)
403d408ebe0SOlga Kornievskaia 		return p;
404d408ebe0SOlga Kornievskaia 	kobject_put(&p->kobject);
405d408ebe0SOlga Kornievskaia out:
406d408ebe0SOlga Kornievskaia 	return NULL;
407d408ebe0SOlga Kornievskaia }
408d408ebe0SOlga Kornievskaia 
4092a338a54SOlga Kornievskaia void rpc_sysfs_client_setup(struct rpc_clnt *clnt,
4102a338a54SOlga Kornievskaia 			    struct rpc_xprt_switch *xprt_switch,
4112a338a54SOlga Kornievskaia 			    struct net *net)
412c5a382ebSOlga Kornievskaia {
413c5a382ebSOlga Kornievskaia 	struct rpc_sysfs_client *rpc_client;
414c5a382ebSOlga Kornievskaia 
4152a338a54SOlga Kornievskaia 	rpc_client = rpc_sysfs_client_alloc(rpc_sunrpc_client_kobj,
4162a338a54SOlga Kornievskaia 					    net, clnt->cl_clid);
417c5a382ebSOlga Kornievskaia 	if (rpc_client) {
4182a338a54SOlga Kornievskaia 		char name[] = "switch";
4192a338a54SOlga Kornievskaia 		struct rpc_sysfs_xprt_switch *xswitch =
4202a338a54SOlga Kornievskaia 			(struct rpc_sysfs_xprt_switch *)xprt_switch->xps_sysfs;
4212a338a54SOlga Kornievskaia 		int ret;
4222a338a54SOlga Kornievskaia 
423c5a382ebSOlga Kornievskaia 		clnt->cl_sysfs = rpc_client;
4242a338a54SOlga Kornievskaia 		rpc_client->clnt = clnt;
4252a338a54SOlga Kornievskaia 		rpc_client->xprt_switch = xprt_switch;
426c5a382ebSOlga Kornievskaia 		kobject_uevent(&rpc_client->kobject, KOBJ_ADD);
4272a338a54SOlga Kornievskaia 		ret = sysfs_create_link_nowarn(&rpc_client->kobject,
4282a338a54SOlga Kornievskaia 					       &xswitch->kobject, name);
4292a338a54SOlga Kornievskaia 		if (ret)
4302a338a54SOlga Kornievskaia 			pr_warn("can't create link to %s in sysfs (%d)\n",
4312a338a54SOlga Kornievskaia 				name, ret);
432c5a382ebSOlga Kornievskaia 	}
433c5a382ebSOlga Kornievskaia }
434c5a382ebSOlga Kornievskaia 
435baea9944SOlga Kornievskaia void rpc_sysfs_xprt_switch_setup(struct rpc_xprt_switch *xprt_switch,
436baea9944SOlga Kornievskaia 				 struct rpc_xprt *xprt,
437baea9944SOlga Kornievskaia 				 gfp_t gfp_flags)
438baea9944SOlga Kornievskaia {
439baea9944SOlga Kornievskaia 	struct rpc_sysfs_xprt_switch *rpc_xprt_switch;
440baea9944SOlga Kornievskaia 	struct net *net;
441baea9944SOlga Kornievskaia 
442baea9944SOlga Kornievskaia 	if (xprt_switch->xps_net)
443baea9944SOlga Kornievskaia 		net = xprt_switch->xps_net;
444baea9944SOlga Kornievskaia 	else
445baea9944SOlga Kornievskaia 		net = xprt->xprt_net;
446baea9944SOlga Kornievskaia 	rpc_xprt_switch =
447baea9944SOlga Kornievskaia 		rpc_sysfs_xprt_switch_alloc(rpc_sunrpc_xprt_switch_kobj,
448baea9944SOlga Kornievskaia 					    xprt_switch, net, gfp_flags);
449baea9944SOlga Kornievskaia 	if (rpc_xprt_switch) {
450baea9944SOlga Kornievskaia 		xprt_switch->xps_sysfs = rpc_xprt_switch;
451baea9944SOlga Kornievskaia 		rpc_xprt_switch->xprt_switch = xprt_switch;
452baea9944SOlga Kornievskaia 		rpc_xprt_switch->xprt = xprt;
453baea9944SOlga Kornievskaia 		kobject_uevent(&rpc_xprt_switch->kobject, KOBJ_ADD);
454baea9944SOlga Kornievskaia 	}
455baea9944SOlga Kornievskaia }
456baea9944SOlga Kornievskaia 
457d408ebe0SOlga Kornievskaia void rpc_sysfs_xprt_setup(struct rpc_xprt_switch *xprt_switch,
458d408ebe0SOlga Kornievskaia 			  struct rpc_xprt *xprt,
459d408ebe0SOlga Kornievskaia 			  gfp_t gfp_flags)
460d408ebe0SOlga Kornievskaia {
461d408ebe0SOlga Kornievskaia 	struct rpc_sysfs_xprt *rpc_xprt;
462d408ebe0SOlga Kornievskaia 	struct rpc_sysfs_xprt_switch *switch_obj =
463d408ebe0SOlga Kornievskaia 		(struct rpc_sysfs_xprt_switch *)xprt_switch->xps_sysfs;
464d408ebe0SOlga Kornievskaia 
465d408ebe0SOlga Kornievskaia 	rpc_xprt = rpc_sysfs_xprt_alloc(&switch_obj->kobject, xprt, gfp_flags);
466d408ebe0SOlga Kornievskaia 	if (rpc_xprt) {
467d408ebe0SOlga Kornievskaia 		xprt->xprt_sysfs = rpc_xprt;
468d408ebe0SOlga Kornievskaia 		rpc_xprt->xprt = xprt;
469d408ebe0SOlga Kornievskaia 		kobject_uevent(&rpc_xprt->kobject, KOBJ_ADD);
470d408ebe0SOlga Kornievskaia 	}
471d408ebe0SOlga Kornievskaia }
472d408ebe0SOlga Kornievskaia 
473c5a382ebSOlga Kornievskaia void rpc_sysfs_client_destroy(struct rpc_clnt *clnt)
474c5a382ebSOlga Kornievskaia {
475c5a382ebSOlga Kornievskaia 	struct rpc_sysfs_client *rpc_client = clnt->cl_sysfs;
476c5a382ebSOlga Kornievskaia 
477c5a382ebSOlga Kornievskaia 	if (rpc_client) {
4782a338a54SOlga Kornievskaia 		char name[] = "switch";
4792a338a54SOlga Kornievskaia 
4802a338a54SOlga Kornievskaia 		sysfs_remove_link(&rpc_client->kobject, name);
481c5a382ebSOlga Kornievskaia 		kobject_uevent(&rpc_client->kobject, KOBJ_REMOVE);
482c5a382ebSOlga Kornievskaia 		kobject_del(&rpc_client->kobject);
483c5a382ebSOlga Kornievskaia 		kobject_put(&rpc_client->kobject);
484c5a382ebSOlga Kornievskaia 		clnt->cl_sysfs = NULL;
485c5a382ebSOlga Kornievskaia 	}
486c5a382ebSOlga Kornievskaia }
487baea9944SOlga Kornievskaia 
488baea9944SOlga Kornievskaia void rpc_sysfs_xprt_switch_destroy(struct rpc_xprt_switch *xprt_switch)
489baea9944SOlga Kornievskaia {
490baea9944SOlga Kornievskaia 	struct rpc_sysfs_xprt_switch *rpc_xprt_switch = xprt_switch->xps_sysfs;
491baea9944SOlga Kornievskaia 
492baea9944SOlga Kornievskaia 	if (rpc_xprt_switch) {
493baea9944SOlga Kornievskaia 		kobject_uevent(&rpc_xprt_switch->kobject, KOBJ_REMOVE);
494baea9944SOlga Kornievskaia 		kobject_del(&rpc_xprt_switch->kobject);
495baea9944SOlga Kornievskaia 		kobject_put(&rpc_xprt_switch->kobject);
496baea9944SOlga Kornievskaia 		xprt_switch->xps_sysfs = NULL;
497baea9944SOlga Kornievskaia 	}
498baea9944SOlga Kornievskaia }
499d408ebe0SOlga Kornievskaia 
500d408ebe0SOlga Kornievskaia void rpc_sysfs_xprt_destroy(struct rpc_xprt *xprt)
501d408ebe0SOlga Kornievskaia {
502d408ebe0SOlga Kornievskaia 	struct rpc_sysfs_xprt *rpc_xprt = xprt->xprt_sysfs;
503d408ebe0SOlga Kornievskaia 
504d408ebe0SOlga Kornievskaia 	if (rpc_xprt) {
505d408ebe0SOlga Kornievskaia 		kobject_uevent(&rpc_xprt->kobject, KOBJ_REMOVE);
506d408ebe0SOlga Kornievskaia 		kobject_del(&rpc_xprt->kobject);
507d408ebe0SOlga Kornievskaia 		kobject_put(&rpc_xprt->kobject);
508d408ebe0SOlga Kornievskaia 		xprt->xprt_sysfs = NULL;
509d408ebe0SOlga Kornievskaia 	}
510d408ebe0SOlga Kornievskaia }
511