Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (c) 2020 Anna Schumaker <Anna.Schumaker@Netapp.com>
0004  */
0005 #include <linux/sunrpc/clnt.h>
0006 #include <linux/kobject.h>
0007 #include <linux/sunrpc/addr.h>
0008 #include <linux/sunrpc/xprtsock.h>
0009 
0010 #include "sysfs.h"
0011 
0012 struct xprt_addr {
0013     const char *addr;
0014     struct rcu_head rcu;
0015 };
0016 
0017 static void free_xprt_addr(struct rcu_head *head)
0018 {
0019     struct xprt_addr *addr = container_of(head, struct xprt_addr, rcu);
0020 
0021     kfree(addr->addr);
0022     kfree(addr);
0023 }
0024 
0025 static struct kset *rpc_sunrpc_kset;
0026 static struct kobject *rpc_sunrpc_client_kobj, *rpc_sunrpc_xprt_switch_kobj;
0027 
0028 static void rpc_sysfs_object_release(struct kobject *kobj)
0029 {
0030     kfree(kobj);
0031 }
0032 
0033 static const struct kobj_ns_type_operations *
0034 rpc_sysfs_object_child_ns_type(struct kobject *kobj)
0035 {
0036     return &net_ns_type_operations;
0037 }
0038 
0039 static struct kobj_type rpc_sysfs_object_type = {
0040     .release = rpc_sysfs_object_release,
0041     .sysfs_ops = &kobj_sysfs_ops,
0042     .child_ns_type = rpc_sysfs_object_child_ns_type,
0043 };
0044 
0045 static struct kobject *rpc_sysfs_object_alloc(const char *name,
0046                           struct kset *kset,
0047                           struct kobject *parent)
0048 {
0049     struct kobject *kobj;
0050 
0051     kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
0052     if (kobj) {
0053         kobj->kset = kset;
0054         if (kobject_init_and_add(kobj, &rpc_sysfs_object_type,
0055                      parent, "%s", name) == 0)
0056             return kobj;
0057         kobject_put(kobj);
0058     }
0059     return NULL;
0060 }
0061 
0062 static inline struct rpc_xprt *
0063 rpc_sysfs_xprt_kobj_get_xprt(struct kobject *kobj)
0064 {
0065     struct rpc_sysfs_xprt *x = container_of(kobj,
0066         struct rpc_sysfs_xprt, kobject);
0067 
0068     return xprt_get(x->xprt);
0069 }
0070 
0071 static inline struct rpc_xprt_switch *
0072 rpc_sysfs_xprt_kobj_get_xprt_switch(struct kobject *kobj)
0073 {
0074     struct rpc_sysfs_xprt *x = container_of(kobj,
0075         struct rpc_sysfs_xprt, kobject);
0076 
0077     return xprt_switch_get(x->xprt_switch);
0078 }
0079 
0080 static inline struct rpc_xprt_switch *
0081 rpc_sysfs_xprt_switch_kobj_get_xprt(struct kobject *kobj)
0082 {
0083     struct rpc_sysfs_xprt_switch *x = container_of(kobj,
0084         struct rpc_sysfs_xprt_switch, kobject);
0085 
0086     return xprt_switch_get(x->xprt_switch);
0087 }
0088 
0089 static ssize_t rpc_sysfs_xprt_dstaddr_show(struct kobject *kobj,
0090                        struct kobj_attribute *attr,
0091                        char *buf)
0092 {
0093     struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
0094     ssize_t ret;
0095 
0096     if (!xprt) {
0097         ret = sprintf(buf, "<closed>\n");
0098         goto out;
0099     }
0100     ret = sprintf(buf, "%s\n", xprt->address_strings[RPC_DISPLAY_ADDR]);
0101     xprt_put(xprt);
0102 out:
0103     return ret;
0104 }
0105 
0106 static ssize_t rpc_sysfs_xprt_srcaddr_show(struct kobject *kobj,
0107                        struct kobj_attribute *attr,
0108                        char *buf)
0109 {
0110     struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
0111     size_t buflen = PAGE_SIZE;
0112     ssize_t ret;
0113 
0114     if (!xprt || !xprt_connected(xprt)) {
0115         ret = sprintf(buf, "<closed>\n");
0116     } else if (xprt->ops->get_srcaddr) {
0117         ret = xprt->ops->get_srcaddr(xprt, buf, buflen);
0118         if (ret > 0) {
0119             if (ret < buflen - 1) {
0120                 buf[ret] = '\n';
0121                 ret++;
0122                 buf[ret] = '\0';
0123             }
0124         } else
0125             ret = sprintf(buf, "<closed>\n");
0126     } else
0127         ret = sprintf(buf, "<not a socket>\n");
0128     xprt_put(xprt);
0129     return ret;
0130 }
0131 
0132 static ssize_t rpc_sysfs_xprt_info_show(struct kobject *kobj,
0133                     struct kobj_attribute *attr, char *buf)
0134 {
0135     struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
0136     unsigned short srcport = 0;
0137     size_t buflen = PAGE_SIZE;
0138     ssize_t ret;
0139 
0140     if (!xprt || !xprt_connected(xprt)) {
0141         ret = sprintf(buf, "<closed>\n");
0142         goto out;
0143     }
0144 
0145     if (xprt->ops->get_srcport)
0146         srcport = xprt->ops->get_srcport(xprt);
0147 
0148     ret = snprintf(buf, buflen,
0149                "last_used=%lu\ncur_cong=%lu\ncong_win=%lu\n"
0150                "max_num_slots=%u\nmin_num_slots=%u\nnum_reqs=%u\n"
0151                "binding_q_len=%u\nsending_q_len=%u\npending_q_len=%u\n"
0152                "backlog_q_len=%u\nmain_xprt=%d\nsrc_port=%u\n"
0153                "tasks_queuelen=%ld\ndst_port=%s\n",
0154                xprt->last_used, xprt->cong, xprt->cwnd, xprt->max_reqs,
0155                xprt->min_reqs, xprt->num_reqs, xprt->binding.qlen,
0156                xprt->sending.qlen, xprt->pending.qlen,
0157                xprt->backlog.qlen, xprt->main, srcport,
0158                atomic_long_read(&xprt->queuelen),
0159                xprt->address_strings[RPC_DISPLAY_PORT]);
0160 out:
0161     xprt_put(xprt);
0162     return ret;
0163 }
0164 
0165 static ssize_t rpc_sysfs_xprt_state_show(struct kobject *kobj,
0166                      struct kobj_attribute *attr,
0167                      char *buf)
0168 {
0169     struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
0170     ssize_t ret;
0171     int locked, connected, connecting, close_wait, bound, binding,
0172         closing, congested, cwnd_wait, write_space, offline, remove;
0173 
0174     if (!(xprt && xprt->state)) {
0175         ret = sprintf(buf, "state=CLOSED\n");
0176     } else {
0177         locked = test_bit(XPRT_LOCKED, &xprt->state);
0178         connected = test_bit(XPRT_CONNECTED, &xprt->state);
0179         connecting = test_bit(XPRT_CONNECTING, &xprt->state);
0180         close_wait = test_bit(XPRT_CLOSE_WAIT, &xprt->state);
0181         bound = test_bit(XPRT_BOUND, &xprt->state);
0182         binding = test_bit(XPRT_BINDING, &xprt->state);
0183         closing = test_bit(XPRT_CLOSING, &xprt->state);
0184         congested = test_bit(XPRT_CONGESTED, &xprt->state);
0185         cwnd_wait = test_bit(XPRT_CWND_WAIT, &xprt->state);
0186         write_space = test_bit(XPRT_WRITE_SPACE, &xprt->state);
0187         offline = test_bit(XPRT_OFFLINE, &xprt->state);
0188         remove = test_bit(XPRT_REMOVE, &xprt->state);
0189 
0190         ret = sprintf(buf, "state=%s %s %s %s %s %s %s %s %s %s %s %s\n",
0191                   locked ? "LOCKED" : "",
0192                   connected ? "CONNECTED" : "",
0193                   connecting ? "CONNECTING" : "",
0194                   close_wait ? "CLOSE_WAIT" : "",
0195                   bound ? "BOUND" : "",
0196                   binding ? "BOUNDING" : "",
0197                   closing ? "CLOSING" : "",
0198                   congested ? "CONGESTED" : "",
0199                   cwnd_wait ? "CWND_WAIT" : "",
0200                   write_space ? "WRITE_SPACE" : "",
0201                   offline ? "OFFLINE" : "",
0202                   remove ? "REMOVE" : "");
0203     }
0204 
0205     xprt_put(xprt);
0206     return ret;
0207 }
0208 
0209 static ssize_t rpc_sysfs_xprt_switch_info_show(struct kobject *kobj,
0210                            struct kobj_attribute *attr,
0211                            char *buf)
0212 {
0213     struct rpc_xprt_switch *xprt_switch =
0214         rpc_sysfs_xprt_switch_kobj_get_xprt(kobj);
0215     ssize_t ret;
0216 
0217     if (!xprt_switch)
0218         return 0;
0219     ret = sprintf(buf, "num_xprts=%u\nnum_active=%u\n"
0220               "num_unique_destaddr=%u\nqueue_len=%ld\n",
0221               xprt_switch->xps_nxprts, xprt_switch->xps_nactive,
0222               xprt_switch->xps_nunique_destaddr_xprts,
0223               atomic_long_read(&xprt_switch->xps_queuelen));
0224     xprt_switch_put(xprt_switch);
0225     return ret;
0226 }
0227 
0228 static ssize_t rpc_sysfs_xprt_dstaddr_store(struct kobject *kobj,
0229                         struct kobj_attribute *attr,
0230                         const char *buf, size_t count)
0231 {
0232     struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
0233     struct sockaddr *saddr;
0234     char *dst_addr;
0235     int port;
0236     struct xprt_addr *saved_addr;
0237     size_t buf_len;
0238 
0239     if (!xprt)
0240         return 0;
0241     if (!(xprt->xprt_class->ident == XPRT_TRANSPORT_TCP ||
0242           xprt->xprt_class->ident == XPRT_TRANSPORT_RDMA)) {
0243         xprt_put(xprt);
0244         return -EOPNOTSUPP;
0245     }
0246 
0247     if (wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_KILLABLE)) {
0248         count = -EINTR;
0249         goto out_put;
0250     }
0251     saddr = (struct sockaddr *)&xprt->addr;
0252     port = rpc_get_port(saddr);
0253 
0254     /* buf_len is the len until the first occurence of either
0255      * '\n' or '\0'
0256      */
0257     buf_len = strcspn(buf, "\n");
0258 
0259     dst_addr = kstrndup(buf, buf_len, GFP_KERNEL);
0260     if (!dst_addr)
0261         goto out_err;
0262     saved_addr = kzalloc(sizeof(*saved_addr), GFP_KERNEL);
0263     if (!saved_addr)
0264         goto out_err_free;
0265     saved_addr->addr =
0266         rcu_dereference_raw(xprt->address_strings[RPC_DISPLAY_ADDR]);
0267     rcu_assign_pointer(xprt->address_strings[RPC_DISPLAY_ADDR], dst_addr);
0268     call_rcu(&saved_addr->rcu, free_xprt_addr);
0269     xprt->addrlen = rpc_pton(xprt->xprt_net, buf, buf_len, saddr,
0270                  sizeof(*saddr));
0271     rpc_set_port(saddr, port);
0272 
0273     xprt_force_disconnect(xprt);
0274 out:
0275     xprt_release_write(xprt, NULL);
0276 out_put:
0277     xprt_put(xprt);
0278     return count;
0279 out_err_free:
0280     kfree(dst_addr);
0281 out_err:
0282     count = -ENOMEM;
0283     goto out;
0284 }
0285 
0286 static ssize_t rpc_sysfs_xprt_state_change(struct kobject *kobj,
0287                        struct kobj_attribute *attr,
0288                        const char *buf, size_t count)
0289 {
0290     struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
0291     int offline = 0, online = 0, remove = 0;
0292     struct rpc_xprt_switch *xps = rpc_sysfs_xprt_kobj_get_xprt_switch(kobj);
0293 
0294     if (!xprt || !xps) {
0295         count = 0;
0296         goto out_put;
0297     }
0298 
0299     if (!strncmp(buf, "offline", 7))
0300         offline = 1;
0301     else if (!strncmp(buf, "online", 6))
0302         online = 1;
0303     else if (!strncmp(buf, "remove", 6))
0304         remove = 1;
0305     else {
0306         count = -EINVAL;
0307         goto out_put;
0308     }
0309 
0310     if (wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_KILLABLE)) {
0311         count = -EINTR;
0312         goto out_put;
0313     }
0314     if (xprt->main) {
0315         count = -EINVAL;
0316         goto release_tasks;
0317     }
0318     if (offline) {
0319         xprt_set_offline_locked(xprt, xps);
0320     } else if (online) {
0321         xprt_set_online_locked(xprt, xps);
0322     } else if (remove) {
0323         if (test_bit(XPRT_OFFLINE, &xprt->state))
0324             xprt_delete_locked(xprt, xps);
0325         else
0326             count = -EINVAL;
0327     }
0328 
0329 release_tasks:
0330     xprt_release_write(xprt, NULL);
0331 out_put:
0332     xprt_put(xprt);
0333     xprt_switch_put(xps);
0334     return count;
0335 }
0336 
0337 int rpc_sysfs_init(void)
0338 {
0339     rpc_sunrpc_kset = kset_create_and_add("sunrpc", NULL, kernel_kobj);
0340     if (!rpc_sunrpc_kset)
0341         return -ENOMEM;
0342     rpc_sunrpc_client_kobj =
0343         rpc_sysfs_object_alloc("rpc-clients", rpc_sunrpc_kset, NULL);
0344     if (!rpc_sunrpc_client_kobj)
0345         goto err_client;
0346     rpc_sunrpc_xprt_switch_kobj =
0347         rpc_sysfs_object_alloc("xprt-switches", rpc_sunrpc_kset, NULL);
0348     if (!rpc_sunrpc_xprt_switch_kobj)
0349         goto err_switch;
0350     return 0;
0351 err_switch:
0352     kobject_put(rpc_sunrpc_client_kobj);
0353     rpc_sunrpc_client_kobj = NULL;
0354 err_client:
0355     kset_unregister(rpc_sunrpc_kset);
0356     rpc_sunrpc_kset = NULL;
0357     return -ENOMEM;
0358 }
0359 
0360 static void rpc_sysfs_client_release(struct kobject *kobj)
0361 {
0362     struct rpc_sysfs_client *c;
0363 
0364     c = container_of(kobj, struct rpc_sysfs_client, kobject);
0365     kfree(c);
0366 }
0367 
0368 static void rpc_sysfs_xprt_switch_release(struct kobject *kobj)
0369 {
0370     struct rpc_sysfs_xprt_switch *xprt_switch;
0371 
0372     xprt_switch = container_of(kobj, struct rpc_sysfs_xprt_switch, kobject);
0373     kfree(xprt_switch);
0374 }
0375 
0376 static void rpc_sysfs_xprt_release(struct kobject *kobj)
0377 {
0378     struct rpc_sysfs_xprt *xprt;
0379 
0380     xprt = container_of(kobj, struct rpc_sysfs_xprt, kobject);
0381     kfree(xprt);
0382 }
0383 
0384 static const void *rpc_sysfs_client_namespace(struct kobject *kobj)
0385 {
0386     return container_of(kobj, struct rpc_sysfs_client, kobject)->net;
0387 }
0388 
0389 static const void *rpc_sysfs_xprt_switch_namespace(struct kobject *kobj)
0390 {
0391     return container_of(kobj, struct rpc_sysfs_xprt_switch, kobject)->net;
0392 }
0393 
0394 static const void *rpc_sysfs_xprt_namespace(struct kobject *kobj)
0395 {
0396     return container_of(kobj, struct rpc_sysfs_xprt,
0397                 kobject)->xprt->xprt_net;
0398 }
0399 
0400 static struct kobj_attribute rpc_sysfs_xprt_dstaddr = __ATTR(dstaddr,
0401     0644, rpc_sysfs_xprt_dstaddr_show, rpc_sysfs_xprt_dstaddr_store);
0402 
0403 static struct kobj_attribute rpc_sysfs_xprt_srcaddr = __ATTR(srcaddr,
0404     0644, rpc_sysfs_xprt_srcaddr_show, NULL);
0405 
0406 static struct kobj_attribute rpc_sysfs_xprt_info = __ATTR(xprt_info,
0407     0444, rpc_sysfs_xprt_info_show, NULL);
0408 
0409 static struct kobj_attribute rpc_sysfs_xprt_change_state = __ATTR(xprt_state,
0410     0644, rpc_sysfs_xprt_state_show, rpc_sysfs_xprt_state_change);
0411 
0412 static struct attribute *rpc_sysfs_xprt_attrs[] = {
0413     &rpc_sysfs_xprt_dstaddr.attr,
0414     &rpc_sysfs_xprt_srcaddr.attr,
0415     &rpc_sysfs_xprt_info.attr,
0416     &rpc_sysfs_xprt_change_state.attr,
0417     NULL,
0418 };
0419 ATTRIBUTE_GROUPS(rpc_sysfs_xprt);
0420 
0421 static struct kobj_attribute rpc_sysfs_xprt_switch_info =
0422     __ATTR(xprt_switch_info, 0444, rpc_sysfs_xprt_switch_info_show, NULL);
0423 
0424 static struct attribute *rpc_sysfs_xprt_switch_attrs[] = {
0425     &rpc_sysfs_xprt_switch_info.attr,
0426     NULL,
0427 };
0428 ATTRIBUTE_GROUPS(rpc_sysfs_xprt_switch);
0429 
0430 static struct kobj_type rpc_sysfs_client_type = {
0431     .release = rpc_sysfs_client_release,
0432     .sysfs_ops = &kobj_sysfs_ops,
0433     .namespace = rpc_sysfs_client_namespace,
0434 };
0435 
0436 static struct kobj_type rpc_sysfs_xprt_switch_type = {
0437     .release = rpc_sysfs_xprt_switch_release,
0438     .default_groups = rpc_sysfs_xprt_switch_groups,
0439     .sysfs_ops = &kobj_sysfs_ops,
0440     .namespace = rpc_sysfs_xprt_switch_namespace,
0441 };
0442 
0443 static struct kobj_type rpc_sysfs_xprt_type = {
0444     .release = rpc_sysfs_xprt_release,
0445     .default_groups = rpc_sysfs_xprt_groups,
0446     .sysfs_ops = &kobj_sysfs_ops,
0447     .namespace = rpc_sysfs_xprt_namespace,
0448 };
0449 
0450 void rpc_sysfs_exit(void)
0451 {
0452     kobject_put(rpc_sunrpc_client_kobj);
0453     kobject_put(rpc_sunrpc_xprt_switch_kobj);
0454     kset_unregister(rpc_sunrpc_kset);
0455 }
0456 
0457 static struct rpc_sysfs_client *rpc_sysfs_client_alloc(struct kobject *parent,
0458                                struct net *net,
0459                                int clid)
0460 {
0461     struct rpc_sysfs_client *p;
0462 
0463     p = kzalloc(sizeof(*p), GFP_KERNEL);
0464     if (p) {
0465         p->net = net;
0466         p->kobject.kset = rpc_sunrpc_kset;
0467         if (kobject_init_and_add(&p->kobject, &rpc_sysfs_client_type,
0468                      parent, "clnt-%d", clid) == 0)
0469             return p;
0470         kobject_put(&p->kobject);
0471     }
0472     return NULL;
0473 }
0474 
0475 static struct rpc_sysfs_xprt_switch *
0476 rpc_sysfs_xprt_switch_alloc(struct kobject *parent,
0477                 struct rpc_xprt_switch *xprt_switch,
0478                 struct net *net,
0479                 gfp_t gfp_flags)
0480 {
0481     struct rpc_sysfs_xprt_switch *p;
0482 
0483     p = kzalloc(sizeof(*p), gfp_flags);
0484     if (p) {
0485         p->net = net;
0486         p->kobject.kset = rpc_sunrpc_kset;
0487         if (kobject_init_and_add(&p->kobject,
0488                      &rpc_sysfs_xprt_switch_type,
0489                      parent, "switch-%d",
0490                      xprt_switch->xps_id) == 0)
0491             return p;
0492         kobject_put(&p->kobject);
0493     }
0494     return NULL;
0495 }
0496 
0497 static struct rpc_sysfs_xprt *rpc_sysfs_xprt_alloc(struct kobject *parent,
0498                            struct rpc_xprt *xprt,
0499                            gfp_t gfp_flags)
0500 {
0501     struct rpc_sysfs_xprt *p;
0502 
0503     p = kzalloc(sizeof(*p), gfp_flags);
0504     if (!p)
0505         goto out;
0506     p->kobject.kset = rpc_sunrpc_kset;
0507     if (kobject_init_and_add(&p->kobject, &rpc_sysfs_xprt_type,
0508                  parent, "xprt-%d-%s", xprt->id,
0509                  xprt->address_strings[RPC_DISPLAY_PROTO]) == 0)
0510         return p;
0511     kobject_put(&p->kobject);
0512 out:
0513     return NULL;
0514 }
0515 
0516 void rpc_sysfs_client_setup(struct rpc_clnt *clnt,
0517                 struct rpc_xprt_switch *xprt_switch,
0518                 struct net *net)
0519 {
0520     struct rpc_sysfs_client *rpc_client;
0521 
0522     rpc_client = rpc_sysfs_client_alloc(rpc_sunrpc_client_kobj,
0523                         net, clnt->cl_clid);
0524     if (rpc_client) {
0525         char name[] = "switch";
0526         struct rpc_sysfs_xprt_switch *xswitch =
0527             (struct rpc_sysfs_xprt_switch *)xprt_switch->xps_sysfs;
0528         int ret;
0529 
0530         clnt->cl_sysfs = rpc_client;
0531         rpc_client->clnt = clnt;
0532         rpc_client->xprt_switch = xprt_switch;
0533         kobject_uevent(&rpc_client->kobject, KOBJ_ADD);
0534         ret = sysfs_create_link_nowarn(&rpc_client->kobject,
0535                            &xswitch->kobject, name);
0536         if (ret)
0537             pr_warn("can't create link to %s in sysfs (%d)\n",
0538                 name, ret);
0539     }
0540 }
0541 
0542 void rpc_sysfs_xprt_switch_setup(struct rpc_xprt_switch *xprt_switch,
0543                  struct rpc_xprt *xprt,
0544                  gfp_t gfp_flags)
0545 {
0546     struct rpc_sysfs_xprt_switch *rpc_xprt_switch;
0547     struct net *net;
0548 
0549     if (xprt_switch->xps_net)
0550         net = xprt_switch->xps_net;
0551     else
0552         net = xprt->xprt_net;
0553     rpc_xprt_switch =
0554         rpc_sysfs_xprt_switch_alloc(rpc_sunrpc_xprt_switch_kobj,
0555                         xprt_switch, net, gfp_flags);
0556     if (rpc_xprt_switch) {
0557         xprt_switch->xps_sysfs = rpc_xprt_switch;
0558         rpc_xprt_switch->xprt_switch = xprt_switch;
0559         rpc_xprt_switch->xprt = xprt;
0560         kobject_uevent(&rpc_xprt_switch->kobject, KOBJ_ADD);
0561     }
0562 }
0563 
0564 void rpc_sysfs_xprt_setup(struct rpc_xprt_switch *xprt_switch,
0565               struct rpc_xprt *xprt,
0566               gfp_t gfp_flags)
0567 {
0568     struct rpc_sysfs_xprt *rpc_xprt;
0569     struct rpc_sysfs_xprt_switch *switch_obj =
0570         (struct rpc_sysfs_xprt_switch *)xprt_switch->xps_sysfs;
0571 
0572     rpc_xprt = rpc_sysfs_xprt_alloc(&switch_obj->kobject, xprt, gfp_flags);
0573     if (rpc_xprt) {
0574         xprt->xprt_sysfs = rpc_xprt;
0575         rpc_xprt->xprt = xprt;
0576         rpc_xprt->xprt_switch = xprt_switch;
0577         kobject_uevent(&rpc_xprt->kobject, KOBJ_ADD);
0578     }
0579 }
0580 
0581 void rpc_sysfs_client_destroy(struct rpc_clnt *clnt)
0582 {
0583     struct rpc_sysfs_client *rpc_client = clnt->cl_sysfs;
0584 
0585     if (rpc_client) {
0586         char name[] = "switch";
0587 
0588         sysfs_remove_link(&rpc_client->kobject, name);
0589         kobject_uevent(&rpc_client->kobject, KOBJ_REMOVE);
0590         kobject_del(&rpc_client->kobject);
0591         kobject_put(&rpc_client->kobject);
0592         clnt->cl_sysfs = NULL;
0593     }
0594 }
0595 
0596 void rpc_sysfs_xprt_switch_destroy(struct rpc_xprt_switch *xprt_switch)
0597 {
0598     struct rpc_sysfs_xprt_switch *rpc_xprt_switch = xprt_switch->xps_sysfs;
0599 
0600     if (rpc_xprt_switch) {
0601         kobject_uevent(&rpc_xprt_switch->kobject, KOBJ_REMOVE);
0602         kobject_del(&rpc_xprt_switch->kobject);
0603         kobject_put(&rpc_xprt_switch->kobject);
0604         xprt_switch->xps_sysfs = NULL;
0605     }
0606 }
0607 
0608 void rpc_sysfs_xprt_destroy(struct rpc_xprt *xprt)
0609 {
0610     struct rpc_sysfs_xprt *rpc_xprt = xprt->xprt_sysfs;
0611 
0612     if (rpc_xprt) {
0613         kobject_uevent(&rpc_xprt->kobject, KOBJ_REMOVE);
0614         kobject_del(&rpc_xprt->kobject);
0615         kobject_put(&rpc_xprt->kobject);
0616         xprt->xprt_sysfs = NULL;
0617     }
0618 }