linux/net/sunrpc/sysfs.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (c) 2020 Anna Schumaker <Anna.Schumaker@Netapp.com>
   4 */
   5#include <linux/sunrpc/clnt.h>
   6#include <linux/kobject.h>
   7#include <linux/sunrpc/addr.h>
   8#include <linux/sunrpc/xprtsock.h>
   9
  10#include "sysfs.h"
  11
  12struct xprt_addr {
  13        const char *addr;
  14        struct rcu_head rcu;
  15};
  16
  17static void free_xprt_addr(struct rcu_head *head)
  18{
  19        struct xprt_addr *addr = container_of(head, struct xprt_addr, rcu);
  20
  21        kfree(addr->addr);
  22        kfree(addr);
  23}
  24
  25static struct kset *rpc_sunrpc_kset;
  26static struct kobject *rpc_sunrpc_client_kobj, *rpc_sunrpc_xprt_switch_kobj;
  27
  28static void rpc_sysfs_object_release(struct kobject *kobj)
  29{
  30        kfree(kobj);
  31}
  32
  33static const struct kobj_ns_type_operations *
  34rpc_sysfs_object_child_ns_type(struct kobject *kobj)
  35{
  36        return &net_ns_type_operations;
  37}
  38
  39static struct kobj_type rpc_sysfs_object_type = {
  40        .release = rpc_sysfs_object_release,
  41        .sysfs_ops = &kobj_sysfs_ops,
  42        .child_ns_type = rpc_sysfs_object_child_ns_type,
  43};
  44
  45static struct kobject *rpc_sysfs_object_alloc(const char *name,
  46                                              struct kset *kset,
  47                                              struct kobject *parent)
  48{
  49        struct kobject *kobj;
  50
  51        kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
  52        if (kobj) {
  53                kobj->kset = kset;
  54                if (kobject_init_and_add(kobj, &rpc_sysfs_object_type,
  55                                         parent, "%s", name) == 0)
  56                        return kobj;
  57                kobject_put(kobj);
  58        }
  59        return NULL;
  60}
  61
  62static inline struct rpc_xprt *
  63rpc_sysfs_xprt_kobj_get_xprt(struct kobject *kobj)
  64{
  65        struct rpc_sysfs_xprt *x = container_of(kobj,
  66                struct rpc_sysfs_xprt, kobject);
  67
  68        return xprt_get(x->xprt);
  69}
  70
  71static inline struct rpc_xprt_switch *
  72rpc_sysfs_xprt_kobj_get_xprt_switch(struct kobject *kobj)
  73{
  74        struct rpc_sysfs_xprt *x = container_of(kobj,
  75                struct rpc_sysfs_xprt, kobject);
  76
  77        return xprt_switch_get(x->xprt_switch);
  78}
  79
  80static inline struct rpc_xprt_switch *
  81rpc_sysfs_xprt_switch_kobj_get_xprt(struct kobject *kobj)
  82{
  83        struct rpc_sysfs_xprt_switch *x = container_of(kobj,
  84                struct rpc_sysfs_xprt_switch, kobject);
  85
  86        return xprt_switch_get(x->xprt_switch);
  87}
  88
  89static ssize_t rpc_sysfs_xprt_dstaddr_show(struct kobject *kobj,
  90                                           struct kobj_attribute *attr,
  91                                           char *buf)
  92{
  93        struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
  94        ssize_t ret;
  95
  96        if (!xprt)
  97                return 0;
  98        ret = sprintf(buf, "%s\n", xprt->address_strings[RPC_DISPLAY_ADDR]);
  99        xprt_put(xprt);
 100        return ret + 1;
 101}
 102
 103static ssize_t rpc_sysfs_xprt_srcaddr_show(struct kobject *kobj,
 104                                           struct kobj_attribute *attr,
 105                                           char *buf)
 106{
 107        struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
 108        struct sockaddr_storage saddr;
 109        struct sock_xprt *sock;
 110        ssize_t ret = -1;
 111
 112        if (!xprt)
 113                return 0;
 114
 115        sock = container_of(xprt, struct sock_xprt, xprt);
 116        if (kernel_getsockname(sock->sock, (struct sockaddr *)&saddr) < 0)
 117                goto out;
 118
 119        ret = sprintf(buf, "%pISc\n", &saddr);
 120out:
 121        xprt_put(xprt);
 122        return ret + 1;
 123}
 124
 125static ssize_t rpc_sysfs_xprt_info_show(struct kobject *kobj,
 126                                        struct kobj_attribute *attr,
 127                                        char *buf)
 128{
 129        struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
 130        ssize_t ret;
 131
 132        if (!xprt)
 133                return 0;
 134
 135        ret = sprintf(buf, "last_used=%lu\ncur_cong=%lu\ncong_win=%lu\n"
 136                       "max_num_slots=%u\nmin_num_slots=%u\nnum_reqs=%u\n"
 137                       "binding_q_len=%u\nsending_q_len=%u\npending_q_len=%u\n"
 138                       "backlog_q_len=%u\nmain_xprt=%d\nsrc_port=%u\n"
 139                       "tasks_queuelen=%ld\ndst_port=%s\n",
 140                       xprt->last_used, xprt->cong, xprt->cwnd, xprt->max_reqs,
 141                       xprt->min_reqs, xprt->num_reqs, xprt->binding.qlen,
 142                       xprt->sending.qlen, xprt->pending.qlen,
 143                       xprt->backlog.qlen, xprt->main,
 144                       (xprt->xprt_class->ident == XPRT_TRANSPORT_TCP) ?
 145                       get_srcport(xprt) : 0,
 146                       atomic_long_read(&xprt->queuelen),
 147                       (xprt->xprt_class->ident == XPRT_TRANSPORT_TCP) ?
 148                                xprt->address_strings[RPC_DISPLAY_PORT] : "0");
 149        xprt_put(xprt);
 150        return ret + 1;
 151}
 152
 153static ssize_t rpc_sysfs_xprt_state_show(struct kobject *kobj,
 154                                         struct kobj_attribute *attr,
 155                                         char *buf)
 156{
 157        struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
 158        ssize_t ret;
 159        int locked, connected, connecting, close_wait, bound, binding,
 160            closing, congested, cwnd_wait, write_space, offline, remove;
 161
 162        if (!xprt)
 163                return 0;
 164
 165        if (!xprt->state) {
 166                ret = sprintf(buf, "state=CLOSED\n");
 167        } else {
 168                locked = test_bit(XPRT_LOCKED, &xprt->state);
 169                connected = test_bit(XPRT_CONNECTED, &xprt->state);
 170                connecting = test_bit(XPRT_CONNECTING, &xprt->state);
 171                close_wait = test_bit(XPRT_CLOSE_WAIT, &xprt->state);
 172                bound = test_bit(XPRT_BOUND, &xprt->state);
 173                binding = test_bit(XPRT_BINDING, &xprt->state);
 174                closing = test_bit(XPRT_CLOSING, &xprt->state);
 175                congested = test_bit(XPRT_CONGESTED, &xprt->state);
 176                cwnd_wait = test_bit(XPRT_CWND_WAIT, &xprt->state);
 177                write_space = test_bit(XPRT_WRITE_SPACE, &xprt->state);
 178                offline = test_bit(XPRT_OFFLINE, &xprt->state);
 179                remove = test_bit(XPRT_REMOVE, &xprt->state);
 180
 181                ret = sprintf(buf, "state=%s %s %s %s %s %s %s %s %s %s %s %s\n",
 182                              locked ? "LOCKED" : "",
 183                              connected ? "CONNECTED" : "",
 184                              connecting ? "CONNECTING" : "",
 185                              close_wait ? "CLOSE_WAIT" : "",
 186                              bound ? "BOUND" : "",
 187                              binding ? "BOUNDING" : "",
 188                              closing ? "CLOSING" : "",
 189                              congested ? "CONGESTED" : "",
 190                              cwnd_wait ? "CWND_WAIT" : "",
 191                              write_space ? "WRITE_SPACE" : "",
 192                              offline ? "OFFLINE" : "",
 193                              remove ? "REMOVE" : "");
 194        }
 195
 196        xprt_put(xprt);
 197        return ret + 1;
 198}
 199
 200static ssize_t rpc_sysfs_xprt_switch_info_show(struct kobject *kobj,
 201                                               struct kobj_attribute *attr,
 202                                               char *buf)
 203{
 204        struct rpc_xprt_switch *xprt_switch =
 205                rpc_sysfs_xprt_switch_kobj_get_xprt(kobj);
 206        ssize_t ret;
 207
 208        if (!xprt_switch)
 209                return 0;
 210        ret = sprintf(buf, "num_xprts=%u\nnum_active=%u\n"
 211                      "num_unique_destaddr=%u\nqueue_len=%ld\n",
 212                      xprt_switch->xps_nxprts, xprt_switch->xps_nactive,
 213                      xprt_switch->xps_nunique_destaddr_xprts,
 214                      atomic_long_read(&xprt_switch->xps_queuelen));
 215        xprt_switch_put(xprt_switch);
 216        return ret + 1;
 217}
 218
 219static ssize_t rpc_sysfs_xprt_dstaddr_store(struct kobject *kobj,
 220                                            struct kobj_attribute *attr,
 221                                            const char *buf, size_t count)
 222{
 223        struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
 224        struct sockaddr *saddr;
 225        char *dst_addr;
 226        int port;
 227        struct xprt_addr *saved_addr;
 228        size_t buf_len;
 229
 230        if (!xprt)
 231                return 0;
 232        if (!(xprt->xprt_class->ident == XPRT_TRANSPORT_TCP ||
 233              xprt->xprt_class->ident == XPRT_TRANSPORT_RDMA)) {
 234                xprt_put(xprt);
 235                return -EOPNOTSUPP;
 236        }
 237
 238        if (wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_KILLABLE)) {
 239                count = -EINTR;
 240                goto out_put;
 241        }
 242        saddr = (struct sockaddr *)&xprt->addr;
 243        port = rpc_get_port(saddr);
 244
 245        /* buf_len is the len until the first occurence of either
 246         * '\n' or '\0'
 247         */
 248        buf_len = strcspn(buf, "\n");
 249
 250        dst_addr = kstrndup(buf, buf_len, GFP_KERNEL);
 251        if (!dst_addr)
 252                goto out_err;
 253        saved_addr = kzalloc(sizeof(*saved_addr), GFP_KERNEL);
 254        if (!saved_addr)
 255                goto out_err_free;
 256        saved_addr->addr =
 257                rcu_dereference_raw(xprt->address_strings[RPC_DISPLAY_ADDR]);
 258        rcu_assign_pointer(xprt->address_strings[RPC_DISPLAY_ADDR], dst_addr);
 259        call_rcu(&saved_addr->rcu, free_xprt_addr);
 260        xprt->addrlen = rpc_pton(xprt->xprt_net, buf, buf_len, saddr,
 261                                 sizeof(*saddr));
 262        rpc_set_port(saddr, port);
 263
 264        xprt_force_disconnect(xprt);
 265out:
 266        xprt_release_write(xprt, NULL);
 267out_put:
 268        xprt_put(xprt);
 269        return count;
 270out_err_free:
 271        kfree(dst_addr);
 272out_err:
 273        count = -ENOMEM;
 274        goto out;
 275}
 276
 277static ssize_t rpc_sysfs_xprt_state_change(struct kobject *kobj,
 278                                           struct kobj_attribute *attr,
 279                                           const char *buf, size_t count)
 280{
 281        struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
 282        int offline = 0, online = 0, remove = 0;
 283        struct rpc_xprt_switch *xps = rpc_sysfs_xprt_kobj_get_xprt_switch(kobj);
 284
 285        if (!xprt)
 286                return 0;
 287
 288        if (!strncmp(buf, "offline", 7))
 289                offline = 1;
 290        else if (!strncmp(buf, "online", 6))
 291                online = 1;
 292        else if (!strncmp(buf, "remove", 6))
 293                remove = 1;
 294        else
 295                return -EINVAL;
 296
 297        if (wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_KILLABLE)) {
 298                count = -EINTR;
 299                goto out_put;
 300        }
 301        if (xprt->main) {
 302                count = -EINVAL;
 303                goto release_tasks;
 304        }
 305        if (offline) {
 306                set_bit(XPRT_OFFLINE, &xprt->state);
 307                spin_lock(&xps->xps_lock);
 308                xps->xps_nactive--;
 309                spin_unlock(&xps->xps_lock);
 310        } else if (online) {
 311                clear_bit(XPRT_OFFLINE, &xprt->state);
 312                spin_lock(&xps->xps_lock);
 313                xps->xps_nactive++;
 314                spin_unlock(&xps->xps_lock);
 315        } else if (remove) {
 316                if (test_bit(XPRT_OFFLINE, &xprt->state)) {
 317                        set_bit(XPRT_REMOVE, &xprt->state);
 318                        xprt_force_disconnect(xprt);
 319                        if (test_bit(XPRT_CONNECTED, &xprt->state)) {
 320                                if (!xprt->sending.qlen &&
 321                                    !xprt->pending.qlen &&
 322                                    !xprt->backlog.qlen &&
 323                                    !atomic_long_read(&xprt->queuelen))
 324                                        rpc_xprt_switch_remove_xprt(xps, xprt);
 325                        }
 326                } else {
 327                        count = -EINVAL;
 328                }
 329        }
 330
 331release_tasks:
 332        xprt_release_write(xprt, NULL);
 333out_put:
 334        xprt_put(xprt);
 335        xprt_switch_put(xps);
 336        return count;
 337}
 338
 339int rpc_sysfs_init(void)
 340{
 341        rpc_sunrpc_kset = kset_create_and_add("sunrpc", NULL, kernel_kobj);
 342        if (!rpc_sunrpc_kset)
 343                return -ENOMEM;
 344        rpc_sunrpc_client_kobj =
 345                rpc_sysfs_object_alloc("rpc-clients", rpc_sunrpc_kset, NULL);
 346        if (!rpc_sunrpc_client_kobj)
 347                goto err_client;
 348        rpc_sunrpc_xprt_switch_kobj =
 349                rpc_sysfs_object_alloc("xprt-switches", rpc_sunrpc_kset, NULL);
 350        if (!rpc_sunrpc_xprt_switch_kobj)
 351                goto err_switch;
 352        return 0;
 353err_switch:
 354        kobject_put(rpc_sunrpc_client_kobj);
 355        rpc_sunrpc_client_kobj = NULL;
 356err_client:
 357        kset_unregister(rpc_sunrpc_kset);
 358        rpc_sunrpc_kset = NULL;
 359        return -ENOMEM;
 360}
 361
 362static void rpc_sysfs_client_release(struct kobject *kobj)
 363{
 364        struct rpc_sysfs_client *c;
 365
 366        c = container_of(kobj, struct rpc_sysfs_client, kobject);
 367        kfree(c);
 368}
 369
 370static void rpc_sysfs_xprt_switch_release(struct kobject *kobj)
 371{
 372        struct rpc_sysfs_xprt_switch *xprt_switch;
 373
 374        xprt_switch = container_of(kobj, struct rpc_sysfs_xprt_switch, kobject);
 375        kfree(xprt_switch);
 376}
 377
 378static void rpc_sysfs_xprt_release(struct kobject *kobj)
 379{
 380        struct rpc_sysfs_xprt *xprt;
 381
 382        xprt = container_of(kobj, struct rpc_sysfs_xprt, kobject);
 383        kfree(xprt);
 384}
 385
 386static const void *rpc_sysfs_client_namespace(struct kobject *kobj)
 387{
 388        return container_of(kobj, struct rpc_sysfs_client, kobject)->net;
 389}
 390
 391static const void *rpc_sysfs_xprt_switch_namespace(struct kobject *kobj)
 392{
 393        return container_of(kobj, struct rpc_sysfs_xprt_switch, kobject)->net;
 394}
 395
 396static const void *rpc_sysfs_xprt_namespace(struct kobject *kobj)
 397{
 398        return container_of(kobj, struct rpc_sysfs_xprt,
 399                            kobject)->xprt->xprt_net;
 400}
 401
 402static struct kobj_attribute rpc_sysfs_xprt_dstaddr = __ATTR(dstaddr,
 403        0644, rpc_sysfs_xprt_dstaddr_show, rpc_sysfs_xprt_dstaddr_store);
 404
 405static struct kobj_attribute rpc_sysfs_xprt_srcaddr = __ATTR(srcaddr,
 406        0644, rpc_sysfs_xprt_srcaddr_show, NULL);
 407
 408static struct kobj_attribute rpc_sysfs_xprt_info = __ATTR(xprt_info,
 409        0444, rpc_sysfs_xprt_info_show, NULL);
 410
 411static struct kobj_attribute rpc_sysfs_xprt_change_state = __ATTR(xprt_state,
 412        0644, rpc_sysfs_xprt_state_show, rpc_sysfs_xprt_state_change);
 413
 414static struct attribute *rpc_sysfs_xprt_attrs[] = {
 415        &rpc_sysfs_xprt_dstaddr.attr,
 416        &rpc_sysfs_xprt_srcaddr.attr,
 417        &rpc_sysfs_xprt_info.attr,
 418        &rpc_sysfs_xprt_change_state.attr,
 419        NULL,
 420};
 421
 422static struct kobj_attribute rpc_sysfs_xprt_switch_info =
 423        __ATTR(xprt_switch_info, 0444, rpc_sysfs_xprt_switch_info_show, NULL);
 424
 425static struct attribute *rpc_sysfs_xprt_switch_attrs[] = {
 426        &rpc_sysfs_xprt_switch_info.attr,
 427        NULL,
 428};
 429
 430static struct kobj_type rpc_sysfs_client_type = {
 431        .release = rpc_sysfs_client_release,
 432        .sysfs_ops = &kobj_sysfs_ops,
 433        .namespace = rpc_sysfs_client_namespace,
 434};
 435
 436static struct kobj_type rpc_sysfs_xprt_switch_type = {
 437        .release = rpc_sysfs_xprt_switch_release,
 438        .default_attrs = rpc_sysfs_xprt_switch_attrs,
 439        .sysfs_ops = &kobj_sysfs_ops,
 440        .namespace = rpc_sysfs_xprt_switch_namespace,
 441};
 442
 443static struct kobj_type rpc_sysfs_xprt_type = {
 444        .release = rpc_sysfs_xprt_release,
 445        .default_attrs = rpc_sysfs_xprt_attrs,
 446        .sysfs_ops = &kobj_sysfs_ops,
 447        .namespace = rpc_sysfs_xprt_namespace,
 448};
 449
 450void rpc_sysfs_exit(void)
 451{
 452        kobject_put(rpc_sunrpc_client_kobj);
 453        kobject_put(rpc_sunrpc_xprt_switch_kobj);
 454        kset_unregister(rpc_sunrpc_kset);
 455}
 456
 457static struct rpc_sysfs_client *rpc_sysfs_client_alloc(struct kobject *parent,
 458                                                       struct net *net,
 459                                                       int clid)
 460{
 461        struct rpc_sysfs_client *p;
 462
 463        p = kzalloc(sizeof(*p), GFP_KERNEL);
 464        if (p) {
 465                p->net = net;
 466                p->kobject.kset = rpc_sunrpc_kset;
 467                if (kobject_init_and_add(&p->kobject, &rpc_sysfs_client_type,
 468                                         parent, "clnt-%d", clid) == 0)
 469                        return p;
 470                kobject_put(&p->kobject);
 471        }
 472        return NULL;
 473}
 474
 475static struct rpc_sysfs_xprt_switch *
 476rpc_sysfs_xprt_switch_alloc(struct kobject *parent,
 477                            struct rpc_xprt_switch *xprt_switch,
 478                            struct net *net,
 479                            gfp_t gfp_flags)
 480{
 481        struct rpc_sysfs_xprt_switch *p;
 482
 483        p = kzalloc(sizeof(*p), gfp_flags);
 484        if (p) {
 485                p->net = net;
 486                p->kobject.kset = rpc_sunrpc_kset;
 487                if (kobject_init_and_add(&p->kobject,
 488                                         &rpc_sysfs_xprt_switch_type,
 489                                         parent, "switch-%d",
 490                                         xprt_switch->xps_id) == 0)
 491                        return p;
 492                kobject_put(&p->kobject);
 493        }
 494        return NULL;
 495}
 496
 497static struct rpc_sysfs_xprt *rpc_sysfs_xprt_alloc(struct kobject *parent,
 498                                                   struct rpc_xprt *xprt,
 499                                                   gfp_t gfp_flags)
 500{
 501        struct rpc_sysfs_xprt *p;
 502
 503        p = kzalloc(sizeof(*p), gfp_flags);
 504        if (!p)
 505                goto out;
 506        p->kobject.kset = rpc_sunrpc_kset;
 507        if (kobject_init_and_add(&p->kobject, &rpc_sysfs_xprt_type,
 508                                 parent, "xprt-%d-%s", xprt->id,
 509                                 xprt->address_strings[RPC_DISPLAY_PROTO]) == 0)
 510                return p;
 511        kobject_put(&p->kobject);
 512out:
 513        return NULL;
 514}
 515
 516void rpc_sysfs_client_setup(struct rpc_clnt *clnt,
 517                            struct rpc_xprt_switch *xprt_switch,
 518                            struct net *net)
 519{
 520        struct rpc_sysfs_client *rpc_client;
 521
 522        rpc_client = rpc_sysfs_client_alloc(rpc_sunrpc_client_kobj,
 523                                            net, clnt->cl_clid);
 524        if (rpc_client) {
 525                char name[] = "switch";
 526                struct rpc_sysfs_xprt_switch *xswitch =
 527                        (struct rpc_sysfs_xprt_switch *)xprt_switch->xps_sysfs;
 528                int ret;
 529
 530                clnt->cl_sysfs = rpc_client;
 531                rpc_client->clnt = clnt;
 532                rpc_client->xprt_switch = xprt_switch;
 533                kobject_uevent(&rpc_client->kobject, KOBJ_ADD);
 534                ret = sysfs_create_link_nowarn(&rpc_client->kobject,
 535                                               &xswitch->kobject, name);
 536                if (ret)
 537                        pr_warn("can't create link to %s in sysfs (%d)\n",
 538                                name, ret);
 539        }
 540}
 541
 542void rpc_sysfs_xprt_switch_setup(struct rpc_xprt_switch *xprt_switch,
 543                                 struct rpc_xprt *xprt,
 544                                 gfp_t gfp_flags)
 545{
 546        struct rpc_sysfs_xprt_switch *rpc_xprt_switch;
 547        struct net *net;
 548
 549        if (xprt_switch->xps_net)
 550                net = xprt_switch->xps_net;
 551        else
 552                net = xprt->xprt_net;
 553        rpc_xprt_switch =
 554                rpc_sysfs_xprt_switch_alloc(rpc_sunrpc_xprt_switch_kobj,
 555                                            xprt_switch, net, gfp_flags);
 556        if (rpc_xprt_switch) {
 557                xprt_switch->xps_sysfs = rpc_xprt_switch;
 558                rpc_xprt_switch->xprt_switch = xprt_switch;
 559                rpc_xprt_switch->xprt = xprt;
 560                kobject_uevent(&rpc_xprt_switch->kobject, KOBJ_ADD);
 561        }
 562}
 563
 564void rpc_sysfs_xprt_setup(struct rpc_xprt_switch *xprt_switch,
 565                          struct rpc_xprt *xprt,
 566                          gfp_t gfp_flags)
 567{
 568        struct rpc_sysfs_xprt *rpc_xprt;
 569        struct rpc_sysfs_xprt_switch *switch_obj =
 570                (struct rpc_sysfs_xprt_switch *)xprt_switch->xps_sysfs;
 571
 572        rpc_xprt = rpc_sysfs_xprt_alloc(&switch_obj->kobject, xprt, gfp_flags);
 573        if (rpc_xprt) {
 574                xprt->xprt_sysfs = rpc_xprt;
 575                rpc_xprt->xprt = xprt;
 576                rpc_xprt->xprt_switch = xprt_switch;
 577                kobject_uevent(&rpc_xprt->kobject, KOBJ_ADD);
 578        }
 579}
 580
 581void rpc_sysfs_client_destroy(struct rpc_clnt *clnt)
 582{
 583        struct rpc_sysfs_client *rpc_client = clnt->cl_sysfs;
 584
 585        if (rpc_client) {
 586                char name[] = "switch";
 587
 588                sysfs_remove_link(&rpc_client->kobject, name);
 589                kobject_uevent(&rpc_client->kobject, KOBJ_REMOVE);
 590                kobject_del(&rpc_client->kobject);
 591                kobject_put(&rpc_client->kobject);
 592                clnt->cl_sysfs = NULL;
 593        }
 594}
 595
 596void rpc_sysfs_xprt_switch_destroy(struct rpc_xprt_switch *xprt_switch)
 597{
 598        struct rpc_sysfs_xprt_switch *rpc_xprt_switch = xprt_switch->xps_sysfs;
 599
 600        if (rpc_xprt_switch) {
 601                kobject_uevent(&rpc_xprt_switch->kobject, KOBJ_REMOVE);
 602                kobject_del(&rpc_xprt_switch->kobject);
 603                kobject_put(&rpc_xprt_switch->kobject);
 604                xprt_switch->xps_sysfs = NULL;
 605        }
 606}
 607
 608void rpc_sysfs_xprt_destroy(struct rpc_xprt *xprt)
 609{
 610        struct rpc_sysfs_xprt *rpc_xprt = xprt->xprt_sysfs;
 611
 612        if (rpc_xprt) {
 613                kobject_uevent(&rpc_xprt->kobject, KOBJ_REMOVE);
 614                kobject_del(&rpc_xprt->kobject);
 615                kobject_put(&rpc_xprt->kobject);
 616                xprt->xprt_sysfs = NULL;
 617        }
 618}
 619