162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2020 Anna Schumaker <Anna.Schumaker@Netapp.com> 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci#include <linux/sunrpc/clnt.h> 662306a36Sopenharmony_ci#include <linux/kobject.h> 762306a36Sopenharmony_ci#include <linux/sunrpc/addr.h> 862306a36Sopenharmony_ci#include <linux/sunrpc/xprtsock.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "sysfs.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_cistruct xprt_addr { 1362306a36Sopenharmony_ci const char *addr; 1462306a36Sopenharmony_ci struct rcu_head rcu; 1562306a36Sopenharmony_ci}; 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cistatic void free_xprt_addr(struct rcu_head *head) 1862306a36Sopenharmony_ci{ 1962306a36Sopenharmony_ci struct xprt_addr *addr = container_of(head, struct xprt_addr, rcu); 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci kfree(addr->addr); 2262306a36Sopenharmony_ci kfree(addr); 2362306a36Sopenharmony_ci} 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic struct kset *rpc_sunrpc_kset; 2662306a36Sopenharmony_cistatic struct kobject *rpc_sunrpc_client_kobj, *rpc_sunrpc_xprt_switch_kobj; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic void rpc_sysfs_object_release(struct kobject *kobj) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci kfree(kobj); 3162306a36Sopenharmony_ci} 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic const struct kobj_ns_type_operations * 3462306a36Sopenharmony_cirpc_sysfs_object_child_ns_type(const struct kobject *kobj) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci return &net_ns_type_operations; 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic const struct kobj_type rpc_sysfs_object_type = { 4062306a36Sopenharmony_ci .release = rpc_sysfs_object_release, 4162306a36Sopenharmony_ci .sysfs_ops = &kobj_sysfs_ops, 4262306a36Sopenharmony_ci .child_ns_type = rpc_sysfs_object_child_ns_type, 4362306a36Sopenharmony_ci}; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic struct kobject *rpc_sysfs_object_alloc(const char *name, 4662306a36Sopenharmony_ci struct kset *kset, 4762306a36Sopenharmony_ci struct kobject *parent) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci struct kobject *kobj; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci kobj = kzalloc(sizeof(*kobj), GFP_KERNEL); 5262306a36Sopenharmony_ci if (kobj) { 5362306a36Sopenharmony_ci kobj->kset = kset; 5462306a36Sopenharmony_ci if (kobject_init_and_add(kobj, &rpc_sysfs_object_type, 5562306a36Sopenharmony_ci parent, "%s", name) == 0) 5662306a36Sopenharmony_ci return kobj; 5762306a36Sopenharmony_ci kobject_put(kobj); 5862306a36Sopenharmony_ci } 5962306a36Sopenharmony_ci return NULL; 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic inline struct rpc_xprt * 6362306a36Sopenharmony_cirpc_sysfs_xprt_kobj_get_xprt(struct kobject *kobj) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci struct rpc_sysfs_xprt *x = container_of(kobj, 6662306a36Sopenharmony_ci struct rpc_sysfs_xprt, kobject); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci return xprt_get(x->xprt); 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic inline struct rpc_xprt_switch * 7262306a36Sopenharmony_cirpc_sysfs_xprt_kobj_get_xprt_switch(struct kobject *kobj) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci struct rpc_sysfs_xprt *x = container_of(kobj, 7562306a36Sopenharmony_ci struct rpc_sysfs_xprt, kobject); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci return xprt_switch_get(x->xprt_switch); 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic inline struct rpc_xprt_switch * 8162306a36Sopenharmony_cirpc_sysfs_xprt_switch_kobj_get_xprt(struct kobject *kobj) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci struct rpc_sysfs_xprt_switch *x = container_of(kobj, 8462306a36Sopenharmony_ci struct rpc_sysfs_xprt_switch, kobject); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci return xprt_switch_get(x->xprt_switch); 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic ssize_t rpc_sysfs_xprt_dstaddr_show(struct kobject *kobj, 9062306a36Sopenharmony_ci struct kobj_attribute *attr, 9162306a36Sopenharmony_ci char *buf) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj); 9462306a36Sopenharmony_ci ssize_t ret; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci if (!xprt) { 9762306a36Sopenharmony_ci ret = sprintf(buf, "<closed>\n"); 9862306a36Sopenharmony_ci goto out; 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci ret = sprintf(buf, "%s\n", xprt->address_strings[RPC_DISPLAY_ADDR]); 10162306a36Sopenharmony_ci xprt_put(xprt); 10262306a36Sopenharmony_ciout: 10362306a36Sopenharmony_ci return ret; 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic ssize_t rpc_sysfs_xprt_srcaddr_show(struct kobject *kobj, 10762306a36Sopenharmony_ci struct kobj_attribute *attr, 10862306a36Sopenharmony_ci char *buf) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj); 11162306a36Sopenharmony_ci size_t buflen = PAGE_SIZE; 11262306a36Sopenharmony_ci ssize_t ret; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci if (!xprt || !xprt_connected(xprt)) { 11562306a36Sopenharmony_ci ret = sprintf(buf, "<closed>\n"); 11662306a36Sopenharmony_ci } else if (xprt->ops->get_srcaddr) { 11762306a36Sopenharmony_ci ret = xprt->ops->get_srcaddr(xprt, buf, buflen); 11862306a36Sopenharmony_ci if (ret > 0) { 11962306a36Sopenharmony_ci if (ret < buflen - 1) { 12062306a36Sopenharmony_ci buf[ret] = '\n'; 12162306a36Sopenharmony_ci ret++; 12262306a36Sopenharmony_ci buf[ret] = '\0'; 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci } else 12562306a36Sopenharmony_ci ret = sprintf(buf, "<closed>\n"); 12662306a36Sopenharmony_ci } else 12762306a36Sopenharmony_ci ret = sprintf(buf, "<not a socket>\n"); 12862306a36Sopenharmony_ci xprt_put(xprt); 12962306a36Sopenharmony_ci return ret; 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic ssize_t rpc_sysfs_xprt_info_show(struct kobject *kobj, 13362306a36Sopenharmony_ci struct kobj_attribute *attr, char *buf) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj); 13662306a36Sopenharmony_ci unsigned short srcport = 0; 13762306a36Sopenharmony_ci size_t buflen = PAGE_SIZE; 13862306a36Sopenharmony_ci ssize_t ret; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci if (!xprt || !xprt_connected(xprt)) { 14162306a36Sopenharmony_ci ret = sprintf(buf, "<closed>\n"); 14262306a36Sopenharmony_ci goto out; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci if (xprt->ops->get_srcport) 14662306a36Sopenharmony_ci srcport = xprt->ops->get_srcport(xprt); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci ret = snprintf(buf, buflen, 14962306a36Sopenharmony_ci "last_used=%lu\ncur_cong=%lu\ncong_win=%lu\n" 15062306a36Sopenharmony_ci "max_num_slots=%u\nmin_num_slots=%u\nnum_reqs=%u\n" 15162306a36Sopenharmony_ci "binding_q_len=%u\nsending_q_len=%u\npending_q_len=%u\n" 15262306a36Sopenharmony_ci "backlog_q_len=%u\nmain_xprt=%d\nsrc_port=%u\n" 15362306a36Sopenharmony_ci "tasks_queuelen=%ld\ndst_port=%s\n", 15462306a36Sopenharmony_ci xprt->last_used, xprt->cong, xprt->cwnd, xprt->max_reqs, 15562306a36Sopenharmony_ci xprt->min_reqs, xprt->num_reqs, xprt->binding.qlen, 15662306a36Sopenharmony_ci xprt->sending.qlen, xprt->pending.qlen, 15762306a36Sopenharmony_ci xprt->backlog.qlen, xprt->main, srcport, 15862306a36Sopenharmony_ci atomic_long_read(&xprt->queuelen), 15962306a36Sopenharmony_ci xprt->address_strings[RPC_DISPLAY_PORT]); 16062306a36Sopenharmony_ciout: 16162306a36Sopenharmony_ci xprt_put(xprt); 16262306a36Sopenharmony_ci return ret; 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic ssize_t rpc_sysfs_xprt_state_show(struct kobject *kobj, 16662306a36Sopenharmony_ci struct kobj_attribute *attr, 16762306a36Sopenharmony_ci char *buf) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj); 17062306a36Sopenharmony_ci ssize_t ret; 17162306a36Sopenharmony_ci int locked, connected, connecting, close_wait, bound, binding, 17262306a36Sopenharmony_ci closing, congested, cwnd_wait, write_space, offline, remove; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci if (!(xprt && xprt->state)) { 17562306a36Sopenharmony_ci ret = sprintf(buf, "state=CLOSED\n"); 17662306a36Sopenharmony_ci } else { 17762306a36Sopenharmony_ci locked = test_bit(XPRT_LOCKED, &xprt->state); 17862306a36Sopenharmony_ci connected = test_bit(XPRT_CONNECTED, &xprt->state); 17962306a36Sopenharmony_ci connecting = test_bit(XPRT_CONNECTING, &xprt->state); 18062306a36Sopenharmony_ci close_wait = test_bit(XPRT_CLOSE_WAIT, &xprt->state); 18162306a36Sopenharmony_ci bound = test_bit(XPRT_BOUND, &xprt->state); 18262306a36Sopenharmony_ci binding = test_bit(XPRT_BINDING, &xprt->state); 18362306a36Sopenharmony_ci closing = test_bit(XPRT_CLOSING, &xprt->state); 18462306a36Sopenharmony_ci congested = test_bit(XPRT_CONGESTED, &xprt->state); 18562306a36Sopenharmony_ci cwnd_wait = test_bit(XPRT_CWND_WAIT, &xprt->state); 18662306a36Sopenharmony_ci write_space = test_bit(XPRT_WRITE_SPACE, &xprt->state); 18762306a36Sopenharmony_ci offline = test_bit(XPRT_OFFLINE, &xprt->state); 18862306a36Sopenharmony_ci remove = test_bit(XPRT_REMOVE, &xprt->state); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci ret = sprintf(buf, "state=%s %s %s %s %s %s %s %s %s %s %s %s\n", 19162306a36Sopenharmony_ci locked ? "LOCKED" : "", 19262306a36Sopenharmony_ci connected ? "CONNECTED" : "", 19362306a36Sopenharmony_ci connecting ? "CONNECTING" : "", 19462306a36Sopenharmony_ci close_wait ? "CLOSE_WAIT" : "", 19562306a36Sopenharmony_ci bound ? "BOUND" : "", 19662306a36Sopenharmony_ci binding ? "BOUNDING" : "", 19762306a36Sopenharmony_ci closing ? "CLOSING" : "", 19862306a36Sopenharmony_ci congested ? "CONGESTED" : "", 19962306a36Sopenharmony_ci cwnd_wait ? "CWND_WAIT" : "", 20062306a36Sopenharmony_ci write_space ? "WRITE_SPACE" : "", 20162306a36Sopenharmony_ci offline ? "OFFLINE" : "", 20262306a36Sopenharmony_ci remove ? "REMOVE" : ""); 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci xprt_put(xprt); 20662306a36Sopenharmony_ci return ret; 20762306a36Sopenharmony_ci} 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic ssize_t rpc_sysfs_xprt_switch_info_show(struct kobject *kobj, 21062306a36Sopenharmony_ci struct kobj_attribute *attr, 21162306a36Sopenharmony_ci char *buf) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci struct rpc_xprt_switch *xprt_switch = 21462306a36Sopenharmony_ci rpc_sysfs_xprt_switch_kobj_get_xprt(kobj); 21562306a36Sopenharmony_ci ssize_t ret; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci if (!xprt_switch) 21862306a36Sopenharmony_ci return 0; 21962306a36Sopenharmony_ci ret = sprintf(buf, "num_xprts=%u\nnum_active=%u\n" 22062306a36Sopenharmony_ci "num_unique_destaddr=%u\nqueue_len=%ld\n", 22162306a36Sopenharmony_ci xprt_switch->xps_nxprts, xprt_switch->xps_nactive, 22262306a36Sopenharmony_ci xprt_switch->xps_nunique_destaddr_xprts, 22362306a36Sopenharmony_ci atomic_long_read(&xprt_switch->xps_queuelen)); 22462306a36Sopenharmony_ci xprt_switch_put(xprt_switch); 22562306a36Sopenharmony_ci return ret; 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic ssize_t rpc_sysfs_xprt_dstaddr_store(struct kobject *kobj, 22962306a36Sopenharmony_ci struct kobj_attribute *attr, 23062306a36Sopenharmony_ci const char *buf, size_t count) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj); 23362306a36Sopenharmony_ci struct sockaddr *saddr; 23462306a36Sopenharmony_ci char *dst_addr; 23562306a36Sopenharmony_ci int port; 23662306a36Sopenharmony_ci struct xprt_addr *saved_addr; 23762306a36Sopenharmony_ci size_t buf_len; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci if (!xprt) 24062306a36Sopenharmony_ci return 0; 24162306a36Sopenharmony_ci if (!(xprt->xprt_class->ident == XPRT_TRANSPORT_TCP || 24262306a36Sopenharmony_ci xprt->xprt_class->ident == XPRT_TRANSPORT_TCP_TLS || 24362306a36Sopenharmony_ci xprt->xprt_class->ident == XPRT_TRANSPORT_RDMA)) { 24462306a36Sopenharmony_ci xprt_put(xprt); 24562306a36Sopenharmony_ci return -EOPNOTSUPP; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci if (wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_KILLABLE)) { 24962306a36Sopenharmony_ci count = -EINTR; 25062306a36Sopenharmony_ci goto out_put; 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci saddr = (struct sockaddr *)&xprt->addr; 25362306a36Sopenharmony_ci port = rpc_get_port(saddr); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci /* buf_len is the len until the first occurence of either 25662306a36Sopenharmony_ci * '\n' or '\0' 25762306a36Sopenharmony_ci */ 25862306a36Sopenharmony_ci buf_len = strcspn(buf, "\n"); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci dst_addr = kstrndup(buf, buf_len, GFP_KERNEL); 26162306a36Sopenharmony_ci if (!dst_addr) 26262306a36Sopenharmony_ci goto out_err; 26362306a36Sopenharmony_ci saved_addr = kzalloc(sizeof(*saved_addr), GFP_KERNEL); 26462306a36Sopenharmony_ci if (!saved_addr) 26562306a36Sopenharmony_ci goto out_err_free; 26662306a36Sopenharmony_ci saved_addr->addr = 26762306a36Sopenharmony_ci rcu_dereference_raw(xprt->address_strings[RPC_DISPLAY_ADDR]); 26862306a36Sopenharmony_ci rcu_assign_pointer(xprt->address_strings[RPC_DISPLAY_ADDR], dst_addr); 26962306a36Sopenharmony_ci call_rcu(&saved_addr->rcu, free_xprt_addr); 27062306a36Sopenharmony_ci xprt->addrlen = rpc_pton(xprt->xprt_net, buf, buf_len, saddr, 27162306a36Sopenharmony_ci sizeof(*saddr)); 27262306a36Sopenharmony_ci rpc_set_port(saddr, port); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci xprt_force_disconnect(xprt); 27562306a36Sopenharmony_ciout: 27662306a36Sopenharmony_ci xprt_release_write(xprt, NULL); 27762306a36Sopenharmony_ciout_put: 27862306a36Sopenharmony_ci xprt_put(xprt); 27962306a36Sopenharmony_ci return count; 28062306a36Sopenharmony_ciout_err_free: 28162306a36Sopenharmony_ci kfree(dst_addr); 28262306a36Sopenharmony_ciout_err: 28362306a36Sopenharmony_ci count = -ENOMEM; 28462306a36Sopenharmony_ci goto out; 28562306a36Sopenharmony_ci} 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_cistatic ssize_t rpc_sysfs_xprt_state_change(struct kobject *kobj, 28862306a36Sopenharmony_ci struct kobj_attribute *attr, 28962306a36Sopenharmony_ci const char *buf, size_t count) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj); 29262306a36Sopenharmony_ci int offline = 0, online = 0, remove = 0; 29362306a36Sopenharmony_ci struct rpc_xprt_switch *xps = rpc_sysfs_xprt_kobj_get_xprt_switch(kobj); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci if (!xprt || !xps) { 29662306a36Sopenharmony_ci count = 0; 29762306a36Sopenharmony_ci goto out_put; 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci if (!strncmp(buf, "offline", 7)) 30162306a36Sopenharmony_ci offline = 1; 30262306a36Sopenharmony_ci else if (!strncmp(buf, "online", 6)) 30362306a36Sopenharmony_ci online = 1; 30462306a36Sopenharmony_ci else if (!strncmp(buf, "remove", 6)) 30562306a36Sopenharmony_ci remove = 1; 30662306a36Sopenharmony_ci else { 30762306a36Sopenharmony_ci count = -EINVAL; 30862306a36Sopenharmony_ci goto out_put; 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci if (wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_KILLABLE)) { 31262306a36Sopenharmony_ci count = -EINTR; 31362306a36Sopenharmony_ci goto out_put; 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci if (xprt->main) { 31662306a36Sopenharmony_ci count = -EINVAL; 31762306a36Sopenharmony_ci goto release_tasks; 31862306a36Sopenharmony_ci } 31962306a36Sopenharmony_ci if (offline) { 32062306a36Sopenharmony_ci xprt_set_offline_locked(xprt, xps); 32162306a36Sopenharmony_ci } else if (online) { 32262306a36Sopenharmony_ci xprt_set_online_locked(xprt, xps); 32362306a36Sopenharmony_ci } else if (remove) { 32462306a36Sopenharmony_ci if (test_bit(XPRT_OFFLINE, &xprt->state)) 32562306a36Sopenharmony_ci xprt_delete_locked(xprt, xps); 32662306a36Sopenharmony_ci else 32762306a36Sopenharmony_ci count = -EINVAL; 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_cirelease_tasks: 33162306a36Sopenharmony_ci xprt_release_write(xprt, NULL); 33262306a36Sopenharmony_ciout_put: 33362306a36Sopenharmony_ci xprt_put(xprt); 33462306a36Sopenharmony_ci xprt_switch_put(xps); 33562306a36Sopenharmony_ci return count; 33662306a36Sopenharmony_ci} 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ciint rpc_sysfs_init(void) 33962306a36Sopenharmony_ci{ 34062306a36Sopenharmony_ci rpc_sunrpc_kset = kset_create_and_add("sunrpc", NULL, kernel_kobj); 34162306a36Sopenharmony_ci if (!rpc_sunrpc_kset) 34262306a36Sopenharmony_ci return -ENOMEM; 34362306a36Sopenharmony_ci rpc_sunrpc_client_kobj = 34462306a36Sopenharmony_ci rpc_sysfs_object_alloc("rpc-clients", rpc_sunrpc_kset, NULL); 34562306a36Sopenharmony_ci if (!rpc_sunrpc_client_kobj) 34662306a36Sopenharmony_ci goto err_client; 34762306a36Sopenharmony_ci rpc_sunrpc_xprt_switch_kobj = 34862306a36Sopenharmony_ci rpc_sysfs_object_alloc("xprt-switches", rpc_sunrpc_kset, NULL); 34962306a36Sopenharmony_ci if (!rpc_sunrpc_xprt_switch_kobj) 35062306a36Sopenharmony_ci goto err_switch; 35162306a36Sopenharmony_ci return 0; 35262306a36Sopenharmony_cierr_switch: 35362306a36Sopenharmony_ci kobject_put(rpc_sunrpc_client_kobj); 35462306a36Sopenharmony_ci rpc_sunrpc_client_kobj = NULL; 35562306a36Sopenharmony_cierr_client: 35662306a36Sopenharmony_ci kset_unregister(rpc_sunrpc_kset); 35762306a36Sopenharmony_ci rpc_sunrpc_kset = NULL; 35862306a36Sopenharmony_ci return -ENOMEM; 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_cistatic void rpc_sysfs_client_release(struct kobject *kobj) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci struct rpc_sysfs_client *c; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci c = container_of(kobj, struct rpc_sysfs_client, kobject); 36662306a36Sopenharmony_ci kfree(c); 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_cistatic void rpc_sysfs_xprt_switch_release(struct kobject *kobj) 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci struct rpc_sysfs_xprt_switch *xprt_switch; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci xprt_switch = container_of(kobj, struct rpc_sysfs_xprt_switch, kobject); 37462306a36Sopenharmony_ci kfree(xprt_switch); 37562306a36Sopenharmony_ci} 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_cistatic void rpc_sysfs_xprt_release(struct kobject *kobj) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci struct rpc_sysfs_xprt *xprt; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci xprt = container_of(kobj, struct rpc_sysfs_xprt, kobject); 38262306a36Sopenharmony_ci kfree(xprt); 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_cistatic const void *rpc_sysfs_client_namespace(const struct kobject *kobj) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci return container_of(kobj, struct rpc_sysfs_client, kobject)->net; 38862306a36Sopenharmony_ci} 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_cistatic const void *rpc_sysfs_xprt_switch_namespace(const struct kobject *kobj) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci return container_of(kobj, struct rpc_sysfs_xprt_switch, kobject)->net; 39362306a36Sopenharmony_ci} 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_cistatic const void *rpc_sysfs_xprt_namespace(const struct kobject *kobj) 39662306a36Sopenharmony_ci{ 39762306a36Sopenharmony_ci return container_of(kobj, struct rpc_sysfs_xprt, 39862306a36Sopenharmony_ci kobject)->xprt->xprt_net; 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_cistatic struct kobj_attribute rpc_sysfs_xprt_dstaddr = __ATTR(dstaddr, 40262306a36Sopenharmony_ci 0644, rpc_sysfs_xprt_dstaddr_show, rpc_sysfs_xprt_dstaddr_store); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_cistatic struct kobj_attribute rpc_sysfs_xprt_srcaddr = __ATTR(srcaddr, 40562306a36Sopenharmony_ci 0644, rpc_sysfs_xprt_srcaddr_show, NULL); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_cistatic struct kobj_attribute rpc_sysfs_xprt_info = __ATTR(xprt_info, 40862306a36Sopenharmony_ci 0444, rpc_sysfs_xprt_info_show, NULL); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_cistatic struct kobj_attribute rpc_sysfs_xprt_change_state = __ATTR(xprt_state, 41162306a36Sopenharmony_ci 0644, rpc_sysfs_xprt_state_show, rpc_sysfs_xprt_state_change); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_cistatic struct attribute *rpc_sysfs_xprt_attrs[] = { 41462306a36Sopenharmony_ci &rpc_sysfs_xprt_dstaddr.attr, 41562306a36Sopenharmony_ci &rpc_sysfs_xprt_srcaddr.attr, 41662306a36Sopenharmony_ci &rpc_sysfs_xprt_info.attr, 41762306a36Sopenharmony_ci &rpc_sysfs_xprt_change_state.attr, 41862306a36Sopenharmony_ci NULL, 41962306a36Sopenharmony_ci}; 42062306a36Sopenharmony_ciATTRIBUTE_GROUPS(rpc_sysfs_xprt); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_cistatic struct kobj_attribute rpc_sysfs_xprt_switch_info = 42362306a36Sopenharmony_ci __ATTR(xprt_switch_info, 0444, rpc_sysfs_xprt_switch_info_show, NULL); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_cistatic struct attribute *rpc_sysfs_xprt_switch_attrs[] = { 42662306a36Sopenharmony_ci &rpc_sysfs_xprt_switch_info.attr, 42762306a36Sopenharmony_ci NULL, 42862306a36Sopenharmony_ci}; 42962306a36Sopenharmony_ciATTRIBUTE_GROUPS(rpc_sysfs_xprt_switch); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cistatic const struct kobj_type rpc_sysfs_client_type = { 43262306a36Sopenharmony_ci .release = rpc_sysfs_client_release, 43362306a36Sopenharmony_ci .sysfs_ops = &kobj_sysfs_ops, 43462306a36Sopenharmony_ci .namespace = rpc_sysfs_client_namespace, 43562306a36Sopenharmony_ci}; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic const struct kobj_type rpc_sysfs_xprt_switch_type = { 43862306a36Sopenharmony_ci .release = rpc_sysfs_xprt_switch_release, 43962306a36Sopenharmony_ci .default_groups = rpc_sysfs_xprt_switch_groups, 44062306a36Sopenharmony_ci .sysfs_ops = &kobj_sysfs_ops, 44162306a36Sopenharmony_ci .namespace = rpc_sysfs_xprt_switch_namespace, 44262306a36Sopenharmony_ci}; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_cistatic const struct kobj_type rpc_sysfs_xprt_type = { 44562306a36Sopenharmony_ci .release = rpc_sysfs_xprt_release, 44662306a36Sopenharmony_ci .default_groups = rpc_sysfs_xprt_groups, 44762306a36Sopenharmony_ci .sysfs_ops = &kobj_sysfs_ops, 44862306a36Sopenharmony_ci .namespace = rpc_sysfs_xprt_namespace, 44962306a36Sopenharmony_ci}; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_civoid rpc_sysfs_exit(void) 45262306a36Sopenharmony_ci{ 45362306a36Sopenharmony_ci kobject_put(rpc_sunrpc_client_kobj); 45462306a36Sopenharmony_ci kobject_put(rpc_sunrpc_xprt_switch_kobj); 45562306a36Sopenharmony_ci kset_unregister(rpc_sunrpc_kset); 45662306a36Sopenharmony_ci} 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_cistatic struct rpc_sysfs_client *rpc_sysfs_client_alloc(struct kobject *parent, 45962306a36Sopenharmony_ci struct net *net, 46062306a36Sopenharmony_ci int clid) 46162306a36Sopenharmony_ci{ 46262306a36Sopenharmony_ci struct rpc_sysfs_client *p; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci p = kzalloc(sizeof(*p), GFP_KERNEL); 46562306a36Sopenharmony_ci if (p) { 46662306a36Sopenharmony_ci p->net = net; 46762306a36Sopenharmony_ci p->kobject.kset = rpc_sunrpc_kset; 46862306a36Sopenharmony_ci if (kobject_init_and_add(&p->kobject, &rpc_sysfs_client_type, 46962306a36Sopenharmony_ci parent, "clnt-%d", clid) == 0) 47062306a36Sopenharmony_ci return p; 47162306a36Sopenharmony_ci kobject_put(&p->kobject); 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci return NULL; 47462306a36Sopenharmony_ci} 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_cistatic struct rpc_sysfs_xprt_switch * 47762306a36Sopenharmony_cirpc_sysfs_xprt_switch_alloc(struct kobject *parent, 47862306a36Sopenharmony_ci struct rpc_xprt_switch *xprt_switch, 47962306a36Sopenharmony_ci struct net *net, 48062306a36Sopenharmony_ci gfp_t gfp_flags) 48162306a36Sopenharmony_ci{ 48262306a36Sopenharmony_ci struct rpc_sysfs_xprt_switch *p; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci p = kzalloc(sizeof(*p), gfp_flags); 48562306a36Sopenharmony_ci if (p) { 48662306a36Sopenharmony_ci p->net = net; 48762306a36Sopenharmony_ci p->kobject.kset = rpc_sunrpc_kset; 48862306a36Sopenharmony_ci if (kobject_init_and_add(&p->kobject, 48962306a36Sopenharmony_ci &rpc_sysfs_xprt_switch_type, 49062306a36Sopenharmony_ci parent, "switch-%d", 49162306a36Sopenharmony_ci xprt_switch->xps_id) == 0) 49262306a36Sopenharmony_ci return p; 49362306a36Sopenharmony_ci kobject_put(&p->kobject); 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci return NULL; 49662306a36Sopenharmony_ci} 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_cistatic struct rpc_sysfs_xprt *rpc_sysfs_xprt_alloc(struct kobject *parent, 49962306a36Sopenharmony_ci struct rpc_xprt *xprt, 50062306a36Sopenharmony_ci gfp_t gfp_flags) 50162306a36Sopenharmony_ci{ 50262306a36Sopenharmony_ci struct rpc_sysfs_xprt *p; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci p = kzalloc(sizeof(*p), gfp_flags); 50562306a36Sopenharmony_ci if (!p) 50662306a36Sopenharmony_ci goto out; 50762306a36Sopenharmony_ci p->kobject.kset = rpc_sunrpc_kset; 50862306a36Sopenharmony_ci if (kobject_init_and_add(&p->kobject, &rpc_sysfs_xprt_type, 50962306a36Sopenharmony_ci parent, "xprt-%d-%s", xprt->id, 51062306a36Sopenharmony_ci xprt->address_strings[RPC_DISPLAY_PROTO]) == 0) 51162306a36Sopenharmony_ci return p; 51262306a36Sopenharmony_ci kobject_put(&p->kobject); 51362306a36Sopenharmony_ciout: 51462306a36Sopenharmony_ci return NULL; 51562306a36Sopenharmony_ci} 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_civoid rpc_sysfs_client_setup(struct rpc_clnt *clnt, 51862306a36Sopenharmony_ci struct rpc_xprt_switch *xprt_switch, 51962306a36Sopenharmony_ci struct net *net) 52062306a36Sopenharmony_ci{ 52162306a36Sopenharmony_ci struct rpc_sysfs_client *rpc_client; 52262306a36Sopenharmony_ci struct rpc_sysfs_xprt_switch *xswitch = 52362306a36Sopenharmony_ci (struct rpc_sysfs_xprt_switch *)xprt_switch->xps_sysfs; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci if (!xswitch) 52662306a36Sopenharmony_ci return; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci rpc_client = rpc_sysfs_client_alloc(rpc_sunrpc_client_kobj, 52962306a36Sopenharmony_ci net, clnt->cl_clid); 53062306a36Sopenharmony_ci if (rpc_client) { 53162306a36Sopenharmony_ci char name[] = "switch"; 53262306a36Sopenharmony_ci int ret; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci clnt->cl_sysfs = rpc_client; 53562306a36Sopenharmony_ci rpc_client->clnt = clnt; 53662306a36Sopenharmony_ci rpc_client->xprt_switch = xprt_switch; 53762306a36Sopenharmony_ci kobject_uevent(&rpc_client->kobject, KOBJ_ADD); 53862306a36Sopenharmony_ci ret = sysfs_create_link_nowarn(&rpc_client->kobject, 53962306a36Sopenharmony_ci &xswitch->kobject, name); 54062306a36Sopenharmony_ci if (ret) 54162306a36Sopenharmony_ci pr_warn("can't create link to %s in sysfs (%d)\n", 54262306a36Sopenharmony_ci name, ret); 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci} 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_civoid rpc_sysfs_xprt_switch_setup(struct rpc_xprt_switch *xprt_switch, 54762306a36Sopenharmony_ci struct rpc_xprt *xprt, 54862306a36Sopenharmony_ci gfp_t gfp_flags) 54962306a36Sopenharmony_ci{ 55062306a36Sopenharmony_ci struct rpc_sysfs_xprt_switch *rpc_xprt_switch; 55162306a36Sopenharmony_ci struct net *net; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci if (xprt_switch->xps_net) 55462306a36Sopenharmony_ci net = xprt_switch->xps_net; 55562306a36Sopenharmony_ci else 55662306a36Sopenharmony_ci net = xprt->xprt_net; 55762306a36Sopenharmony_ci rpc_xprt_switch = 55862306a36Sopenharmony_ci rpc_sysfs_xprt_switch_alloc(rpc_sunrpc_xprt_switch_kobj, 55962306a36Sopenharmony_ci xprt_switch, net, gfp_flags); 56062306a36Sopenharmony_ci if (rpc_xprt_switch) { 56162306a36Sopenharmony_ci xprt_switch->xps_sysfs = rpc_xprt_switch; 56262306a36Sopenharmony_ci rpc_xprt_switch->xprt_switch = xprt_switch; 56362306a36Sopenharmony_ci rpc_xprt_switch->xprt = xprt; 56462306a36Sopenharmony_ci kobject_uevent(&rpc_xprt_switch->kobject, KOBJ_ADD); 56562306a36Sopenharmony_ci } else { 56662306a36Sopenharmony_ci xprt_switch->xps_sysfs = NULL; 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci} 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_civoid rpc_sysfs_xprt_setup(struct rpc_xprt_switch *xprt_switch, 57162306a36Sopenharmony_ci struct rpc_xprt *xprt, 57262306a36Sopenharmony_ci gfp_t gfp_flags) 57362306a36Sopenharmony_ci{ 57462306a36Sopenharmony_ci struct rpc_sysfs_xprt *rpc_xprt; 57562306a36Sopenharmony_ci struct rpc_sysfs_xprt_switch *switch_obj = 57662306a36Sopenharmony_ci (struct rpc_sysfs_xprt_switch *)xprt_switch->xps_sysfs; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci if (!switch_obj) 57962306a36Sopenharmony_ci return; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci rpc_xprt = rpc_sysfs_xprt_alloc(&switch_obj->kobject, xprt, gfp_flags); 58262306a36Sopenharmony_ci if (rpc_xprt) { 58362306a36Sopenharmony_ci xprt->xprt_sysfs = rpc_xprt; 58462306a36Sopenharmony_ci rpc_xprt->xprt = xprt; 58562306a36Sopenharmony_ci rpc_xprt->xprt_switch = xprt_switch; 58662306a36Sopenharmony_ci kobject_uevent(&rpc_xprt->kobject, KOBJ_ADD); 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci} 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_civoid rpc_sysfs_client_destroy(struct rpc_clnt *clnt) 59162306a36Sopenharmony_ci{ 59262306a36Sopenharmony_ci struct rpc_sysfs_client *rpc_client = clnt->cl_sysfs; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci if (rpc_client) { 59562306a36Sopenharmony_ci char name[] = "switch"; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci sysfs_remove_link(&rpc_client->kobject, name); 59862306a36Sopenharmony_ci kobject_uevent(&rpc_client->kobject, KOBJ_REMOVE); 59962306a36Sopenharmony_ci kobject_del(&rpc_client->kobject); 60062306a36Sopenharmony_ci kobject_put(&rpc_client->kobject); 60162306a36Sopenharmony_ci clnt->cl_sysfs = NULL; 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci} 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_civoid rpc_sysfs_xprt_switch_destroy(struct rpc_xprt_switch *xprt_switch) 60662306a36Sopenharmony_ci{ 60762306a36Sopenharmony_ci struct rpc_sysfs_xprt_switch *rpc_xprt_switch = xprt_switch->xps_sysfs; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci if (rpc_xprt_switch) { 61062306a36Sopenharmony_ci kobject_uevent(&rpc_xprt_switch->kobject, KOBJ_REMOVE); 61162306a36Sopenharmony_ci kobject_del(&rpc_xprt_switch->kobject); 61262306a36Sopenharmony_ci kobject_put(&rpc_xprt_switch->kobject); 61362306a36Sopenharmony_ci xprt_switch->xps_sysfs = NULL; 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci} 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_civoid rpc_sysfs_xprt_destroy(struct rpc_xprt *xprt) 61862306a36Sopenharmony_ci{ 61962306a36Sopenharmony_ci struct rpc_sysfs_xprt *rpc_xprt = xprt->xprt_sysfs; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci if (rpc_xprt) { 62262306a36Sopenharmony_ci kobject_uevent(&rpc_xprt->kobject, KOBJ_REMOVE); 62362306a36Sopenharmony_ci kobject_del(&rpc_xprt->kobject); 62462306a36Sopenharmony_ci kobject_put(&rpc_xprt->kobject); 62562306a36Sopenharmony_ci xprt->xprt_sysfs = NULL; 62662306a36Sopenharmony_ci } 62762306a36Sopenharmony_ci} 628