1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2 /* 3 * Copyright (c) 2017, Mellanox Technologies inc. All rights reserved. 4 */ 5 #include <rdma/uverbs_ioctl.h> 6 #include <rdma/rdma_user_ioctl.h> 7 #include <linux/bitops.h> 8 #include "rdma_core.h" 9 #include "uverbs.h" 10 11 static int ib_uverbs_notsupp(struct uverbs_attr_bundle *attrs) 12 { 13 return -EOPNOTSUPP; 14 } 15 16 static void *uapi_add_elm(struct uverbs_api *uapi, u32 key, size_t alloc_size) 17 { 18 void *elm; 19 int rc; 20 21 if (key == UVERBS_API_KEY_ERR) 22 return ERR_PTR(-EOVERFLOW); 23 24 elm = kzalloc(alloc_size, GFP_KERNEL); 25 if (!elm) 26 return ERR_PTR(-ENOMEM); 27 rc = radix_tree_insert(&uapi->radix, key, elm); 28 if (rc) { 29 kfree(elm); 30 return ERR_PTR(rc); 31 } 32 33 return elm; 34 } 35 36 static void *uapi_add_get_elm(struct uverbs_api *uapi, u32 key, 37 size_t alloc_size, bool *exists) 38 { 39 void *elm; 40 41 elm = uapi_add_elm(uapi, key, alloc_size); 42 if (!IS_ERR(elm)) { 43 *exists = false; 44 return elm; 45 } 46 47 if (elm != ERR_PTR(-EEXIST)) 48 return elm; 49 50 elm = radix_tree_lookup(&uapi->radix, key); 51 if (WARN_ON(!elm)) 52 return ERR_PTR(-EINVAL); 53 *exists = true; 54 return elm; 55 } 56 57 static int uapi_create_write(struct uverbs_api *uapi, 58 struct ib_device *ibdev, 59 const struct uapi_definition *def, 60 u32 obj_key, 61 u32 *cur_method_key) 62 { 63 struct uverbs_api_write_method *method_elm; 64 u32 method_key = obj_key; 65 bool exists; 66 67 if (def->write.is_ex) 68 method_key |= uapi_key_write_ex_method(def->write.command_num); 69 else 70 method_key |= uapi_key_write_method(def->write.command_num); 71 72 method_elm = uapi_add_get_elm(uapi, method_key, sizeof(*method_elm), 73 &exists); 74 if (IS_ERR(method_elm)) 75 return PTR_ERR(method_elm); 76 77 if (WARN_ON(exists && (def->write.is_ex != method_elm->is_ex))) 78 return -EINVAL; 79 80 method_elm->is_ex = def->write.is_ex; 81 method_elm->handler = def->func_write; 82 if (def->write.is_ex) 83 method_elm->disabled = !(ibdev->uverbs_ex_cmd_mask & 84 BIT_ULL(def->write.command_num)); 85 else 86 method_elm->disabled = !(ibdev->uverbs_cmd_mask & 87 BIT_ULL(def->write.command_num)); 88 89 if (!def->write.is_ex && def->func_write) { 90 method_elm->has_udata = def->write.has_udata; 91 method_elm->has_resp = def->write.has_resp; 92 method_elm->req_size = def->write.req_size; 93 method_elm->resp_size = def->write.resp_size; 94 } 95 96 *cur_method_key = method_key; 97 return 0; 98 } 99 100 static int uapi_merge_method(struct uverbs_api *uapi, 101 struct uverbs_api_object *obj_elm, u32 obj_key, 102 const struct uverbs_method_def *method, 103 bool is_driver) 104 { 105 u32 method_key = obj_key | uapi_key_ioctl_method(method->id); 106 struct uverbs_api_ioctl_method *method_elm; 107 unsigned int i; 108 bool exists; 109 110 if (!method->attrs) 111 return 0; 112 113 method_elm = uapi_add_get_elm(uapi, method_key, sizeof(*method_elm), 114 &exists); 115 if (IS_ERR(method_elm)) 116 return PTR_ERR(method_elm); 117 if (exists) { 118 /* 119 * This occurs when a driver uses ADD_UVERBS_ATTRIBUTES_SIMPLE 120 */ 121 if (WARN_ON(method->handler)) 122 return -EINVAL; 123 } else { 124 WARN_ON(!method->handler); 125 rcu_assign_pointer(method_elm->handler, method->handler); 126 if (method->handler != uverbs_destroy_def_handler) 127 method_elm->driver_method = is_driver; 128 } 129 130 for (i = 0; i != method->num_attrs; i++) { 131 const struct uverbs_attr_def *attr = (*method->attrs)[i]; 132 struct uverbs_api_attr *attr_slot; 133 134 if (!attr) 135 continue; 136 137 /* 138 * ENUM_IN contains the 'ids' pointer to the driver's .rodata, 139 * so if it is specified by a driver then it always makes this 140 * into a driver method. 141 */ 142 if (attr->attr.type == UVERBS_ATTR_TYPE_ENUM_IN) 143 method_elm->driver_method |= is_driver; 144 145 /* 146 * Like other uobject based things we only support a single 147 * uobject being NEW'd or DESTROY'd 148 */ 149 if (attr->attr.type == UVERBS_ATTR_TYPE_IDRS_ARRAY) { 150 u8 access = attr->attr.u2.objs_arr.access; 151 152 if (WARN_ON(access == UVERBS_ACCESS_NEW || 153 access == UVERBS_ACCESS_DESTROY)) 154 return -EINVAL; 155 } 156 157 attr_slot = 158 uapi_add_elm(uapi, method_key | uapi_key_attr(attr->id), 159 sizeof(*attr_slot)); 160 /* Attributes are not allowed to be modified by drivers */ 161 if (IS_ERR(attr_slot)) 162 return PTR_ERR(attr_slot); 163 164 attr_slot->spec = attr->attr; 165 } 166 167 return 0; 168 } 169 170 static int uapi_merge_obj_tree(struct uverbs_api *uapi, 171 const struct uverbs_object_def *obj, 172 bool is_driver) 173 { 174 struct uverbs_api_object *obj_elm; 175 unsigned int i; 176 u32 obj_key; 177 bool exists; 178 int rc; 179 180 obj_key = uapi_key_obj(obj->id); 181 obj_elm = uapi_add_get_elm(uapi, obj_key, sizeof(*obj_elm), &exists); 182 if (IS_ERR(obj_elm)) 183 return PTR_ERR(obj_elm); 184 185 if (obj->type_attrs) { 186 if (WARN_ON(obj_elm->type_attrs)) 187 return -EINVAL; 188 189 obj_elm->id = obj->id; 190 obj_elm->type_attrs = obj->type_attrs; 191 obj_elm->type_class = obj->type_attrs->type_class; 192 /* 193 * Today drivers are only permitted to use idr_class and 194 * fd_class types. We can revoke the IDR types during 195 * disassociation, and the FD types require the driver to use 196 * struct file_operations.owner to prevent the driver module 197 * code from unloading while the file is open. This provides 198 * enough safety that uverbs_close_fd() will continue to work. 199 * Drivers using FD are responsible to handle disassociation of 200 * the device on their own. 201 */ 202 if (WARN_ON(is_driver && 203 obj->type_attrs->type_class != &uverbs_idr_class && 204 obj->type_attrs->type_class != &uverbs_fd_class)) 205 return -EINVAL; 206 } 207 208 if (!obj->methods) 209 return 0; 210 211 for (i = 0; i != obj->num_methods; i++) { 212 const struct uverbs_method_def *method = (*obj->methods)[i]; 213 214 if (!method) 215 continue; 216 217 rc = uapi_merge_method(uapi, obj_elm, obj_key, method, 218 is_driver); 219 if (rc) 220 return rc; 221 } 222 223 return 0; 224 } 225 226 static int uapi_disable_elm(struct uverbs_api *uapi, 227 const struct uapi_definition *def, 228 u32 obj_key, 229 u32 method_key) 230 { 231 bool exists; 232 233 if (def->scope == UAPI_SCOPE_OBJECT) { 234 struct uverbs_api_object *obj_elm; 235 236 obj_elm = uapi_add_get_elm( 237 uapi, obj_key, sizeof(*obj_elm), &exists); 238 if (IS_ERR(obj_elm)) 239 return PTR_ERR(obj_elm); 240 obj_elm->disabled = 1; 241 return 0; 242 } 243 244 if (def->scope == UAPI_SCOPE_METHOD && 245 uapi_key_is_ioctl_method(method_key)) { 246 struct uverbs_api_ioctl_method *method_elm; 247 248 method_elm = uapi_add_get_elm(uapi, method_key, 249 sizeof(*method_elm), &exists); 250 if (IS_ERR(method_elm)) 251 return PTR_ERR(method_elm); 252 method_elm->disabled = 1; 253 return 0; 254 } 255 256 if (def->scope == UAPI_SCOPE_METHOD && 257 (uapi_key_is_write_method(method_key) || 258 uapi_key_is_write_ex_method(method_key))) { 259 struct uverbs_api_write_method *write_elm; 260 261 write_elm = uapi_add_get_elm(uapi, method_key, 262 sizeof(*write_elm), &exists); 263 if (IS_ERR(write_elm)) 264 return PTR_ERR(write_elm); 265 write_elm->disabled = 1; 266 return 0; 267 } 268 269 WARN_ON(true); 270 return -EINVAL; 271 } 272 273 static int uapi_merge_def(struct uverbs_api *uapi, struct ib_device *ibdev, 274 const struct uapi_definition *def_list, 275 bool is_driver) 276 { 277 const struct uapi_definition *def = def_list; 278 u32 cur_obj_key = UVERBS_API_KEY_ERR; 279 u32 cur_method_key = UVERBS_API_KEY_ERR; 280 bool exists; 281 int rc; 282 283 if (!def_list) 284 return 0; 285 286 for (;; def++) { 287 switch ((enum uapi_definition_kind)def->kind) { 288 case UAPI_DEF_CHAIN: 289 rc = uapi_merge_def(uapi, ibdev, def->chain, is_driver); 290 if (rc) 291 return rc; 292 continue; 293 294 case UAPI_DEF_CHAIN_OBJ_TREE: 295 if (WARN_ON(def->object_start.object_id != 296 def->chain_obj_tree->id)) 297 return -EINVAL; 298 299 cur_obj_key = uapi_key_obj(def->object_start.object_id); 300 rc = uapi_merge_obj_tree(uapi, def->chain_obj_tree, 301 is_driver); 302 if (rc) 303 return rc; 304 continue; 305 306 case UAPI_DEF_END: 307 return 0; 308 309 case UAPI_DEF_IS_SUPPORTED_DEV_FN: { 310 void **ibdev_fn = 311 (void *)(&ibdev->ops) + def->needs_fn_offset; 312 313 if (*ibdev_fn) 314 continue; 315 rc = uapi_disable_elm( 316 uapi, def, cur_obj_key, cur_method_key); 317 if (rc) 318 return rc; 319 continue; 320 } 321 322 case UAPI_DEF_IS_SUPPORTED_FUNC: 323 if (def->func_is_supported(ibdev)) 324 continue; 325 rc = uapi_disable_elm( 326 uapi, def, cur_obj_key, cur_method_key); 327 if (rc) 328 return rc; 329 continue; 330 331 case UAPI_DEF_OBJECT_START: { 332 struct uverbs_api_object *obj_elm; 333 334 cur_obj_key = uapi_key_obj(def->object_start.object_id); 335 obj_elm = uapi_add_get_elm(uapi, cur_obj_key, 336 sizeof(*obj_elm), &exists); 337 if (IS_ERR(obj_elm)) 338 return PTR_ERR(obj_elm); 339 continue; 340 } 341 342 case UAPI_DEF_WRITE: 343 rc = uapi_create_write( 344 uapi, ibdev, def, cur_obj_key, &cur_method_key); 345 if (rc) 346 return rc; 347 continue; 348 } 349 WARN_ON(true); 350 return -EINVAL; 351 } 352 } 353 354 static int 355 uapi_finalize_ioctl_method(struct uverbs_api *uapi, 356 struct uverbs_api_ioctl_method *method_elm, 357 u32 method_key) 358 { 359 struct radix_tree_iter iter; 360 unsigned int num_attrs = 0; 361 unsigned int max_bkey = 0; 362 bool single_uobj = false; 363 void __rcu **slot; 364 365 method_elm->destroy_bkey = UVERBS_API_ATTR_BKEY_LEN; 366 radix_tree_for_each_slot (slot, &uapi->radix, &iter, 367 uapi_key_attrs_start(method_key)) { 368 struct uverbs_api_attr *elm = 369 rcu_dereference_protected(*slot, true); 370 u32 attr_key = iter.index & UVERBS_API_ATTR_KEY_MASK; 371 u32 attr_bkey = uapi_bkey_attr(attr_key); 372 u8 type = elm->spec.type; 373 374 if (uapi_key_attr_to_ioctl_method(iter.index) != 375 uapi_key_attr_to_ioctl_method(method_key)) 376 break; 377 378 if (elm->spec.mandatory) 379 __set_bit(attr_bkey, method_elm->attr_mandatory); 380 381 if (elm->spec.is_udata) 382 method_elm->has_udata = true; 383 384 if (type == UVERBS_ATTR_TYPE_IDR || 385 type == UVERBS_ATTR_TYPE_FD) { 386 u8 access = elm->spec.u.obj.access; 387 388 /* 389 * Verbs specs may only have one NEW/DESTROY, we don't 390 * have the infrastructure to abort multiple NEW's or 391 * cope with multiple DESTROY failure. 392 */ 393 if (access == UVERBS_ACCESS_NEW || 394 access == UVERBS_ACCESS_DESTROY) { 395 if (WARN_ON(single_uobj)) 396 return -EINVAL; 397 398 single_uobj = true; 399 if (WARN_ON(!elm->spec.mandatory)) 400 return -EINVAL; 401 } 402 403 if (access == UVERBS_ACCESS_DESTROY) 404 method_elm->destroy_bkey = attr_bkey; 405 } 406 407 max_bkey = max(max_bkey, attr_bkey); 408 num_attrs++; 409 } 410 411 method_elm->key_bitmap_len = max_bkey + 1; 412 WARN_ON(method_elm->key_bitmap_len > UVERBS_API_ATTR_BKEY_LEN); 413 414 uapi_compute_bundle_size(method_elm, num_attrs); 415 return 0; 416 } 417 418 static int uapi_finalize(struct uverbs_api *uapi) 419 { 420 const struct uverbs_api_write_method **data; 421 unsigned long max_write_ex = 0; 422 unsigned long max_write = 0; 423 struct radix_tree_iter iter; 424 void __rcu **slot; 425 int rc; 426 int i; 427 428 radix_tree_for_each_slot (slot, &uapi->radix, &iter, 0) { 429 struct uverbs_api_ioctl_method *method_elm = 430 rcu_dereference_protected(*slot, true); 431 432 if (uapi_key_is_ioctl_method(iter.index)) { 433 rc = uapi_finalize_ioctl_method(uapi, method_elm, 434 iter.index); 435 if (rc) 436 return rc; 437 } 438 439 if (uapi_key_is_write_method(iter.index)) 440 max_write = max(max_write, 441 iter.index & UVERBS_API_ATTR_KEY_MASK); 442 if (uapi_key_is_write_ex_method(iter.index)) 443 max_write_ex = 444 max(max_write_ex, 445 iter.index & UVERBS_API_ATTR_KEY_MASK); 446 } 447 448 uapi->notsupp_method.handler = ib_uverbs_notsupp; 449 uapi->num_write = max_write + 1; 450 uapi->num_write_ex = max_write_ex + 1; 451 data = kmalloc_array(uapi->num_write + uapi->num_write_ex, 452 sizeof(*uapi->write_methods), GFP_KERNEL); 453 for (i = 0; i != uapi->num_write + uapi->num_write_ex; i++) 454 data[i] = &uapi->notsupp_method; 455 uapi->write_methods = data; 456 uapi->write_ex_methods = data + uapi->num_write; 457 458 radix_tree_for_each_slot (slot, &uapi->radix, &iter, 0) { 459 if (uapi_key_is_write_method(iter.index)) 460 uapi->write_methods[iter.index & 461 UVERBS_API_ATTR_KEY_MASK] = 462 rcu_dereference_protected(*slot, true); 463 if (uapi_key_is_write_ex_method(iter.index)) 464 uapi->write_ex_methods[iter.index & 465 UVERBS_API_ATTR_KEY_MASK] = 466 rcu_dereference_protected(*slot, true); 467 } 468 469 return 0; 470 } 471 472 static void uapi_remove_range(struct uverbs_api *uapi, u32 start, u32 last) 473 { 474 struct radix_tree_iter iter; 475 void __rcu **slot; 476 477 radix_tree_for_each_slot (slot, &uapi->radix, &iter, start) { 478 if (iter.index > last) 479 return; 480 kfree(rcu_dereference_protected(*slot, true)); 481 radix_tree_iter_delete(&uapi->radix, &iter, slot); 482 } 483 } 484 485 static void uapi_remove_object(struct uverbs_api *uapi, u32 obj_key) 486 { 487 uapi_remove_range(uapi, obj_key, 488 obj_key | UVERBS_API_METHOD_KEY_MASK | 489 UVERBS_API_ATTR_KEY_MASK); 490 } 491 492 static void uapi_remove_method(struct uverbs_api *uapi, u32 method_key) 493 { 494 uapi_remove_range(uapi, method_key, 495 method_key | UVERBS_API_ATTR_KEY_MASK); 496 } 497 498 499 static u32 uapi_get_obj_id(struct uverbs_attr_spec *spec) 500 { 501 if (spec->type == UVERBS_ATTR_TYPE_IDR || 502 spec->type == UVERBS_ATTR_TYPE_FD) 503 return spec->u.obj.obj_type; 504 if (spec->type == UVERBS_ATTR_TYPE_IDRS_ARRAY) 505 return spec->u2.objs_arr.obj_type; 506 return UVERBS_API_KEY_ERR; 507 } 508 509 static void uapi_key_okay(u32 key) 510 { 511 unsigned int count = 0; 512 513 if (uapi_key_is_object(key)) 514 count++; 515 if (uapi_key_is_ioctl_method(key)) 516 count++; 517 if (uapi_key_is_write_method(key)) 518 count++; 519 if (uapi_key_is_write_ex_method(key)) 520 count++; 521 if (uapi_key_is_attr(key)) 522 count++; 523 WARN(count != 1, "Bad count %d key=%x", count, key); 524 } 525 526 static void uapi_finalize_disable(struct uverbs_api *uapi) 527 { 528 struct radix_tree_iter iter; 529 u32 starting_key = 0; 530 bool scan_again = false; 531 void __rcu **slot; 532 533 again: 534 radix_tree_for_each_slot (slot, &uapi->radix, &iter, starting_key) { 535 uapi_key_okay(iter.index); 536 537 if (uapi_key_is_object(iter.index)) { 538 struct uverbs_api_object *obj_elm = 539 rcu_dereference_protected(*slot, true); 540 541 if (obj_elm->disabled) { 542 /* Have to check all the attrs again */ 543 scan_again = true; 544 starting_key = iter.index; 545 uapi_remove_object(uapi, iter.index); 546 goto again; 547 } 548 continue; 549 } 550 551 if (uapi_key_is_ioctl_method(iter.index)) { 552 struct uverbs_api_ioctl_method *method_elm = 553 rcu_dereference_protected(*slot, true); 554 555 if (method_elm->disabled) { 556 starting_key = iter.index; 557 uapi_remove_method(uapi, iter.index); 558 goto again; 559 } 560 continue; 561 } 562 563 if (uapi_key_is_write_method(iter.index) || 564 uapi_key_is_write_ex_method(iter.index)) { 565 struct uverbs_api_write_method *method_elm = 566 rcu_dereference_protected(*slot, true); 567 568 if (method_elm->disabled) { 569 kfree(method_elm); 570 radix_tree_iter_delete(&uapi->radix, &iter, slot); 571 } 572 continue; 573 } 574 575 if (uapi_key_is_attr(iter.index)) { 576 struct uverbs_api_attr *attr_elm = 577 rcu_dereference_protected(*slot, true); 578 const struct uverbs_api_object *tmp_obj; 579 u32 obj_key; 580 581 /* 582 * If the method has a mandatory object handle 583 * attribute which relies on an object which is not 584 * present then the entire method is uncallable. 585 */ 586 if (!attr_elm->spec.mandatory) 587 continue; 588 obj_key = uapi_get_obj_id(&attr_elm->spec); 589 if (obj_key == UVERBS_API_KEY_ERR) 590 continue; 591 tmp_obj = uapi_get_object(uapi, obj_key); 592 if (IS_ERR(tmp_obj)) { 593 if (PTR_ERR(tmp_obj) == -ENOMSG) 594 continue; 595 } else { 596 if (!tmp_obj->disabled) 597 continue; 598 } 599 600 starting_key = iter.index; 601 uapi_remove_method( 602 uapi, 603 iter.index & (UVERBS_API_OBJ_KEY_MASK | 604 UVERBS_API_METHOD_KEY_MASK)); 605 goto again; 606 } 607 608 WARN_ON(false); 609 } 610 611 if (!scan_again) 612 return; 613 scan_again = false; 614 starting_key = 0; 615 goto again; 616 } 617 618 void uverbs_destroy_api(struct uverbs_api *uapi) 619 { 620 if (!uapi) 621 return; 622 623 uapi_remove_range(uapi, 0, U32_MAX); 624 kfree(uapi->write_methods); 625 kfree(uapi); 626 } 627 628 static const struct uapi_definition uverbs_core_api[] = { 629 UAPI_DEF_CHAIN(uverbs_def_obj_counters), 630 UAPI_DEF_CHAIN(uverbs_def_obj_cq), 631 UAPI_DEF_CHAIN(uverbs_def_obj_device), 632 UAPI_DEF_CHAIN(uverbs_def_obj_dm), 633 UAPI_DEF_CHAIN(uverbs_def_obj_flow_action), 634 UAPI_DEF_CHAIN(uverbs_def_obj_intf), 635 UAPI_DEF_CHAIN(uverbs_def_obj_mr), 636 UAPI_DEF_CHAIN(uverbs_def_write_intf), 637 {}, 638 }; 639 640 struct uverbs_api *uverbs_alloc_api(struct ib_device *ibdev) 641 { 642 struct uverbs_api *uapi; 643 int rc; 644 645 uapi = kzalloc(sizeof(*uapi), GFP_KERNEL); 646 if (!uapi) 647 return ERR_PTR(-ENOMEM); 648 649 INIT_RADIX_TREE(&uapi->radix, GFP_KERNEL); 650 uapi->driver_id = ibdev->ops.driver_id; 651 652 rc = uapi_merge_def(uapi, ibdev, uverbs_core_api, false); 653 if (rc) 654 goto err; 655 rc = uapi_merge_def(uapi, ibdev, ibdev->driver_def, true); 656 if (rc) 657 goto err; 658 659 uapi_finalize_disable(uapi); 660 rc = uapi_finalize(uapi); 661 if (rc) 662 goto err; 663 664 return uapi; 665 err: 666 if (rc != -ENOMEM) 667 dev_err(&ibdev->dev, 668 "Setup of uverbs_api failed, kernel parsing tree description is not valid (%d)??\n", 669 rc); 670 671 uverbs_destroy_api(uapi); 672 return ERR_PTR(rc); 673 } 674 675 /* 676 * The pre version is done before destroying the HW objects, it only blocks 677 * off method access. All methods that require the ib_dev or the module data 678 * must test one of these assignments prior to continuing. 679 */ 680 void uverbs_disassociate_api_pre(struct ib_uverbs_device *uverbs_dev) 681 { 682 struct uverbs_api *uapi = uverbs_dev->uapi; 683 struct radix_tree_iter iter; 684 void __rcu **slot; 685 686 rcu_assign_pointer(uverbs_dev->ib_dev, NULL); 687 688 radix_tree_for_each_slot (slot, &uapi->radix, &iter, 0) { 689 if (uapi_key_is_ioctl_method(iter.index)) { 690 struct uverbs_api_ioctl_method *method_elm = 691 rcu_dereference_protected(*slot, true); 692 693 if (method_elm->driver_method) 694 rcu_assign_pointer(method_elm->handler, NULL); 695 } 696 } 697 698 synchronize_srcu(&uverbs_dev->disassociate_srcu); 699 } 700 701 /* 702 * Called when a driver disassociates from the ib_uverbs_device. The 703 * assumption is that the driver module will unload after. Replace everything 704 * related to the driver with NULL as a safety measure. 705 */ 706 void uverbs_disassociate_api(struct uverbs_api *uapi) 707 { 708 struct radix_tree_iter iter; 709 void __rcu **slot; 710 711 radix_tree_for_each_slot (slot, &uapi->radix, &iter, 0) { 712 if (uapi_key_is_object(iter.index)) { 713 struct uverbs_api_object *object_elm = 714 rcu_dereference_protected(*slot, true); 715 716 /* 717 * Some type_attrs are in the driver module. We don't 718 * bother to keep track of which since there should be 719 * no use of this after disassociate. 720 */ 721 object_elm->type_attrs = NULL; 722 } else if (uapi_key_is_attr(iter.index)) { 723 struct uverbs_api_attr *elm = 724 rcu_dereference_protected(*slot, true); 725 726 if (elm->spec.type == UVERBS_ATTR_TYPE_ENUM_IN) 727 elm->spec.u2.enum_def.ids = NULL; 728 } 729 } 730 } 731