0001
0002
0003
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
0255
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 }