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 * 34*02a476d9SGreg Kroah-Hartman rpc_sysfs_object_child_ns_type(const struct kobject *kobj) 35c441f125SOlga Kornievskaia { 36c441f125SOlga Kornievskaia return &net_ns_type_operations; 37c441f125SOlga Kornievskaia } 38c441f125SOlga Kornievskaia 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 96ebbe7887STrond Myklebust if (!xprt) { 97ebbe7887STrond Myklebust ret = sprintf(buf, "<closed>\n"); 98ebbe7887STrond Myklebust goto out; 99ebbe7887STrond Myklebust } 100587bc725SOlga Kornievskaia ret = sprintf(buf, "%s\n", xprt->address_strings[RPC_DISPLAY_ADDR]); 101587bc725SOlga Kornievskaia xprt_put(xprt); 102ebbe7887STrond Myklebust out: 103421ab1beSTrond Myklebust return ret; 104587bc725SOlga Kornievskaia } 105587bc725SOlga Kornievskaia 106e44773daSAnna Schumaker static ssize_t rpc_sysfs_xprt_srcaddr_show(struct kobject *kobj, 107e44773daSAnna Schumaker struct kobj_attribute *attr, 108e44773daSAnna Schumaker char *buf) 109e44773daSAnna Schumaker { 110e44773daSAnna Schumaker struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj); 111421ab1beSTrond Myklebust size_t buflen = PAGE_SIZE; 112ebbe7887STrond Myklebust ssize_t ret; 113e44773daSAnna Schumaker 11417f09d3fSAnna Schumaker if (!xprt || !xprt_connected(xprt)) { 115ebbe7887STrond Myklebust ret = sprintf(buf, "<closed>\n"); 116421ab1beSTrond Myklebust } else if (xprt->ops->get_srcaddr) { 117421ab1beSTrond Myklebust ret = xprt->ops->get_srcaddr(xprt, buf, buflen); 118421ab1beSTrond Myklebust if (ret > 0) { 119421ab1beSTrond Myklebust if (ret < buflen - 1) { 120421ab1beSTrond Myklebust buf[ret] = '\n'; 121421ab1beSTrond Myklebust ret++; 122421ab1beSTrond Myklebust buf[ret] = '\0'; 12317f09d3fSAnna Schumaker } 124ebbe7887STrond Myklebust } else 125ebbe7887STrond Myklebust ret = sprintf(buf, "<closed>\n"); 126ebbe7887STrond Myklebust } else 127ebbe7887STrond Myklebust ret = sprintf(buf, "<not a socket>\n"); 128e44773daSAnna Schumaker xprt_put(xprt); 129421ab1beSTrond Myklebust return ret; 130e44773daSAnna Schumaker } 131e44773daSAnna Schumaker 1324a09651aSOlga Kornievskaia static ssize_t rpc_sysfs_xprt_info_show(struct kobject *kobj, 133421ab1beSTrond Myklebust struct kobj_attribute *attr, char *buf) 1344a09651aSOlga Kornievskaia { 1354a09651aSOlga Kornievskaia struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj); 136421ab1beSTrond Myklebust unsigned short srcport = 0; 137421ab1beSTrond Myklebust size_t buflen = PAGE_SIZE; 1384a09651aSOlga Kornievskaia ssize_t ret; 1394a09651aSOlga Kornievskaia 14017f09d3fSAnna Schumaker if (!xprt || !xprt_connected(xprt)) { 141ebbe7887STrond Myklebust ret = sprintf(buf, "<closed>\n"); 142ebbe7887STrond Myklebust goto out; 14317f09d3fSAnna Schumaker } 1444a09651aSOlga Kornievskaia 145421ab1beSTrond Myklebust if (xprt->ops->get_srcport) 146421ab1beSTrond Myklebust srcport = xprt->ops->get_srcport(xprt); 147421ab1beSTrond Myklebust 148421ab1beSTrond Myklebust ret = snprintf(buf, buflen, 149421ab1beSTrond Myklebust "last_used=%lu\ncur_cong=%lu\ncong_win=%lu\n" 1504a09651aSOlga Kornievskaia "max_num_slots=%u\nmin_num_slots=%u\nnum_reqs=%u\n" 1514a09651aSOlga Kornievskaia "binding_q_len=%u\nsending_q_len=%u\npending_q_len=%u\n" 1526a284059SOlga Kornievskaia "backlog_q_len=%u\nmain_xprt=%d\nsrc_port=%u\n" 15369f2cd6dSAnna Schumaker "tasks_queuelen=%ld\ndst_port=%s\n", 154c1830a63SOlga Kornievskaia xprt->last_used, xprt->cong, xprt->cwnd, xprt->max_reqs, 155c1830a63SOlga Kornievskaia xprt->min_reqs, xprt->num_reqs, xprt->binding.qlen, 156c1830a63SOlga Kornievskaia xprt->sending.qlen, xprt->pending.qlen, 157421ab1beSTrond Myklebust xprt->backlog.qlen, xprt->main, srcport, 15869f2cd6dSAnna Schumaker atomic_long_read(&xprt->queuelen), 159421ab1beSTrond Myklebust xprt->address_strings[RPC_DISPLAY_PORT]); 160ebbe7887STrond Myklebust out: 1614a09651aSOlga Kornievskaia xprt_put(xprt); 162421ab1beSTrond Myklebust return ret; 1634a09651aSOlga Kornievskaia } 1644a09651aSOlga Kornievskaia 165681d5699SOlga Kornievskaia static ssize_t rpc_sysfs_xprt_state_show(struct kobject *kobj, 166681d5699SOlga Kornievskaia struct kobj_attribute *attr, 167681d5699SOlga Kornievskaia char *buf) 168681d5699SOlga Kornievskaia { 169681d5699SOlga Kornievskaia struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj); 170681d5699SOlga Kornievskaia ssize_t ret; 171681d5699SOlga Kornievskaia int locked, connected, connecting, close_wait, bound, binding, 1726f081693SOlga Kornievskaia closing, congested, cwnd_wait, write_space, offline, remove; 173681d5699SOlga Kornievskaia 174ebbe7887STrond Myklebust if (!(xprt && xprt->state)) { 175681d5699SOlga Kornievskaia ret = sprintf(buf, "state=CLOSED\n"); 176681d5699SOlga Kornievskaia } else { 177681d5699SOlga Kornievskaia locked = test_bit(XPRT_LOCKED, &xprt->state); 178681d5699SOlga Kornievskaia connected = test_bit(XPRT_CONNECTED, &xprt->state); 179681d5699SOlga Kornievskaia connecting = test_bit(XPRT_CONNECTING, &xprt->state); 180681d5699SOlga Kornievskaia close_wait = test_bit(XPRT_CLOSE_WAIT, &xprt->state); 181681d5699SOlga Kornievskaia bound = test_bit(XPRT_BOUND, &xprt->state); 182681d5699SOlga Kornievskaia binding = test_bit(XPRT_BINDING, &xprt->state); 183681d5699SOlga Kornievskaia closing = test_bit(XPRT_CLOSING, &xprt->state); 184681d5699SOlga Kornievskaia congested = test_bit(XPRT_CONGESTED, &xprt->state); 185681d5699SOlga Kornievskaia cwnd_wait = test_bit(XPRT_CWND_WAIT, &xprt->state); 186681d5699SOlga Kornievskaia write_space = test_bit(XPRT_WRITE_SPACE, &xprt->state); 1875b7eb784SOlga Kornievskaia offline = test_bit(XPRT_OFFLINE, &xprt->state); 1886f081693SOlga Kornievskaia remove = test_bit(XPRT_REMOVE, &xprt->state); 189681d5699SOlga Kornievskaia 1906f081693SOlga Kornievskaia ret = sprintf(buf, "state=%s %s %s %s %s %s %s %s %s %s %s %s\n", 191681d5699SOlga Kornievskaia locked ? "LOCKED" : "", 192681d5699SOlga Kornievskaia connected ? "CONNECTED" : "", 193681d5699SOlga Kornievskaia connecting ? "CONNECTING" : "", 194681d5699SOlga Kornievskaia close_wait ? "CLOSE_WAIT" : "", 195681d5699SOlga Kornievskaia bound ? "BOUND" : "", 196681d5699SOlga Kornievskaia binding ? "BOUNDING" : "", 197681d5699SOlga Kornievskaia closing ? "CLOSING" : "", 198681d5699SOlga Kornievskaia congested ? "CONGESTED" : "", 199681d5699SOlga Kornievskaia cwnd_wait ? "CWND_WAIT" : "", 2005b7eb784SOlga Kornievskaia write_space ? "WRITE_SPACE" : "", 2016f081693SOlga Kornievskaia offline ? "OFFLINE" : "", 2026f081693SOlga Kornievskaia remove ? "REMOVE" : ""); 203681d5699SOlga Kornievskaia } 204681d5699SOlga Kornievskaia 205681d5699SOlga Kornievskaia xprt_put(xprt); 206421ab1beSTrond Myklebust return ret; 207681d5699SOlga Kornievskaia } 208681d5699SOlga Kornievskaia 2090e559035SOlga Kornievskaia static ssize_t rpc_sysfs_xprt_switch_info_show(struct kobject *kobj, 2100e559035SOlga Kornievskaia struct kobj_attribute *attr, 2110e559035SOlga Kornievskaia char *buf) 2120e559035SOlga Kornievskaia { 2130e559035SOlga Kornievskaia struct rpc_xprt_switch *xprt_switch = 2140e559035SOlga Kornievskaia rpc_sysfs_xprt_switch_kobj_get_xprt(kobj); 2150e559035SOlga Kornievskaia ssize_t ret; 2160e559035SOlga Kornievskaia 2170e559035SOlga Kornievskaia if (!xprt_switch) 2180e559035SOlga Kornievskaia return 0; 219df205d0aSOlga Kornievskaia ret = sprintf(buf, "num_xprts=%u\nnum_active=%u\n" 220df205d0aSOlga Kornievskaia "num_unique_destaddr=%u\nqueue_len=%ld\n", 2210e559035SOlga Kornievskaia xprt_switch->xps_nxprts, xprt_switch->xps_nactive, 222df205d0aSOlga Kornievskaia xprt_switch->xps_nunique_destaddr_xprts, 2230e559035SOlga Kornievskaia atomic_long_read(&xprt_switch->xps_queuelen)); 2240e559035SOlga Kornievskaia xprt_switch_put(xprt_switch); 225421ab1beSTrond Myklebust return ret; 2260e559035SOlga Kornievskaia } 2270e559035SOlga Kornievskaia 228587bc725SOlga Kornievskaia static ssize_t rpc_sysfs_xprt_dstaddr_store(struct kobject *kobj, 229587bc725SOlga Kornievskaia struct kobj_attribute *attr, 230587bc725SOlga Kornievskaia const char *buf, size_t count) 231587bc725SOlga Kornievskaia { 232587bc725SOlga Kornievskaia struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj); 233587bc725SOlga Kornievskaia struct sockaddr *saddr; 234587bc725SOlga Kornievskaia char *dst_addr; 235587bc725SOlga Kornievskaia int port; 236587bc725SOlga Kornievskaia struct xprt_addr *saved_addr; 237587bc725SOlga Kornievskaia size_t buf_len; 238587bc725SOlga Kornievskaia 239587bc725SOlga Kornievskaia if (!xprt) 240587bc725SOlga Kornievskaia return 0; 241587bc725SOlga Kornievskaia if (!(xprt->xprt_class->ident == XPRT_TRANSPORT_TCP || 242587bc725SOlga Kornievskaia xprt->xprt_class->ident == XPRT_TRANSPORT_RDMA)) { 243587bc725SOlga Kornievskaia xprt_put(xprt); 244587bc725SOlga Kornievskaia return -EOPNOTSUPP; 245587bc725SOlga Kornievskaia } 246587bc725SOlga Kornievskaia 247587bc725SOlga Kornievskaia if (wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_KILLABLE)) { 248587bc725SOlga Kornievskaia count = -EINTR; 249587bc725SOlga Kornievskaia goto out_put; 250587bc725SOlga Kornievskaia } 251587bc725SOlga Kornievskaia saddr = (struct sockaddr *)&xprt->addr; 252587bc725SOlga Kornievskaia port = rpc_get_port(saddr); 253587bc725SOlga Kornievskaia 254587bc725SOlga Kornievskaia /* buf_len is the len until the first occurence of either 255587bc725SOlga Kornievskaia * '\n' or '\0' 256587bc725SOlga Kornievskaia */ 257587bc725SOlga Kornievskaia buf_len = strcspn(buf, "\n"); 258587bc725SOlga Kornievskaia 259587bc725SOlga Kornievskaia dst_addr = kstrndup(buf, buf_len, GFP_KERNEL); 260587bc725SOlga Kornievskaia if (!dst_addr) 261587bc725SOlga Kornievskaia goto out_err; 262587bc725SOlga Kornievskaia saved_addr = kzalloc(sizeof(*saved_addr), GFP_KERNEL); 263587bc725SOlga Kornievskaia if (!saved_addr) 264587bc725SOlga Kornievskaia goto out_err_free; 265587bc725SOlga Kornievskaia saved_addr->addr = 266587bc725SOlga Kornievskaia rcu_dereference_raw(xprt->address_strings[RPC_DISPLAY_ADDR]); 267587bc725SOlga Kornievskaia rcu_assign_pointer(xprt->address_strings[RPC_DISPLAY_ADDR], dst_addr); 268587bc725SOlga Kornievskaia call_rcu(&saved_addr->rcu, free_xprt_addr); 269587bc725SOlga Kornievskaia xprt->addrlen = rpc_pton(xprt->xprt_net, buf, buf_len, saddr, 270587bc725SOlga Kornievskaia sizeof(*saddr)); 271587bc725SOlga Kornievskaia rpc_set_port(saddr, port); 272587bc725SOlga Kornievskaia 273587bc725SOlga Kornievskaia xprt_force_disconnect(xprt); 274587bc725SOlga Kornievskaia out: 275587bc725SOlga Kornievskaia xprt_release_write(xprt, NULL); 276587bc725SOlga Kornievskaia out_put: 277587bc725SOlga Kornievskaia xprt_put(xprt); 278587bc725SOlga Kornievskaia return count; 279587bc725SOlga Kornievskaia out_err_free: 280587bc725SOlga Kornievskaia kfree(dst_addr); 281587bc725SOlga Kornievskaia out_err: 282587bc725SOlga Kornievskaia count = -ENOMEM; 283587bc725SOlga Kornievskaia goto out; 284587bc725SOlga Kornievskaia } 285587bc725SOlga Kornievskaia 2865b7eb784SOlga Kornievskaia static ssize_t rpc_sysfs_xprt_state_change(struct kobject *kobj, 2875b7eb784SOlga Kornievskaia struct kobj_attribute *attr, 2885b7eb784SOlga Kornievskaia const char *buf, size_t count) 2895b7eb784SOlga Kornievskaia { 2905b7eb784SOlga Kornievskaia struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj); 2916f081693SOlga Kornievskaia int offline = 0, online = 0, remove = 0; 2925b7eb784SOlga Kornievskaia struct rpc_xprt_switch *xps = rpc_sysfs_xprt_kobj_get_xprt_switch(kobj); 2935b7eb784SOlga Kornievskaia 294bfc48f1bSXin Xiong if (!xprt || !xps) { 295bfc48f1bSXin Xiong count = 0; 296bfc48f1bSXin Xiong goto out_put; 297bfc48f1bSXin Xiong } 2985b7eb784SOlga Kornievskaia 2995b7eb784SOlga Kornievskaia if (!strncmp(buf, "offline", 7)) 3005b7eb784SOlga Kornievskaia offline = 1; 3015b7eb784SOlga Kornievskaia else if (!strncmp(buf, "online", 6)) 3025b7eb784SOlga Kornievskaia online = 1; 3036f081693SOlga Kornievskaia else if (!strncmp(buf, "remove", 6)) 3046f081693SOlga Kornievskaia remove = 1; 305776d794fSXiyu Yang else { 306776d794fSXiyu Yang count = -EINVAL; 307776d794fSXiyu Yang goto out_put; 308776d794fSXiyu Yang } 3095b7eb784SOlga Kornievskaia 3105b7eb784SOlga Kornievskaia if (wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_KILLABLE)) { 3115b7eb784SOlga Kornievskaia count = -EINTR; 3125b7eb784SOlga Kornievskaia goto out_put; 3135b7eb784SOlga Kornievskaia } 3145b7eb784SOlga Kornievskaia if (xprt->main) { 3155b7eb784SOlga Kornievskaia count = -EINVAL; 3165b7eb784SOlga Kornievskaia goto release_tasks; 3175b7eb784SOlga Kornievskaia } 3185b7eb784SOlga Kornievskaia if (offline) { 3197ffcdaa6SOlga Kornievskaia xprt_set_offline_locked(xprt, xps); 3205b7eb784SOlga Kornievskaia } else if (online) { 3217ffcdaa6SOlga Kornievskaia xprt_set_online_locked(xprt, xps); 3226f081693SOlga Kornievskaia } else if (remove) { 3237ffcdaa6SOlga Kornievskaia if (test_bit(XPRT_OFFLINE, &xprt->state)) 3247ffcdaa6SOlga Kornievskaia xprt_delete_locked(xprt, xps); 3257ffcdaa6SOlga Kornievskaia else 3266f081693SOlga Kornievskaia count = -EINVAL; 3276f081693SOlga Kornievskaia } 3285b7eb784SOlga Kornievskaia 3295b7eb784SOlga Kornievskaia release_tasks: 3305b7eb784SOlga Kornievskaia xprt_release_write(xprt, NULL); 3315b7eb784SOlga Kornievskaia out_put: 3325b7eb784SOlga Kornievskaia xprt_put(xprt); 3335b7eb784SOlga Kornievskaia xprt_switch_put(xps); 3345b7eb784SOlga Kornievskaia return count; 3355b7eb784SOlga Kornievskaia } 3365b7eb784SOlga Kornievskaia 33774678748SOlga Kornievskaia int rpc_sysfs_init(void) 33874678748SOlga Kornievskaia { 33974678748SOlga Kornievskaia rpc_sunrpc_kset = kset_create_and_add("sunrpc", NULL, kernel_kobj); 34074678748SOlga Kornievskaia if (!rpc_sunrpc_kset) 34174678748SOlga Kornievskaia return -ENOMEM; 342baea9944SOlga Kornievskaia rpc_sunrpc_client_kobj = 343baea9944SOlga Kornievskaia rpc_sysfs_object_alloc("rpc-clients", rpc_sunrpc_kset, NULL); 344baea9944SOlga Kornievskaia if (!rpc_sunrpc_client_kobj) 345baea9944SOlga Kornievskaia goto err_client; 346baea9944SOlga Kornievskaia rpc_sunrpc_xprt_switch_kobj = 347baea9944SOlga Kornievskaia rpc_sysfs_object_alloc("xprt-switches", rpc_sunrpc_kset, NULL); 348baea9944SOlga Kornievskaia if (!rpc_sunrpc_xprt_switch_kobj) 349baea9944SOlga Kornievskaia goto err_switch; 35074678748SOlga Kornievskaia return 0; 351baea9944SOlga Kornievskaia err_switch: 352baea9944SOlga Kornievskaia kobject_put(rpc_sunrpc_client_kobj); 353baea9944SOlga Kornievskaia rpc_sunrpc_client_kobj = NULL; 354baea9944SOlga Kornievskaia err_client: 355baea9944SOlga Kornievskaia kset_unregister(rpc_sunrpc_kset); 356baea9944SOlga Kornievskaia rpc_sunrpc_kset = NULL; 357baea9944SOlga Kornievskaia return -ENOMEM; 35874678748SOlga Kornievskaia } 35974678748SOlga Kornievskaia 360c5a382ebSOlga Kornievskaia static void rpc_sysfs_client_release(struct kobject *kobj) 361c5a382ebSOlga Kornievskaia { 362c5a382ebSOlga Kornievskaia struct rpc_sysfs_client *c; 363c5a382ebSOlga Kornievskaia 364c5a382ebSOlga Kornievskaia c = container_of(kobj, struct rpc_sysfs_client, kobject); 365c5a382ebSOlga Kornievskaia kfree(c); 366c5a382ebSOlga Kornievskaia } 367c5a382ebSOlga Kornievskaia 368baea9944SOlga Kornievskaia static void rpc_sysfs_xprt_switch_release(struct kobject *kobj) 369baea9944SOlga Kornievskaia { 370baea9944SOlga Kornievskaia struct rpc_sysfs_xprt_switch *xprt_switch; 371baea9944SOlga Kornievskaia 372baea9944SOlga Kornievskaia xprt_switch = container_of(kobj, struct rpc_sysfs_xprt_switch, kobject); 373baea9944SOlga Kornievskaia kfree(xprt_switch); 374baea9944SOlga Kornievskaia } 375baea9944SOlga Kornievskaia 376d408ebe0SOlga Kornievskaia static void rpc_sysfs_xprt_release(struct kobject *kobj) 377d408ebe0SOlga Kornievskaia { 378d408ebe0SOlga Kornievskaia struct rpc_sysfs_xprt *xprt; 379d408ebe0SOlga Kornievskaia 380d408ebe0SOlga Kornievskaia xprt = container_of(kobj, struct rpc_sysfs_xprt, kobject); 381d408ebe0SOlga Kornievskaia kfree(xprt); 382d408ebe0SOlga Kornievskaia } 383d408ebe0SOlga Kornievskaia 384*02a476d9SGreg Kroah-Hartman static const void *rpc_sysfs_client_namespace(const struct kobject *kobj) 385c5a382ebSOlga Kornievskaia { 386c5a382ebSOlga Kornievskaia return container_of(kobj, struct rpc_sysfs_client, kobject)->net; 387c5a382ebSOlga Kornievskaia } 388c5a382ebSOlga Kornievskaia 389*02a476d9SGreg Kroah-Hartman static const void *rpc_sysfs_xprt_switch_namespace(const struct kobject *kobj) 390baea9944SOlga Kornievskaia { 391baea9944SOlga Kornievskaia return container_of(kobj, struct rpc_sysfs_xprt_switch, kobject)->net; 392baea9944SOlga Kornievskaia } 393baea9944SOlga Kornievskaia 394*02a476d9SGreg Kroah-Hartman static const void *rpc_sysfs_xprt_namespace(const struct kobject *kobj) 395d408ebe0SOlga Kornievskaia { 396d408ebe0SOlga Kornievskaia return container_of(kobj, struct rpc_sysfs_xprt, 397d408ebe0SOlga Kornievskaia kobject)->xprt->xprt_net; 398d408ebe0SOlga Kornievskaia } 399d408ebe0SOlga Kornievskaia 400587bc725SOlga Kornievskaia static struct kobj_attribute rpc_sysfs_xprt_dstaddr = __ATTR(dstaddr, 401587bc725SOlga Kornievskaia 0644, rpc_sysfs_xprt_dstaddr_show, rpc_sysfs_xprt_dstaddr_store); 402587bc725SOlga Kornievskaia 403e44773daSAnna Schumaker static struct kobj_attribute rpc_sysfs_xprt_srcaddr = __ATTR(srcaddr, 404e44773daSAnna Schumaker 0644, rpc_sysfs_xprt_srcaddr_show, NULL); 405e44773daSAnna Schumaker 4064a09651aSOlga Kornievskaia static struct kobj_attribute rpc_sysfs_xprt_info = __ATTR(xprt_info, 4074a09651aSOlga Kornievskaia 0444, rpc_sysfs_xprt_info_show, NULL); 4084a09651aSOlga Kornievskaia 409681d5699SOlga Kornievskaia static struct kobj_attribute rpc_sysfs_xprt_change_state = __ATTR(xprt_state, 4105b7eb784SOlga Kornievskaia 0644, rpc_sysfs_xprt_state_show, rpc_sysfs_xprt_state_change); 411681d5699SOlga Kornievskaia 412587bc725SOlga Kornievskaia static struct attribute *rpc_sysfs_xprt_attrs[] = { 413587bc725SOlga Kornievskaia &rpc_sysfs_xprt_dstaddr.attr, 414e44773daSAnna Schumaker &rpc_sysfs_xprt_srcaddr.attr, 4154a09651aSOlga Kornievskaia &rpc_sysfs_xprt_info.attr, 416681d5699SOlga Kornievskaia &rpc_sysfs_xprt_change_state.attr, 417587bc725SOlga Kornievskaia NULL, 418587bc725SOlga Kornievskaia }; 41986439fa2SGreg Kroah-Hartman ATTRIBUTE_GROUPS(rpc_sysfs_xprt); 420587bc725SOlga Kornievskaia 4210e559035SOlga Kornievskaia static struct kobj_attribute rpc_sysfs_xprt_switch_info = 4220e559035SOlga Kornievskaia __ATTR(xprt_switch_info, 0444, rpc_sysfs_xprt_switch_info_show, NULL); 4230e559035SOlga Kornievskaia 4240e559035SOlga Kornievskaia static struct attribute *rpc_sysfs_xprt_switch_attrs[] = { 4250e559035SOlga Kornievskaia &rpc_sysfs_xprt_switch_info.attr, 4260e559035SOlga Kornievskaia NULL, 4270e559035SOlga Kornievskaia }; 42886439fa2SGreg Kroah-Hartman ATTRIBUTE_GROUPS(rpc_sysfs_xprt_switch); 4290e559035SOlga Kornievskaia 430c5a382ebSOlga Kornievskaia static struct kobj_type rpc_sysfs_client_type = { 431c5a382ebSOlga Kornievskaia .release = rpc_sysfs_client_release, 432c5a382ebSOlga Kornievskaia .sysfs_ops = &kobj_sysfs_ops, 433c5a382ebSOlga Kornievskaia .namespace = rpc_sysfs_client_namespace, 434c5a382ebSOlga Kornievskaia }; 435c5a382ebSOlga Kornievskaia 436baea9944SOlga Kornievskaia static struct kobj_type rpc_sysfs_xprt_switch_type = { 437baea9944SOlga Kornievskaia .release = rpc_sysfs_xprt_switch_release, 43886439fa2SGreg Kroah-Hartman .default_groups = rpc_sysfs_xprt_switch_groups, 439baea9944SOlga Kornievskaia .sysfs_ops = &kobj_sysfs_ops, 440baea9944SOlga Kornievskaia .namespace = rpc_sysfs_xprt_switch_namespace, 441baea9944SOlga Kornievskaia }; 442baea9944SOlga Kornievskaia 443d408ebe0SOlga Kornievskaia static struct kobj_type rpc_sysfs_xprt_type = { 444d408ebe0SOlga Kornievskaia .release = rpc_sysfs_xprt_release, 44586439fa2SGreg Kroah-Hartman .default_groups = rpc_sysfs_xprt_groups, 446d408ebe0SOlga Kornievskaia .sysfs_ops = &kobj_sysfs_ops, 447d408ebe0SOlga Kornievskaia .namespace = rpc_sysfs_xprt_namespace, 448d408ebe0SOlga Kornievskaia }; 449d408ebe0SOlga Kornievskaia 45074678748SOlga Kornievskaia void rpc_sysfs_exit(void) 45174678748SOlga Kornievskaia { 452c441f125SOlga Kornievskaia kobject_put(rpc_sunrpc_client_kobj); 453baea9944SOlga Kornievskaia kobject_put(rpc_sunrpc_xprt_switch_kobj); 45474678748SOlga Kornievskaia kset_unregister(rpc_sunrpc_kset); 45574678748SOlga Kornievskaia } 456c5a382ebSOlga Kornievskaia 457c5a382ebSOlga Kornievskaia static struct rpc_sysfs_client *rpc_sysfs_client_alloc(struct kobject *parent, 458c5a382ebSOlga Kornievskaia struct net *net, 459c5a382ebSOlga Kornievskaia int clid) 460c5a382ebSOlga Kornievskaia { 461c5a382ebSOlga Kornievskaia struct rpc_sysfs_client *p; 462c5a382ebSOlga Kornievskaia 463c5a382ebSOlga Kornievskaia p = kzalloc(sizeof(*p), GFP_KERNEL); 464c5a382ebSOlga Kornievskaia if (p) { 465c5a382ebSOlga Kornievskaia p->net = net; 466c5a382ebSOlga Kornievskaia p->kobject.kset = rpc_sunrpc_kset; 467c5a382ebSOlga Kornievskaia if (kobject_init_and_add(&p->kobject, &rpc_sysfs_client_type, 468c5a382ebSOlga Kornievskaia parent, "clnt-%d", clid) == 0) 469c5a382ebSOlga Kornievskaia return p; 470c5a382ebSOlga Kornievskaia kobject_put(&p->kobject); 471c5a382ebSOlga Kornievskaia } 472c5a382ebSOlga Kornievskaia return NULL; 473c5a382ebSOlga Kornievskaia } 474c5a382ebSOlga Kornievskaia 475baea9944SOlga Kornievskaia static struct rpc_sysfs_xprt_switch * 476baea9944SOlga Kornievskaia rpc_sysfs_xprt_switch_alloc(struct kobject *parent, 477baea9944SOlga Kornievskaia struct rpc_xprt_switch *xprt_switch, 478baea9944SOlga Kornievskaia struct net *net, 479baea9944SOlga Kornievskaia gfp_t gfp_flags) 480baea9944SOlga Kornievskaia { 481baea9944SOlga Kornievskaia struct rpc_sysfs_xprt_switch *p; 482baea9944SOlga Kornievskaia 483baea9944SOlga Kornievskaia p = kzalloc(sizeof(*p), gfp_flags); 484baea9944SOlga Kornievskaia if (p) { 485baea9944SOlga Kornievskaia p->net = net; 486baea9944SOlga Kornievskaia p->kobject.kset = rpc_sunrpc_kset; 487baea9944SOlga Kornievskaia if (kobject_init_and_add(&p->kobject, 488baea9944SOlga Kornievskaia &rpc_sysfs_xprt_switch_type, 489baea9944SOlga Kornievskaia parent, "switch-%d", 490baea9944SOlga Kornievskaia xprt_switch->xps_id) == 0) 491baea9944SOlga Kornievskaia return p; 492baea9944SOlga Kornievskaia kobject_put(&p->kobject); 493baea9944SOlga Kornievskaia } 494baea9944SOlga Kornievskaia return NULL; 495baea9944SOlga Kornievskaia } 496baea9944SOlga Kornievskaia 497d408ebe0SOlga Kornievskaia static struct rpc_sysfs_xprt *rpc_sysfs_xprt_alloc(struct kobject *parent, 498d408ebe0SOlga Kornievskaia struct rpc_xprt *xprt, 499d408ebe0SOlga Kornievskaia gfp_t gfp_flags) 500d408ebe0SOlga Kornievskaia { 501d408ebe0SOlga Kornievskaia struct rpc_sysfs_xprt *p; 502d408ebe0SOlga Kornievskaia 503d408ebe0SOlga Kornievskaia p = kzalloc(sizeof(*p), gfp_flags); 504d408ebe0SOlga Kornievskaia if (!p) 505d408ebe0SOlga Kornievskaia goto out; 506d408ebe0SOlga Kornievskaia p->kobject.kset = rpc_sunrpc_kset; 507d408ebe0SOlga Kornievskaia if (kobject_init_and_add(&p->kobject, &rpc_sysfs_xprt_type, 508d408ebe0SOlga Kornievskaia parent, "xprt-%d-%s", xprt->id, 509d408ebe0SOlga Kornievskaia xprt->address_strings[RPC_DISPLAY_PROTO]) == 0) 510d408ebe0SOlga Kornievskaia return p; 511d408ebe0SOlga Kornievskaia kobject_put(&p->kobject); 512d408ebe0SOlga Kornievskaia out: 513d408ebe0SOlga Kornievskaia return NULL; 514d408ebe0SOlga Kornievskaia } 515d408ebe0SOlga Kornievskaia 5162a338a54SOlga Kornievskaia void rpc_sysfs_client_setup(struct rpc_clnt *clnt, 5172a338a54SOlga Kornievskaia struct rpc_xprt_switch *xprt_switch, 5182a338a54SOlga Kornievskaia struct net *net) 519c5a382ebSOlga Kornievskaia { 520c5a382ebSOlga Kornievskaia struct rpc_sysfs_client *rpc_client; 521cbdeaee9SZhang Xiaoxu struct rpc_sysfs_xprt_switch *xswitch = 522cbdeaee9SZhang Xiaoxu (struct rpc_sysfs_xprt_switch *)xprt_switch->xps_sysfs; 523cbdeaee9SZhang Xiaoxu 524cbdeaee9SZhang Xiaoxu if (!xswitch) 525cbdeaee9SZhang Xiaoxu return; 526c5a382ebSOlga Kornievskaia 5272a338a54SOlga Kornievskaia rpc_client = rpc_sysfs_client_alloc(rpc_sunrpc_client_kobj, 5282a338a54SOlga Kornievskaia net, clnt->cl_clid); 529c5a382ebSOlga Kornievskaia if (rpc_client) { 5302a338a54SOlga Kornievskaia char name[] = "switch"; 5312a338a54SOlga Kornievskaia int ret; 5322a338a54SOlga Kornievskaia 533c5a382ebSOlga Kornievskaia clnt->cl_sysfs = rpc_client; 5342a338a54SOlga Kornievskaia rpc_client->clnt = clnt; 5352a338a54SOlga Kornievskaia rpc_client->xprt_switch = xprt_switch; 536c5a382ebSOlga Kornievskaia kobject_uevent(&rpc_client->kobject, KOBJ_ADD); 5372a338a54SOlga Kornievskaia ret = sysfs_create_link_nowarn(&rpc_client->kobject, 5382a338a54SOlga Kornievskaia &xswitch->kobject, name); 5392a338a54SOlga Kornievskaia if (ret) 5402a338a54SOlga Kornievskaia pr_warn("can't create link to %s in sysfs (%d)\n", 5412a338a54SOlga Kornievskaia name, ret); 542c5a382ebSOlga Kornievskaia } 543c5a382ebSOlga Kornievskaia } 544c5a382ebSOlga Kornievskaia 545baea9944SOlga Kornievskaia void rpc_sysfs_xprt_switch_setup(struct rpc_xprt_switch *xprt_switch, 546baea9944SOlga Kornievskaia struct rpc_xprt *xprt, 547baea9944SOlga Kornievskaia gfp_t gfp_flags) 548baea9944SOlga Kornievskaia { 549baea9944SOlga Kornievskaia struct rpc_sysfs_xprt_switch *rpc_xprt_switch; 550baea9944SOlga Kornievskaia struct net *net; 551baea9944SOlga Kornievskaia 552baea9944SOlga Kornievskaia if (xprt_switch->xps_net) 553baea9944SOlga Kornievskaia net = xprt_switch->xps_net; 554baea9944SOlga Kornievskaia else 555baea9944SOlga Kornievskaia net = xprt->xprt_net; 556baea9944SOlga Kornievskaia rpc_xprt_switch = 557baea9944SOlga Kornievskaia rpc_sysfs_xprt_switch_alloc(rpc_sunrpc_xprt_switch_kobj, 558baea9944SOlga Kornievskaia xprt_switch, net, gfp_flags); 559baea9944SOlga Kornievskaia if (rpc_xprt_switch) { 560baea9944SOlga Kornievskaia xprt_switch->xps_sysfs = rpc_xprt_switch; 561baea9944SOlga Kornievskaia rpc_xprt_switch->xprt_switch = xprt_switch; 562baea9944SOlga Kornievskaia rpc_xprt_switch->xprt = xprt; 563baea9944SOlga Kornievskaia kobject_uevent(&rpc_xprt_switch->kobject, KOBJ_ADD); 564cbdeaee9SZhang Xiaoxu } else { 565cbdeaee9SZhang Xiaoxu xprt_switch->xps_sysfs = NULL; 566baea9944SOlga Kornievskaia } 567baea9944SOlga Kornievskaia } 568baea9944SOlga Kornievskaia 569d408ebe0SOlga Kornievskaia void rpc_sysfs_xprt_setup(struct rpc_xprt_switch *xprt_switch, 570d408ebe0SOlga Kornievskaia struct rpc_xprt *xprt, 571d408ebe0SOlga Kornievskaia gfp_t gfp_flags) 572d408ebe0SOlga Kornievskaia { 573d408ebe0SOlga Kornievskaia struct rpc_sysfs_xprt *rpc_xprt; 574d408ebe0SOlga Kornievskaia struct rpc_sysfs_xprt_switch *switch_obj = 575d408ebe0SOlga Kornievskaia (struct rpc_sysfs_xprt_switch *)xprt_switch->xps_sysfs; 576d408ebe0SOlga Kornievskaia 577cbdeaee9SZhang Xiaoxu if (!switch_obj) 578cbdeaee9SZhang Xiaoxu return; 579cbdeaee9SZhang Xiaoxu 580d408ebe0SOlga Kornievskaia rpc_xprt = rpc_sysfs_xprt_alloc(&switch_obj->kobject, xprt, gfp_flags); 581d408ebe0SOlga Kornievskaia if (rpc_xprt) { 582d408ebe0SOlga Kornievskaia xprt->xprt_sysfs = rpc_xprt; 583d408ebe0SOlga Kornievskaia rpc_xprt->xprt = xprt; 5845b7eb784SOlga Kornievskaia rpc_xprt->xprt_switch = xprt_switch; 585d408ebe0SOlga Kornievskaia kobject_uevent(&rpc_xprt->kobject, KOBJ_ADD); 586d408ebe0SOlga Kornievskaia } 587d408ebe0SOlga Kornievskaia } 588d408ebe0SOlga Kornievskaia 589c5a382ebSOlga Kornievskaia void rpc_sysfs_client_destroy(struct rpc_clnt *clnt) 590c5a382ebSOlga Kornievskaia { 591c5a382ebSOlga Kornievskaia struct rpc_sysfs_client *rpc_client = clnt->cl_sysfs; 592c5a382ebSOlga Kornievskaia 593c5a382ebSOlga Kornievskaia if (rpc_client) { 5942a338a54SOlga Kornievskaia char name[] = "switch"; 5952a338a54SOlga Kornievskaia 5962a338a54SOlga Kornievskaia sysfs_remove_link(&rpc_client->kobject, name); 597c5a382ebSOlga Kornievskaia kobject_uevent(&rpc_client->kobject, KOBJ_REMOVE); 598c5a382ebSOlga Kornievskaia kobject_del(&rpc_client->kobject); 599c5a382ebSOlga Kornievskaia kobject_put(&rpc_client->kobject); 600c5a382ebSOlga Kornievskaia clnt->cl_sysfs = NULL; 601c5a382ebSOlga Kornievskaia } 602c5a382ebSOlga Kornievskaia } 603baea9944SOlga Kornievskaia 604baea9944SOlga Kornievskaia void rpc_sysfs_xprt_switch_destroy(struct rpc_xprt_switch *xprt_switch) 605baea9944SOlga Kornievskaia { 606baea9944SOlga Kornievskaia struct rpc_sysfs_xprt_switch *rpc_xprt_switch = xprt_switch->xps_sysfs; 607baea9944SOlga Kornievskaia 608baea9944SOlga Kornievskaia if (rpc_xprt_switch) { 609baea9944SOlga Kornievskaia kobject_uevent(&rpc_xprt_switch->kobject, KOBJ_REMOVE); 610baea9944SOlga Kornievskaia kobject_del(&rpc_xprt_switch->kobject); 611baea9944SOlga Kornievskaia kobject_put(&rpc_xprt_switch->kobject); 612baea9944SOlga Kornievskaia xprt_switch->xps_sysfs = NULL; 613baea9944SOlga Kornievskaia } 614baea9944SOlga Kornievskaia } 615d408ebe0SOlga Kornievskaia 616d408ebe0SOlga Kornievskaia void rpc_sysfs_xprt_destroy(struct rpc_xprt *xprt) 617d408ebe0SOlga Kornievskaia { 618d408ebe0SOlga Kornievskaia struct rpc_sysfs_xprt *rpc_xprt = xprt->xprt_sysfs; 619d408ebe0SOlga Kornievskaia 620d408ebe0SOlga Kornievskaia if (rpc_xprt) { 621d408ebe0SOlga Kornievskaia kobject_uevent(&rpc_xprt->kobject, KOBJ_REMOVE); 622d408ebe0SOlga Kornievskaia kobject_del(&rpc_xprt->kobject); 623d408ebe0SOlga Kornievskaia kobject_put(&rpc_xprt->kobject); 624d408ebe0SOlga Kornievskaia xprt->xprt_sysfs = NULL; 625d408ebe0SOlga Kornievskaia } 626d408ebe0SOlga Kornievskaia } 627