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