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