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