xref: /openbmc/linux/net/sunrpc/sysfs.c (revision 6f081693)
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 *
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 *
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 
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 
96587bc725SOlga Kornievskaia 	if (!xprt)
97587bc725SOlga Kornievskaia 		return 0;
98587bc725SOlga Kornievskaia 	ret = sprintf(buf, "%s\n", xprt->address_strings[RPC_DISPLAY_ADDR]);
99587bc725SOlga Kornievskaia 	xprt_put(xprt);
100587bc725SOlga Kornievskaia 	return ret + 1;
101587bc725SOlga Kornievskaia }
102587bc725SOlga Kornievskaia 
1034a09651aSOlga Kornievskaia static ssize_t rpc_sysfs_xprt_info_show(struct kobject *kobj,
1044a09651aSOlga Kornievskaia 					struct kobj_attribute *attr,
1054a09651aSOlga Kornievskaia 					char *buf)
1064a09651aSOlga Kornievskaia {
1074a09651aSOlga Kornievskaia 	struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
1084a09651aSOlga Kornievskaia 	ssize_t ret;
1094a09651aSOlga Kornievskaia 
1104a09651aSOlga Kornievskaia 	if (!xprt)
1114a09651aSOlga Kornievskaia 		return 0;
1124a09651aSOlga Kornievskaia 
1134a09651aSOlga Kornievskaia 	ret = sprintf(buf, "last_used=%lu\ncur_cong=%lu\ncong_win=%lu\n"
1144a09651aSOlga Kornievskaia 		       "max_num_slots=%u\nmin_num_slots=%u\nnum_reqs=%u\n"
1154a09651aSOlga Kornievskaia 		       "binding_q_len=%u\nsending_q_len=%u\npending_q_len=%u\n"
1166a284059SOlga Kornievskaia 		       "backlog_q_len=%u\nmain_xprt=%d\nsrc_port=%u\n"
1176a284059SOlga Kornievskaia 		       "tasks_queuelen=%ld\n",
118c1830a63SOlga Kornievskaia 		       xprt->last_used, xprt->cong, xprt->cwnd, xprt->max_reqs,
119c1830a63SOlga Kornievskaia 		       xprt->min_reqs, xprt->num_reqs, xprt->binding.qlen,
120c1830a63SOlga Kornievskaia 		       xprt->sending.qlen, xprt->pending.qlen,
121c1830a63SOlga Kornievskaia 		       xprt->backlog.qlen, xprt->main,
122c1830a63SOlga Kornievskaia 		       (xprt->xprt_class->ident == XPRT_TRANSPORT_TCP) ?
1236a284059SOlga Kornievskaia 		       get_srcport(xprt) : 0,
1246a284059SOlga Kornievskaia 		       atomic_long_read(&xprt->queuelen));
1254a09651aSOlga Kornievskaia 	xprt_put(xprt);
1264a09651aSOlga Kornievskaia 	return ret + 1;
1274a09651aSOlga Kornievskaia }
1284a09651aSOlga Kornievskaia 
129681d5699SOlga Kornievskaia static ssize_t rpc_sysfs_xprt_state_show(struct kobject *kobj,
130681d5699SOlga Kornievskaia 					 struct kobj_attribute *attr,
131681d5699SOlga Kornievskaia 					 char *buf)
132681d5699SOlga Kornievskaia {
133681d5699SOlga Kornievskaia 	struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
134681d5699SOlga Kornievskaia 	ssize_t ret;
135681d5699SOlga Kornievskaia 	int locked, connected, connecting, close_wait, bound, binding,
136*6f081693SOlga Kornievskaia 	    closing, congested, cwnd_wait, write_space, offline, remove;
137681d5699SOlga Kornievskaia 
138681d5699SOlga Kornievskaia 	if (!xprt)
139681d5699SOlga Kornievskaia 		return 0;
140681d5699SOlga Kornievskaia 
141681d5699SOlga Kornievskaia 	if (!xprt->state) {
142681d5699SOlga Kornievskaia 		ret = sprintf(buf, "state=CLOSED\n");
143681d5699SOlga Kornievskaia 	} else {
144681d5699SOlga Kornievskaia 		locked = test_bit(XPRT_LOCKED, &xprt->state);
145681d5699SOlga Kornievskaia 		connected = test_bit(XPRT_CONNECTED, &xprt->state);
146681d5699SOlga Kornievskaia 		connecting = test_bit(XPRT_CONNECTING, &xprt->state);
147681d5699SOlga Kornievskaia 		close_wait = test_bit(XPRT_CLOSE_WAIT, &xprt->state);
148681d5699SOlga Kornievskaia 		bound = test_bit(XPRT_BOUND, &xprt->state);
149681d5699SOlga Kornievskaia 		binding = test_bit(XPRT_BINDING, &xprt->state);
150681d5699SOlga Kornievskaia 		closing = test_bit(XPRT_CLOSING, &xprt->state);
151681d5699SOlga Kornievskaia 		congested = test_bit(XPRT_CONGESTED, &xprt->state);
152681d5699SOlga Kornievskaia 		cwnd_wait = test_bit(XPRT_CWND_WAIT, &xprt->state);
153681d5699SOlga Kornievskaia 		write_space = test_bit(XPRT_WRITE_SPACE, &xprt->state);
1545b7eb784SOlga Kornievskaia 		offline = test_bit(XPRT_OFFLINE, &xprt->state);
155*6f081693SOlga Kornievskaia 		remove = test_bit(XPRT_REMOVE, &xprt->state);
156681d5699SOlga Kornievskaia 
157*6f081693SOlga Kornievskaia 		ret = sprintf(buf, "state=%s %s %s %s %s %s %s %s %s %s %s %s\n",
158681d5699SOlga Kornievskaia 			      locked ? "LOCKED" : "",
159681d5699SOlga Kornievskaia 			      connected ? "CONNECTED" : "",
160681d5699SOlga Kornievskaia 			      connecting ? "CONNECTING" : "",
161681d5699SOlga Kornievskaia 			      close_wait ? "CLOSE_WAIT" : "",
162681d5699SOlga Kornievskaia 			      bound ? "BOUND" : "",
163681d5699SOlga Kornievskaia 			      binding ? "BOUNDING" : "",
164681d5699SOlga Kornievskaia 			      closing ? "CLOSING" : "",
165681d5699SOlga Kornievskaia 			      congested ? "CONGESTED" : "",
166681d5699SOlga Kornievskaia 			      cwnd_wait ? "CWND_WAIT" : "",
1675b7eb784SOlga Kornievskaia 			      write_space ? "WRITE_SPACE" : "",
168*6f081693SOlga Kornievskaia 			      offline ? "OFFLINE" : "",
169*6f081693SOlga Kornievskaia 			      remove ? "REMOVE" : "");
170681d5699SOlga Kornievskaia 	}
171681d5699SOlga Kornievskaia 
172681d5699SOlga Kornievskaia 	xprt_put(xprt);
173681d5699SOlga Kornievskaia 	return ret + 1;
174681d5699SOlga Kornievskaia }
175681d5699SOlga Kornievskaia 
1760e559035SOlga Kornievskaia static ssize_t rpc_sysfs_xprt_switch_info_show(struct kobject *kobj,
1770e559035SOlga Kornievskaia 					       struct kobj_attribute *attr,
1780e559035SOlga Kornievskaia 					       char *buf)
1790e559035SOlga Kornievskaia {
1800e559035SOlga Kornievskaia 	struct rpc_xprt_switch *xprt_switch =
1810e559035SOlga Kornievskaia 		rpc_sysfs_xprt_switch_kobj_get_xprt(kobj);
1820e559035SOlga Kornievskaia 	ssize_t ret;
1830e559035SOlga Kornievskaia 
1840e559035SOlga Kornievskaia 	if (!xprt_switch)
1850e559035SOlga Kornievskaia 		return 0;
1860e559035SOlga Kornievskaia 	ret = sprintf(buf, "num_xprts=%u\nnum_active=%u\nqueue_len=%ld\n",
1870e559035SOlga Kornievskaia 		      xprt_switch->xps_nxprts, xprt_switch->xps_nactive,
1880e559035SOlga Kornievskaia 		      atomic_long_read(&xprt_switch->xps_queuelen));
1890e559035SOlga Kornievskaia 	xprt_switch_put(xprt_switch);
1900e559035SOlga Kornievskaia 	return ret + 1;
1910e559035SOlga Kornievskaia }
1920e559035SOlga Kornievskaia 
193587bc725SOlga Kornievskaia static ssize_t rpc_sysfs_xprt_dstaddr_store(struct kobject *kobj,
194587bc725SOlga Kornievskaia 					    struct kobj_attribute *attr,
195587bc725SOlga Kornievskaia 					    const char *buf, size_t count)
196587bc725SOlga Kornievskaia {
197587bc725SOlga Kornievskaia 	struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
198587bc725SOlga Kornievskaia 	struct sockaddr *saddr;
199587bc725SOlga Kornievskaia 	char *dst_addr;
200587bc725SOlga Kornievskaia 	int port;
201587bc725SOlga Kornievskaia 	struct xprt_addr *saved_addr;
202587bc725SOlga Kornievskaia 	size_t buf_len;
203587bc725SOlga Kornievskaia 
204587bc725SOlga Kornievskaia 	if (!xprt)
205587bc725SOlga Kornievskaia 		return 0;
206587bc725SOlga Kornievskaia 	if (!(xprt->xprt_class->ident == XPRT_TRANSPORT_TCP ||
207587bc725SOlga Kornievskaia 	      xprt->xprt_class->ident == XPRT_TRANSPORT_RDMA)) {
208587bc725SOlga Kornievskaia 		xprt_put(xprt);
209587bc725SOlga Kornievskaia 		return -EOPNOTSUPP;
210587bc725SOlga Kornievskaia 	}
211587bc725SOlga Kornievskaia 
212587bc725SOlga Kornievskaia 	if (wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_KILLABLE)) {
213587bc725SOlga Kornievskaia 		count = -EINTR;
214587bc725SOlga Kornievskaia 		goto out_put;
215587bc725SOlga Kornievskaia 	}
216587bc725SOlga Kornievskaia 	saddr = (struct sockaddr *)&xprt->addr;
217587bc725SOlga Kornievskaia 	port = rpc_get_port(saddr);
218587bc725SOlga Kornievskaia 
219587bc725SOlga Kornievskaia 	/* buf_len is the len until the first occurence of either
220587bc725SOlga Kornievskaia 	 * '\n' or '\0'
221587bc725SOlga Kornievskaia 	 */
222587bc725SOlga Kornievskaia 	buf_len = strcspn(buf, "\n");
223587bc725SOlga Kornievskaia 
224587bc725SOlga Kornievskaia 	dst_addr = kstrndup(buf, buf_len, GFP_KERNEL);
225587bc725SOlga Kornievskaia 	if (!dst_addr)
226587bc725SOlga Kornievskaia 		goto out_err;
227587bc725SOlga Kornievskaia 	saved_addr = kzalloc(sizeof(*saved_addr), GFP_KERNEL);
228587bc725SOlga Kornievskaia 	if (!saved_addr)
229587bc725SOlga Kornievskaia 		goto out_err_free;
230587bc725SOlga Kornievskaia 	saved_addr->addr =
231587bc725SOlga Kornievskaia 		rcu_dereference_raw(xprt->address_strings[RPC_DISPLAY_ADDR]);
232587bc725SOlga Kornievskaia 	rcu_assign_pointer(xprt->address_strings[RPC_DISPLAY_ADDR], dst_addr);
233587bc725SOlga Kornievskaia 	call_rcu(&saved_addr->rcu, free_xprt_addr);
234587bc725SOlga Kornievskaia 	xprt->addrlen = rpc_pton(xprt->xprt_net, buf, buf_len, saddr,
235587bc725SOlga Kornievskaia 				 sizeof(*saddr));
236587bc725SOlga Kornievskaia 	rpc_set_port(saddr, port);
237587bc725SOlga Kornievskaia 
238587bc725SOlga Kornievskaia 	xprt_force_disconnect(xprt);
239587bc725SOlga Kornievskaia out:
240587bc725SOlga Kornievskaia 	xprt_release_write(xprt, NULL);
241587bc725SOlga Kornievskaia out_put:
242587bc725SOlga Kornievskaia 	xprt_put(xprt);
243587bc725SOlga Kornievskaia 	return count;
244587bc725SOlga Kornievskaia out_err_free:
245587bc725SOlga Kornievskaia 	kfree(dst_addr);
246587bc725SOlga Kornievskaia out_err:
247587bc725SOlga Kornievskaia 	count = -ENOMEM;
248587bc725SOlga Kornievskaia 	goto out;
249587bc725SOlga Kornievskaia }
250587bc725SOlga Kornievskaia 
2515b7eb784SOlga Kornievskaia static ssize_t rpc_sysfs_xprt_state_change(struct kobject *kobj,
2525b7eb784SOlga Kornievskaia 					   struct kobj_attribute *attr,
2535b7eb784SOlga Kornievskaia 					   const char *buf, size_t count)
2545b7eb784SOlga Kornievskaia {
2555b7eb784SOlga Kornievskaia 	struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
256*6f081693SOlga Kornievskaia 	int offline = 0, online = 0, remove = 0;
2575b7eb784SOlga Kornievskaia 	struct rpc_xprt_switch *xps = rpc_sysfs_xprt_kobj_get_xprt_switch(kobj);
2585b7eb784SOlga Kornievskaia 
2595b7eb784SOlga Kornievskaia 	if (!xprt)
2605b7eb784SOlga Kornievskaia 		return 0;
2615b7eb784SOlga Kornievskaia 
2625b7eb784SOlga Kornievskaia 	if (!strncmp(buf, "offline", 7))
2635b7eb784SOlga Kornievskaia 		offline = 1;
2645b7eb784SOlga Kornievskaia 	else if (!strncmp(buf, "online", 6))
2655b7eb784SOlga Kornievskaia 		online = 1;
266*6f081693SOlga Kornievskaia 	else if (!strncmp(buf, "remove", 6))
267*6f081693SOlga Kornievskaia 		remove = 1;
2685b7eb784SOlga Kornievskaia 	else
2695b7eb784SOlga Kornievskaia 		return -EINVAL;
2705b7eb784SOlga Kornievskaia 
2715b7eb784SOlga Kornievskaia 	if (wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_KILLABLE)) {
2725b7eb784SOlga Kornievskaia 		count = -EINTR;
2735b7eb784SOlga Kornievskaia 		goto out_put;
2745b7eb784SOlga Kornievskaia 	}
2755b7eb784SOlga Kornievskaia 	if (xprt->main) {
2765b7eb784SOlga Kornievskaia 		count = -EINVAL;
2775b7eb784SOlga Kornievskaia 		goto release_tasks;
2785b7eb784SOlga Kornievskaia 	}
2795b7eb784SOlga Kornievskaia 	if (offline) {
2805b7eb784SOlga Kornievskaia 		set_bit(XPRT_OFFLINE, &xprt->state);
2815b7eb784SOlga Kornievskaia 		spin_lock(&xps->xps_lock);
2825b7eb784SOlga Kornievskaia 		xps->xps_nactive--;
2835b7eb784SOlga Kornievskaia 		spin_unlock(&xps->xps_lock);
2845b7eb784SOlga Kornievskaia 	} else if (online) {
2855b7eb784SOlga Kornievskaia 		clear_bit(XPRT_OFFLINE, &xprt->state);
2865b7eb784SOlga Kornievskaia 		spin_lock(&xps->xps_lock);
2875b7eb784SOlga Kornievskaia 		xps->xps_nactive++;
2885b7eb784SOlga Kornievskaia 		spin_unlock(&xps->xps_lock);
289*6f081693SOlga Kornievskaia 	} else if (remove) {
290*6f081693SOlga Kornievskaia 		if (test_bit(XPRT_OFFLINE, &xprt->state)) {
291*6f081693SOlga Kornievskaia 			set_bit(XPRT_REMOVE, &xprt->state);
292*6f081693SOlga Kornievskaia 			xprt_force_disconnect(xprt);
293*6f081693SOlga Kornievskaia 			if (test_bit(XPRT_CONNECTED, &xprt->state)) {
294*6f081693SOlga Kornievskaia 				if (!xprt->sending.qlen &&
295*6f081693SOlga Kornievskaia 				    !xprt->pending.qlen &&
296*6f081693SOlga Kornievskaia 				    !xprt->backlog.qlen &&
297*6f081693SOlga Kornievskaia 				    !atomic_long_read(&xprt->queuelen))
298*6f081693SOlga Kornievskaia 					rpc_xprt_switch_remove_xprt(xps, xprt);
299*6f081693SOlga Kornievskaia 			}
300*6f081693SOlga Kornievskaia 		} else {
301*6f081693SOlga Kornievskaia 			count = -EINVAL;
302*6f081693SOlga Kornievskaia 		}
3035b7eb784SOlga Kornievskaia 	}
3045b7eb784SOlga Kornievskaia 
3055b7eb784SOlga Kornievskaia release_tasks:
3065b7eb784SOlga Kornievskaia 	xprt_release_write(xprt, NULL);
3075b7eb784SOlga Kornievskaia out_put:
3085b7eb784SOlga Kornievskaia 	xprt_put(xprt);
3095b7eb784SOlga Kornievskaia 	xprt_switch_put(xps);
3105b7eb784SOlga Kornievskaia 	return count;
3115b7eb784SOlga Kornievskaia }
3125b7eb784SOlga Kornievskaia 
31374678748SOlga Kornievskaia int rpc_sysfs_init(void)
31474678748SOlga Kornievskaia {
31574678748SOlga Kornievskaia 	rpc_sunrpc_kset = kset_create_and_add("sunrpc", NULL, kernel_kobj);
31674678748SOlga Kornievskaia 	if (!rpc_sunrpc_kset)
31774678748SOlga Kornievskaia 		return -ENOMEM;
318baea9944SOlga Kornievskaia 	rpc_sunrpc_client_kobj =
319baea9944SOlga Kornievskaia 		rpc_sysfs_object_alloc("rpc-clients", rpc_sunrpc_kset, NULL);
320baea9944SOlga Kornievskaia 	if (!rpc_sunrpc_client_kobj)
321baea9944SOlga Kornievskaia 		goto err_client;
322baea9944SOlga Kornievskaia 	rpc_sunrpc_xprt_switch_kobj =
323baea9944SOlga Kornievskaia 		rpc_sysfs_object_alloc("xprt-switches", rpc_sunrpc_kset, NULL);
324baea9944SOlga Kornievskaia 	if (!rpc_sunrpc_xprt_switch_kobj)
325baea9944SOlga Kornievskaia 		goto err_switch;
32674678748SOlga Kornievskaia 	return 0;
327baea9944SOlga Kornievskaia err_switch:
328baea9944SOlga Kornievskaia 	kobject_put(rpc_sunrpc_client_kobj);
329baea9944SOlga Kornievskaia 	rpc_sunrpc_client_kobj = NULL;
330baea9944SOlga Kornievskaia err_client:
331baea9944SOlga Kornievskaia 	kset_unregister(rpc_sunrpc_kset);
332baea9944SOlga Kornievskaia 	rpc_sunrpc_kset = NULL;
333baea9944SOlga Kornievskaia 	return -ENOMEM;
33474678748SOlga Kornievskaia }
33574678748SOlga Kornievskaia 
336c5a382ebSOlga Kornievskaia static void rpc_sysfs_client_release(struct kobject *kobj)
337c5a382ebSOlga Kornievskaia {
338c5a382ebSOlga Kornievskaia 	struct rpc_sysfs_client *c;
339c5a382ebSOlga Kornievskaia 
340c5a382ebSOlga Kornievskaia 	c = container_of(kobj, struct rpc_sysfs_client, kobject);
341c5a382ebSOlga Kornievskaia 	kfree(c);
342c5a382ebSOlga Kornievskaia }
343c5a382ebSOlga Kornievskaia 
344baea9944SOlga Kornievskaia static void rpc_sysfs_xprt_switch_release(struct kobject *kobj)
345baea9944SOlga Kornievskaia {
346baea9944SOlga Kornievskaia 	struct rpc_sysfs_xprt_switch *xprt_switch;
347baea9944SOlga Kornievskaia 
348baea9944SOlga Kornievskaia 	xprt_switch = container_of(kobj, struct rpc_sysfs_xprt_switch, kobject);
349baea9944SOlga Kornievskaia 	kfree(xprt_switch);
350baea9944SOlga Kornievskaia }
351baea9944SOlga Kornievskaia 
352d408ebe0SOlga Kornievskaia static void rpc_sysfs_xprt_release(struct kobject *kobj)
353d408ebe0SOlga Kornievskaia {
354d408ebe0SOlga Kornievskaia 	struct rpc_sysfs_xprt *xprt;
355d408ebe0SOlga Kornievskaia 
356d408ebe0SOlga Kornievskaia 	xprt = container_of(kobj, struct rpc_sysfs_xprt, kobject);
357d408ebe0SOlga Kornievskaia 	kfree(xprt);
358d408ebe0SOlga Kornievskaia }
359d408ebe0SOlga Kornievskaia 
360c5a382ebSOlga Kornievskaia static const void *rpc_sysfs_client_namespace(struct kobject *kobj)
361c5a382ebSOlga Kornievskaia {
362c5a382ebSOlga Kornievskaia 	return container_of(kobj, struct rpc_sysfs_client, kobject)->net;
363c5a382ebSOlga Kornievskaia }
364c5a382ebSOlga Kornievskaia 
365baea9944SOlga Kornievskaia static const void *rpc_sysfs_xprt_switch_namespace(struct kobject *kobj)
366baea9944SOlga Kornievskaia {
367baea9944SOlga Kornievskaia 	return container_of(kobj, struct rpc_sysfs_xprt_switch, kobject)->net;
368baea9944SOlga Kornievskaia }
369baea9944SOlga Kornievskaia 
370d408ebe0SOlga Kornievskaia static const void *rpc_sysfs_xprt_namespace(struct kobject *kobj)
371d408ebe0SOlga Kornievskaia {
372d408ebe0SOlga Kornievskaia 	return container_of(kobj, struct rpc_sysfs_xprt,
373d408ebe0SOlga Kornievskaia 			    kobject)->xprt->xprt_net;
374d408ebe0SOlga Kornievskaia }
375d408ebe0SOlga Kornievskaia 
376587bc725SOlga Kornievskaia static struct kobj_attribute rpc_sysfs_xprt_dstaddr = __ATTR(dstaddr,
377587bc725SOlga Kornievskaia 	0644, rpc_sysfs_xprt_dstaddr_show, rpc_sysfs_xprt_dstaddr_store);
378587bc725SOlga Kornievskaia 
3794a09651aSOlga Kornievskaia static struct kobj_attribute rpc_sysfs_xprt_info = __ATTR(xprt_info,
3804a09651aSOlga Kornievskaia 	0444, rpc_sysfs_xprt_info_show, NULL);
3814a09651aSOlga Kornievskaia 
382681d5699SOlga Kornievskaia static struct kobj_attribute rpc_sysfs_xprt_change_state = __ATTR(xprt_state,
3835b7eb784SOlga Kornievskaia 	0644, rpc_sysfs_xprt_state_show, rpc_sysfs_xprt_state_change);
384681d5699SOlga Kornievskaia 
385587bc725SOlga Kornievskaia static struct attribute *rpc_sysfs_xprt_attrs[] = {
386587bc725SOlga Kornievskaia 	&rpc_sysfs_xprt_dstaddr.attr,
3874a09651aSOlga Kornievskaia 	&rpc_sysfs_xprt_info.attr,
388681d5699SOlga Kornievskaia 	&rpc_sysfs_xprt_change_state.attr,
389587bc725SOlga Kornievskaia 	NULL,
390587bc725SOlga Kornievskaia };
391587bc725SOlga Kornievskaia 
3920e559035SOlga Kornievskaia static struct kobj_attribute rpc_sysfs_xprt_switch_info =
3930e559035SOlga Kornievskaia 	__ATTR(xprt_switch_info, 0444, rpc_sysfs_xprt_switch_info_show, NULL);
3940e559035SOlga Kornievskaia 
3950e559035SOlga Kornievskaia static struct attribute *rpc_sysfs_xprt_switch_attrs[] = {
3960e559035SOlga Kornievskaia 	&rpc_sysfs_xprt_switch_info.attr,
3970e559035SOlga Kornievskaia 	NULL,
3980e559035SOlga Kornievskaia };
3990e559035SOlga Kornievskaia 
400c5a382ebSOlga Kornievskaia static struct kobj_type rpc_sysfs_client_type = {
401c5a382ebSOlga Kornievskaia 	.release = rpc_sysfs_client_release,
402c5a382ebSOlga Kornievskaia 	.sysfs_ops = &kobj_sysfs_ops,
403c5a382ebSOlga Kornievskaia 	.namespace = rpc_sysfs_client_namespace,
404c5a382ebSOlga Kornievskaia };
405c5a382ebSOlga Kornievskaia 
406baea9944SOlga Kornievskaia static struct kobj_type rpc_sysfs_xprt_switch_type = {
407baea9944SOlga Kornievskaia 	.release = rpc_sysfs_xprt_switch_release,
4080e559035SOlga Kornievskaia 	.default_attrs = rpc_sysfs_xprt_switch_attrs,
409baea9944SOlga Kornievskaia 	.sysfs_ops = &kobj_sysfs_ops,
410baea9944SOlga Kornievskaia 	.namespace = rpc_sysfs_xprt_switch_namespace,
411baea9944SOlga Kornievskaia };
412baea9944SOlga Kornievskaia 
413d408ebe0SOlga Kornievskaia static struct kobj_type rpc_sysfs_xprt_type = {
414d408ebe0SOlga Kornievskaia 	.release = rpc_sysfs_xprt_release,
415587bc725SOlga Kornievskaia 	.default_attrs = rpc_sysfs_xprt_attrs,
416d408ebe0SOlga Kornievskaia 	.sysfs_ops = &kobj_sysfs_ops,
417d408ebe0SOlga Kornievskaia 	.namespace = rpc_sysfs_xprt_namespace,
418d408ebe0SOlga Kornievskaia };
419d408ebe0SOlga Kornievskaia 
42074678748SOlga Kornievskaia void rpc_sysfs_exit(void)
42174678748SOlga Kornievskaia {
422c441f125SOlga Kornievskaia 	kobject_put(rpc_sunrpc_client_kobj);
423baea9944SOlga Kornievskaia 	kobject_put(rpc_sunrpc_xprt_switch_kobj);
42474678748SOlga Kornievskaia 	kset_unregister(rpc_sunrpc_kset);
42574678748SOlga Kornievskaia }
426c5a382ebSOlga Kornievskaia 
427c5a382ebSOlga Kornievskaia static struct rpc_sysfs_client *rpc_sysfs_client_alloc(struct kobject *parent,
428c5a382ebSOlga Kornievskaia 						       struct net *net,
429c5a382ebSOlga Kornievskaia 						       int clid)
430c5a382ebSOlga Kornievskaia {
431c5a382ebSOlga Kornievskaia 	struct rpc_sysfs_client *p;
432c5a382ebSOlga Kornievskaia 
433c5a382ebSOlga Kornievskaia 	p = kzalloc(sizeof(*p), GFP_KERNEL);
434c5a382ebSOlga Kornievskaia 	if (p) {
435c5a382ebSOlga Kornievskaia 		p->net = net;
436c5a382ebSOlga Kornievskaia 		p->kobject.kset = rpc_sunrpc_kset;
437c5a382ebSOlga Kornievskaia 		if (kobject_init_and_add(&p->kobject, &rpc_sysfs_client_type,
438c5a382ebSOlga Kornievskaia 					 parent, "clnt-%d", clid) == 0)
439c5a382ebSOlga Kornievskaia 			return p;
440c5a382ebSOlga Kornievskaia 		kobject_put(&p->kobject);
441c5a382ebSOlga Kornievskaia 	}
442c5a382ebSOlga Kornievskaia 	return NULL;
443c5a382ebSOlga Kornievskaia }
444c5a382ebSOlga Kornievskaia 
445baea9944SOlga Kornievskaia static struct rpc_sysfs_xprt_switch *
446baea9944SOlga Kornievskaia rpc_sysfs_xprt_switch_alloc(struct kobject *parent,
447baea9944SOlga Kornievskaia 			    struct rpc_xprt_switch *xprt_switch,
448baea9944SOlga Kornievskaia 			    struct net *net,
449baea9944SOlga Kornievskaia 			    gfp_t gfp_flags)
450baea9944SOlga Kornievskaia {
451baea9944SOlga Kornievskaia 	struct rpc_sysfs_xprt_switch *p;
452baea9944SOlga Kornievskaia 
453baea9944SOlga Kornievskaia 	p = kzalloc(sizeof(*p), gfp_flags);
454baea9944SOlga Kornievskaia 	if (p) {
455baea9944SOlga Kornievskaia 		p->net = net;
456baea9944SOlga Kornievskaia 		p->kobject.kset = rpc_sunrpc_kset;
457baea9944SOlga Kornievskaia 		if (kobject_init_and_add(&p->kobject,
458baea9944SOlga Kornievskaia 					 &rpc_sysfs_xprt_switch_type,
459baea9944SOlga Kornievskaia 					 parent, "switch-%d",
460baea9944SOlga Kornievskaia 					 xprt_switch->xps_id) == 0)
461baea9944SOlga Kornievskaia 			return p;
462baea9944SOlga Kornievskaia 		kobject_put(&p->kobject);
463baea9944SOlga Kornievskaia 	}
464baea9944SOlga Kornievskaia 	return NULL;
465baea9944SOlga Kornievskaia }
466baea9944SOlga Kornievskaia 
467d408ebe0SOlga Kornievskaia static struct rpc_sysfs_xprt *rpc_sysfs_xprt_alloc(struct kobject *parent,
468d408ebe0SOlga Kornievskaia 						   struct rpc_xprt *xprt,
469d408ebe0SOlga Kornievskaia 						   gfp_t gfp_flags)
470d408ebe0SOlga Kornievskaia {
471d408ebe0SOlga Kornievskaia 	struct rpc_sysfs_xprt *p;
472d408ebe0SOlga Kornievskaia 
473d408ebe0SOlga Kornievskaia 	p = kzalloc(sizeof(*p), gfp_flags);
474d408ebe0SOlga Kornievskaia 	if (!p)
475d408ebe0SOlga Kornievskaia 		goto out;
476d408ebe0SOlga Kornievskaia 	p->kobject.kset = rpc_sunrpc_kset;
477d408ebe0SOlga Kornievskaia 	if (kobject_init_and_add(&p->kobject, &rpc_sysfs_xprt_type,
478d408ebe0SOlga Kornievskaia 				 parent, "xprt-%d-%s", xprt->id,
479d408ebe0SOlga Kornievskaia 				 xprt->address_strings[RPC_DISPLAY_PROTO]) == 0)
480d408ebe0SOlga Kornievskaia 		return p;
481d408ebe0SOlga Kornievskaia 	kobject_put(&p->kobject);
482d408ebe0SOlga Kornievskaia out:
483d408ebe0SOlga Kornievskaia 	return NULL;
484d408ebe0SOlga Kornievskaia }
485d408ebe0SOlga Kornievskaia 
4862a338a54SOlga Kornievskaia void rpc_sysfs_client_setup(struct rpc_clnt *clnt,
4872a338a54SOlga Kornievskaia 			    struct rpc_xprt_switch *xprt_switch,
4882a338a54SOlga Kornievskaia 			    struct net *net)
489c5a382ebSOlga Kornievskaia {
490c5a382ebSOlga Kornievskaia 	struct rpc_sysfs_client *rpc_client;
491c5a382ebSOlga Kornievskaia 
4922a338a54SOlga Kornievskaia 	rpc_client = rpc_sysfs_client_alloc(rpc_sunrpc_client_kobj,
4932a338a54SOlga Kornievskaia 					    net, clnt->cl_clid);
494c5a382ebSOlga Kornievskaia 	if (rpc_client) {
4952a338a54SOlga Kornievskaia 		char name[] = "switch";
4962a338a54SOlga Kornievskaia 		struct rpc_sysfs_xprt_switch *xswitch =
4972a338a54SOlga Kornievskaia 			(struct rpc_sysfs_xprt_switch *)xprt_switch->xps_sysfs;
4982a338a54SOlga Kornievskaia 		int ret;
4992a338a54SOlga Kornievskaia 
500c5a382ebSOlga Kornievskaia 		clnt->cl_sysfs = rpc_client;
5012a338a54SOlga Kornievskaia 		rpc_client->clnt = clnt;
5022a338a54SOlga Kornievskaia 		rpc_client->xprt_switch = xprt_switch;
503c5a382ebSOlga Kornievskaia 		kobject_uevent(&rpc_client->kobject, KOBJ_ADD);
5042a338a54SOlga Kornievskaia 		ret = sysfs_create_link_nowarn(&rpc_client->kobject,
5052a338a54SOlga Kornievskaia 					       &xswitch->kobject, name);
5062a338a54SOlga Kornievskaia 		if (ret)
5072a338a54SOlga Kornievskaia 			pr_warn("can't create link to %s in sysfs (%d)\n",
5082a338a54SOlga Kornievskaia 				name, ret);
509c5a382ebSOlga Kornievskaia 	}
510c5a382ebSOlga Kornievskaia }
511c5a382ebSOlga Kornievskaia 
512baea9944SOlga Kornievskaia void rpc_sysfs_xprt_switch_setup(struct rpc_xprt_switch *xprt_switch,
513baea9944SOlga Kornievskaia 				 struct rpc_xprt *xprt,
514baea9944SOlga Kornievskaia 				 gfp_t gfp_flags)
515baea9944SOlga Kornievskaia {
516baea9944SOlga Kornievskaia 	struct rpc_sysfs_xprt_switch *rpc_xprt_switch;
517baea9944SOlga Kornievskaia 	struct net *net;
518baea9944SOlga Kornievskaia 
519baea9944SOlga Kornievskaia 	if (xprt_switch->xps_net)
520baea9944SOlga Kornievskaia 		net = xprt_switch->xps_net;
521baea9944SOlga Kornievskaia 	else
522baea9944SOlga Kornievskaia 		net = xprt->xprt_net;
523baea9944SOlga Kornievskaia 	rpc_xprt_switch =
524baea9944SOlga Kornievskaia 		rpc_sysfs_xprt_switch_alloc(rpc_sunrpc_xprt_switch_kobj,
525baea9944SOlga Kornievskaia 					    xprt_switch, net, gfp_flags);
526baea9944SOlga Kornievskaia 	if (rpc_xprt_switch) {
527baea9944SOlga Kornievskaia 		xprt_switch->xps_sysfs = rpc_xprt_switch;
528baea9944SOlga Kornievskaia 		rpc_xprt_switch->xprt_switch = xprt_switch;
529baea9944SOlga Kornievskaia 		rpc_xprt_switch->xprt = xprt;
530baea9944SOlga Kornievskaia 		kobject_uevent(&rpc_xprt_switch->kobject, KOBJ_ADD);
531baea9944SOlga Kornievskaia 	}
532baea9944SOlga Kornievskaia }
533baea9944SOlga Kornievskaia 
534d408ebe0SOlga Kornievskaia void rpc_sysfs_xprt_setup(struct rpc_xprt_switch *xprt_switch,
535d408ebe0SOlga Kornievskaia 			  struct rpc_xprt *xprt,
536d408ebe0SOlga Kornievskaia 			  gfp_t gfp_flags)
537d408ebe0SOlga Kornievskaia {
538d408ebe0SOlga Kornievskaia 	struct rpc_sysfs_xprt *rpc_xprt;
539d408ebe0SOlga Kornievskaia 	struct rpc_sysfs_xprt_switch *switch_obj =
540d408ebe0SOlga Kornievskaia 		(struct rpc_sysfs_xprt_switch *)xprt_switch->xps_sysfs;
541d408ebe0SOlga Kornievskaia 
542d408ebe0SOlga Kornievskaia 	rpc_xprt = rpc_sysfs_xprt_alloc(&switch_obj->kobject, xprt, gfp_flags);
543d408ebe0SOlga Kornievskaia 	if (rpc_xprt) {
544d408ebe0SOlga Kornievskaia 		xprt->xprt_sysfs = rpc_xprt;
545d408ebe0SOlga Kornievskaia 		rpc_xprt->xprt = xprt;
5465b7eb784SOlga Kornievskaia 		rpc_xprt->xprt_switch = xprt_switch;
547d408ebe0SOlga Kornievskaia 		kobject_uevent(&rpc_xprt->kobject, KOBJ_ADD);
548d408ebe0SOlga Kornievskaia 	}
549d408ebe0SOlga Kornievskaia }
550d408ebe0SOlga Kornievskaia 
551c5a382ebSOlga Kornievskaia void rpc_sysfs_client_destroy(struct rpc_clnt *clnt)
552c5a382ebSOlga Kornievskaia {
553c5a382ebSOlga Kornievskaia 	struct rpc_sysfs_client *rpc_client = clnt->cl_sysfs;
554c5a382ebSOlga Kornievskaia 
555c5a382ebSOlga Kornievskaia 	if (rpc_client) {
5562a338a54SOlga Kornievskaia 		char name[] = "switch";
5572a338a54SOlga Kornievskaia 
5582a338a54SOlga Kornievskaia 		sysfs_remove_link(&rpc_client->kobject, name);
559c5a382ebSOlga Kornievskaia 		kobject_uevent(&rpc_client->kobject, KOBJ_REMOVE);
560c5a382ebSOlga Kornievskaia 		kobject_del(&rpc_client->kobject);
561c5a382ebSOlga Kornievskaia 		kobject_put(&rpc_client->kobject);
562c5a382ebSOlga Kornievskaia 		clnt->cl_sysfs = NULL;
563c5a382ebSOlga Kornievskaia 	}
564c5a382ebSOlga Kornievskaia }
565baea9944SOlga Kornievskaia 
566baea9944SOlga Kornievskaia void rpc_sysfs_xprt_switch_destroy(struct rpc_xprt_switch *xprt_switch)
567baea9944SOlga Kornievskaia {
568baea9944SOlga Kornievskaia 	struct rpc_sysfs_xprt_switch *rpc_xprt_switch = xprt_switch->xps_sysfs;
569baea9944SOlga Kornievskaia 
570baea9944SOlga Kornievskaia 	if (rpc_xprt_switch) {
571baea9944SOlga Kornievskaia 		kobject_uevent(&rpc_xprt_switch->kobject, KOBJ_REMOVE);
572baea9944SOlga Kornievskaia 		kobject_del(&rpc_xprt_switch->kobject);
573baea9944SOlga Kornievskaia 		kobject_put(&rpc_xprt_switch->kobject);
574baea9944SOlga Kornievskaia 		xprt_switch->xps_sysfs = NULL;
575baea9944SOlga Kornievskaia 	}
576baea9944SOlga Kornievskaia }
577d408ebe0SOlga Kornievskaia 
578d408ebe0SOlga Kornievskaia void rpc_sysfs_xprt_destroy(struct rpc_xprt *xprt)
579d408ebe0SOlga Kornievskaia {
580d408ebe0SOlga Kornievskaia 	struct rpc_sysfs_xprt *rpc_xprt = xprt->xprt_sysfs;
581d408ebe0SOlga Kornievskaia 
582d408ebe0SOlga Kornievskaia 	if (rpc_xprt) {
583d408ebe0SOlga Kornievskaia 		kobject_uevent(&rpc_xprt->kobject, KOBJ_REMOVE);
584d408ebe0SOlga Kornievskaia 		kobject_del(&rpc_xprt->kobject);
585d408ebe0SOlga Kornievskaia 		kobject_put(&rpc_xprt->kobject);
586d408ebe0SOlga Kornievskaia 		xprt->xprt_sysfs = NULL;
587d408ebe0SOlga Kornievskaia 	}
588d408ebe0SOlga Kornievskaia }
589