0001
0002
0003
0004
0005 #include <rdma/uverbs_ioctl.h>
0006 #include <rdma/rdma_user_ioctl.h>
0007 #include <linux/bitops.h>
0008 #include "rdma_core.h"
0009 #include "uverbs.h"
0010
0011 static int ib_uverbs_notsupp(struct uverbs_attr_bundle *attrs)
0012 {
0013 return -EOPNOTSUPP;
0014 }
0015
0016 static void *uapi_add_elm(struct uverbs_api *uapi, u32 key, size_t alloc_size)
0017 {
0018 void *elm;
0019 int rc;
0020
0021 if (key == UVERBS_API_KEY_ERR)
0022 return ERR_PTR(-EOVERFLOW);
0023
0024 elm = kzalloc(alloc_size, GFP_KERNEL);
0025 if (!elm)
0026 return ERR_PTR(-ENOMEM);
0027 rc = radix_tree_insert(&uapi->radix, key, elm);
0028 if (rc) {
0029 kfree(elm);
0030 return ERR_PTR(rc);
0031 }
0032
0033 return elm;
0034 }
0035
0036 static void *uapi_add_get_elm(struct uverbs_api *uapi, u32 key,
0037 size_t alloc_size, bool *exists)
0038 {
0039 void *elm;
0040
0041 elm = uapi_add_elm(uapi, key, alloc_size);
0042 if (!IS_ERR(elm)) {
0043 *exists = false;
0044 return elm;
0045 }
0046
0047 if (elm != ERR_PTR(-EEXIST))
0048 return elm;
0049
0050 elm = radix_tree_lookup(&uapi->radix, key);
0051 if (WARN_ON(!elm))
0052 return ERR_PTR(-EINVAL);
0053 *exists = true;
0054 return elm;
0055 }
0056
0057 static int uapi_create_write(struct uverbs_api *uapi,
0058 struct ib_device *ibdev,
0059 const struct uapi_definition *def,
0060 u32 obj_key,
0061 u32 *cur_method_key)
0062 {
0063 struct uverbs_api_write_method *method_elm;
0064 u32 method_key = obj_key;
0065 bool exists;
0066
0067 if (def->write.is_ex)
0068 method_key |= uapi_key_write_ex_method(def->write.command_num);
0069 else
0070 method_key |= uapi_key_write_method(def->write.command_num);
0071
0072 method_elm = uapi_add_get_elm(uapi, method_key, sizeof(*method_elm),
0073 &exists);
0074 if (IS_ERR(method_elm))
0075 return PTR_ERR(method_elm);
0076
0077 if (WARN_ON(exists && (def->write.is_ex != method_elm->is_ex)))
0078 return -EINVAL;
0079
0080 method_elm->is_ex = def->write.is_ex;
0081 method_elm->handler = def->func_write;
0082 if (!def->write.is_ex)
0083 method_elm->disabled = !(ibdev->uverbs_cmd_mask &
0084 BIT_ULL(def->write.command_num));
0085
0086 if (!def->write.is_ex && def->func_write) {
0087 method_elm->has_udata = def->write.has_udata;
0088 method_elm->has_resp = def->write.has_resp;
0089 method_elm->req_size = def->write.req_size;
0090 method_elm->resp_size = def->write.resp_size;
0091 }
0092
0093 *cur_method_key = method_key;
0094 return 0;
0095 }
0096
0097 static int uapi_merge_method(struct uverbs_api *uapi,
0098 struct uverbs_api_object *obj_elm, u32 obj_key,
0099 const struct uverbs_method_def *method,
0100 bool is_driver)
0101 {
0102 u32 method_key = obj_key | uapi_key_ioctl_method(method->id);
0103 struct uverbs_api_ioctl_method *method_elm;
0104 unsigned int i;
0105 bool exists;
0106
0107 if (!method->attrs)
0108 return 0;
0109
0110 method_elm = uapi_add_get_elm(uapi, method_key, sizeof(*method_elm),
0111 &exists);
0112 if (IS_ERR(method_elm))
0113 return PTR_ERR(method_elm);
0114 if (exists) {
0115
0116
0117
0118 if (WARN_ON(method->handler))
0119 return -EINVAL;
0120 } else {
0121 WARN_ON(!method->handler);
0122 rcu_assign_pointer(method_elm->handler, method->handler);
0123 if (method->handler != uverbs_destroy_def_handler)
0124 method_elm->driver_method = is_driver;
0125 }
0126
0127 for (i = 0; i != method->num_attrs; i++) {
0128 const struct uverbs_attr_def *attr = (*method->attrs)[i];
0129 struct uverbs_api_attr *attr_slot;
0130
0131 if (!attr)
0132 continue;
0133
0134
0135
0136
0137
0138
0139 if (attr->attr.type == UVERBS_ATTR_TYPE_ENUM_IN)
0140 method_elm->driver_method |= is_driver;
0141
0142
0143
0144
0145
0146 if (attr->attr.type == UVERBS_ATTR_TYPE_IDRS_ARRAY) {
0147 u8 access = attr->attr.u2.objs_arr.access;
0148
0149 if (WARN_ON(access == UVERBS_ACCESS_NEW ||
0150 access == UVERBS_ACCESS_DESTROY))
0151 return -EINVAL;
0152 }
0153
0154 attr_slot =
0155 uapi_add_elm(uapi, method_key | uapi_key_attr(attr->id),
0156 sizeof(*attr_slot));
0157
0158 if (IS_ERR(attr_slot))
0159 return PTR_ERR(attr_slot);
0160
0161 attr_slot->spec = attr->attr;
0162 }
0163
0164 return 0;
0165 }
0166
0167 static int uapi_merge_obj_tree(struct uverbs_api *uapi,
0168 const struct uverbs_object_def *obj,
0169 bool is_driver)
0170 {
0171 struct uverbs_api_object *obj_elm;
0172 unsigned int i;
0173 u32 obj_key;
0174 bool exists;
0175 int rc;
0176
0177 obj_key = uapi_key_obj(obj->id);
0178 obj_elm = uapi_add_get_elm(uapi, obj_key, sizeof(*obj_elm), &exists);
0179 if (IS_ERR(obj_elm))
0180 return PTR_ERR(obj_elm);
0181
0182 if (obj->type_attrs) {
0183 if (WARN_ON(obj_elm->type_attrs))
0184 return -EINVAL;
0185
0186 obj_elm->id = obj->id;
0187 obj_elm->type_attrs = obj->type_attrs;
0188 obj_elm->type_class = obj->type_attrs->type_class;
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199 if (WARN_ON(is_driver &&
0200 obj->type_attrs->type_class != &uverbs_idr_class &&
0201 obj->type_attrs->type_class != &uverbs_fd_class))
0202 return -EINVAL;
0203 }
0204
0205 if (!obj->methods)
0206 return 0;
0207
0208 for (i = 0; i != obj->num_methods; i++) {
0209 const struct uverbs_method_def *method = (*obj->methods)[i];
0210
0211 if (!method)
0212 continue;
0213
0214 rc = uapi_merge_method(uapi, obj_elm, obj_key, method,
0215 is_driver);
0216 if (rc)
0217 return rc;
0218 }
0219
0220 return 0;
0221 }
0222
0223 static int uapi_disable_elm(struct uverbs_api *uapi,
0224 const struct uapi_definition *def,
0225 u32 obj_key,
0226 u32 method_key)
0227 {
0228 bool exists;
0229
0230 if (def->scope == UAPI_SCOPE_OBJECT) {
0231 struct uverbs_api_object *obj_elm;
0232
0233 obj_elm = uapi_add_get_elm(
0234 uapi, obj_key, sizeof(*obj_elm), &exists);
0235 if (IS_ERR(obj_elm))
0236 return PTR_ERR(obj_elm);
0237 obj_elm->disabled = 1;
0238 return 0;
0239 }
0240
0241 if (def->scope == UAPI_SCOPE_METHOD &&
0242 uapi_key_is_ioctl_method(method_key)) {
0243 struct uverbs_api_ioctl_method *method_elm;
0244
0245 method_elm = uapi_add_get_elm(uapi, method_key,
0246 sizeof(*method_elm), &exists);
0247 if (IS_ERR(method_elm))
0248 return PTR_ERR(method_elm);
0249 method_elm->disabled = 1;
0250 return 0;
0251 }
0252
0253 if (def->scope == UAPI_SCOPE_METHOD &&
0254 (uapi_key_is_write_method(method_key) ||
0255 uapi_key_is_write_ex_method(method_key))) {
0256 struct uverbs_api_write_method *write_elm;
0257
0258 write_elm = uapi_add_get_elm(uapi, method_key,
0259 sizeof(*write_elm), &exists);
0260 if (IS_ERR(write_elm))
0261 return PTR_ERR(write_elm);
0262 write_elm->disabled = 1;
0263 return 0;
0264 }
0265
0266 WARN_ON(true);
0267 return -EINVAL;
0268 }
0269
0270 static int uapi_merge_def(struct uverbs_api *uapi, struct ib_device *ibdev,
0271 const struct uapi_definition *def_list,
0272 bool is_driver)
0273 {
0274 const struct uapi_definition *def = def_list;
0275 u32 cur_obj_key = UVERBS_API_KEY_ERR;
0276 u32 cur_method_key = UVERBS_API_KEY_ERR;
0277 bool exists;
0278 int rc;
0279
0280 if (!def_list)
0281 return 0;
0282
0283 for (;; def++) {
0284 switch ((enum uapi_definition_kind)def->kind) {
0285 case UAPI_DEF_CHAIN:
0286 rc = uapi_merge_def(uapi, ibdev, def->chain, is_driver);
0287 if (rc)
0288 return rc;
0289 continue;
0290
0291 case UAPI_DEF_CHAIN_OBJ_TREE:
0292 if (WARN_ON(def->object_start.object_id !=
0293 def->chain_obj_tree->id))
0294 return -EINVAL;
0295
0296 cur_obj_key = uapi_key_obj(def->object_start.object_id);
0297 rc = uapi_merge_obj_tree(uapi, def->chain_obj_tree,
0298 is_driver);
0299 if (rc)
0300 return rc;
0301 continue;
0302
0303 case UAPI_DEF_END:
0304 return 0;
0305
0306 case UAPI_DEF_IS_SUPPORTED_DEV_FN: {
0307 void **ibdev_fn =
0308 (void *)(&ibdev->ops) + def->needs_fn_offset;
0309
0310 if (*ibdev_fn)
0311 continue;
0312 rc = uapi_disable_elm(
0313 uapi, def, cur_obj_key, cur_method_key);
0314 if (rc)
0315 return rc;
0316 continue;
0317 }
0318
0319 case UAPI_DEF_IS_SUPPORTED_FUNC:
0320 if (def->func_is_supported(ibdev))
0321 continue;
0322 rc = uapi_disable_elm(
0323 uapi, def, cur_obj_key, cur_method_key);
0324 if (rc)
0325 return rc;
0326 continue;
0327
0328 case UAPI_DEF_OBJECT_START: {
0329 struct uverbs_api_object *obj_elm;
0330
0331 cur_obj_key = uapi_key_obj(def->object_start.object_id);
0332 obj_elm = uapi_add_get_elm(uapi, cur_obj_key,
0333 sizeof(*obj_elm), &exists);
0334 if (IS_ERR(obj_elm))
0335 return PTR_ERR(obj_elm);
0336 continue;
0337 }
0338
0339 case UAPI_DEF_WRITE:
0340 rc = uapi_create_write(
0341 uapi, ibdev, def, cur_obj_key, &cur_method_key);
0342 if (rc)
0343 return rc;
0344 continue;
0345 }
0346 WARN_ON(true);
0347 return -EINVAL;
0348 }
0349 }
0350
0351 static int
0352 uapi_finalize_ioctl_method(struct uverbs_api *uapi,
0353 struct uverbs_api_ioctl_method *method_elm,
0354 u32 method_key)
0355 {
0356 struct radix_tree_iter iter;
0357 unsigned int num_attrs = 0;
0358 unsigned int max_bkey = 0;
0359 bool single_uobj = false;
0360 void __rcu **slot;
0361
0362 method_elm->destroy_bkey = UVERBS_API_ATTR_BKEY_LEN;
0363 radix_tree_for_each_slot (slot, &uapi->radix, &iter,
0364 uapi_key_attrs_start(method_key)) {
0365 struct uverbs_api_attr *elm =
0366 rcu_dereference_protected(*slot, true);
0367 u32 attr_key = iter.index & UVERBS_API_ATTR_KEY_MASK;
0368 u32 attr_bkey = uapi_bkey_attr(attr_key);
0369 u8 type = elm->spec.type;
0370
0371 if (uapi_key_attr_to_ioctl_method(iter.index) !=
0372 uapi_key_attr_to_ioctl_method(method_key))
0373 break;
0374
0375 if (elm->spec.mandatory)
0376 __set_bit(attr_bkey, method_elm->attr_mandatory);
0377
0378 if (elm->spec.is_udata)
0379 method_elm->has_udata = true;
0380
0381 if (type == UVERBS_ATTR_TYPE_IDR ||
0382 type == UVERBS_ATTR_TYPE_FD) {
0383 u8 access = elm->spec.u.obj.access;
0384
0385
0386
0387
0388
0389
0390 if (access == UVERBS_ACCESS_NEW ||
0391 access == UVERBS_ACCESS_DESTROY) {
0392 if (WARN_ON(single_uobj))
0393 return -EINVAL;
0394
0395 single_uobj = true;
0396 if (WARN_ON(!elm->spec.mandatory))
0397 return -EINVAL;
0398 }
0399
0400 if (access == UVERBS_ACCESS_DESTROY)
0401 method_elm->destroy_bkey = attr_bkey;
0402 }
0403
0404 max_bkey = max(max_bkey, attr_bkey);
0405 num_attrs++;
0406 }
0407
0408 method_elm->key_bitmap_len = max_bkey + 1;
0409 WARN_ON(method_elm->key_bitmap_len > UVERBS_API_ATTR_BKEY_LEN);
0410
0411 uapi_compute_bundle_size(method_elm, num_attrs);
0412 return 0;
0413 }
0414
0415 static int uapi_finalize(struct uverbs_api *uapi)
0416 {
0417 const struct uverbs_api_write_method **data;
0418 unsigned long max_write_ex = 0;
0419 unsigned long max_write = 0;
0420 struct radix_tree_iter iter;
0421 void __rcu **slot;
0422 int rc;
0423 int i;
0424
0425 radix_tree_for_each_slot (slot, &uapi->radix, &iter, 0) {
0426 struct uverbs_api_ioctl_method *method_elm =
0427 rcu_dereference_protected(*slot, true);
0428
0429 if (uapi_key_is_ioctl_method(iter.index)) {
0430 rc = uapi_finalize_ioctl_method(uapi, method_elm,
0431 iter.index);
0432 if (rc)
0433 return rc;
0434 }
0435
0436 if (uapi_key_is_write_method(iter.index))
0437 max_write = max(max_write,
0438 iter.index & UVERBS_API_ATTR_KEY_MASK);
0439 if (uapi_key_is_write_ex_method(iter.index))
0440 max_write_ex =
0441 max(max_write_ex,
0442 iter.index & UVERBS_API_ATTR_KEY_MASK);
0443 }
0444
0445 uapi->notsupp_method.handler = ib_uverbs_notsupp;
0446 uapi->num_write = max_write + 1;
0447 uapi->num_write_ex = max_write_ex + 1;
0448 data = kmalloc_array(uapi->num_write + uapi->num_write_ex,
0449 sizeof(*uapi->write_methods), GFP_KERNEL);
0450 if (!data)
0451 return -ENOMEM;
0452
0453 for (i = 0; i != uapi->num_write + uapi->num_write_ex; i++)
0454 data[i] = &uapi->notsupp_method;
0455 uapi->write_methods = data;
0456 uapi->write_ex_methods = data + uapi->num_write;
0457
0458 radix_tree_for_each_slot (slot, &uapi->radix, &iter, 0) {
0459 if (uapi_key_is_write_method(iter.index))
0460 uapi->write_methods[iter.index &
0461 UVERBS_API_ATTR_KEY_MASK] =
0462 rcu_dereference_protected(*slot, true);
0463 if (uapi_key_is_write_ex_method(iter.index))
0464 uapi->write_ex_methods[iter.index &
0465 UVERBS_API_ATTR_KEY_MASK] =
0466 rcu_dereference_protected(*slot, true);
0467 }
0468
0469 return 0;
0470 }
0471
0472 static void uapi_remove_range(struct uverbs_api *uapi, u32 start, u32 last)
0473 {
0474 struct radix_tree_iter iter;
0475 void __rcu **slot;
0476
0477 radix_tree_for_each_slot (slot, &uapi->radix, &iter, start) {
0478 if (iter.index > last)
0479 return;
0480 kfree(rcu_dereference_protected(*slot, true));
0481 radix_tree_iter_delete(&uapi->radix, &iter, slot);
0482 }
0483 }
0484
0485 static void uapi_remove_object(struct uverbs_api *uapi, u32 obj_key)
0486 {
0487 uapi_remove_range(uapi, obj_key,
0488 obj_key | UVERBS_API_METHOD_KEY_MASK |
0489 UVERBS_API_ATTR_KEY_MASK);
0490 }
0491
0492 static void uapi_remove_method(struct uverbs_api *uapi, u32 method_key)
0493 {
0494 uapi_remove_range(uapi, method_key,
0495 method_key | UVERBS_API_ATTR_KEY_MASK);
0496 }
0497
0498
0499 static u32 uapi_get_obj_id(struct uverbs_attr_spec *spec)
0500 {
0501 if (spec->type == UVERBS_ATTR_TYPE_IDR ||
0502 spec->type == UVERBS_ATTR_TYPE_FD)
0503 return spec->u.obj.obj_type;
0504 if (spec->type == UVERBS_ATTR_TYPE_IDRS_ARRAY)
0505 return spec->u2.objs_arr.obj_type;
0506 return UVERBS_API_KEY_ERR;
0507 }
0508
0509 static void uapi_key_okay(u32 key)
0510 {
0511 unsigned int count = 0;
0512
0513 if (uapi_key_is_object(key))
0514 count++;
0515 if (uapi_key_is_ioctl_method(key))
0516 count++;
0517 if (uapi_key_is_write_method(key))
0518 count++;
0519 if (uapi_key_is_write_ex_method(key))
0520 count++;
0521 if (uapi_key_is_attr(key))
0522 count++;
0523 WARN(count != 1, "Bad count %u key=%x", count, key);
0524 }
0525
0526 static void uapi_finalize_disable(struct uverbs_api *uapi)
0527 {
0528 struct radix_tree_iter iter;
0529 u32 starting_key = 0;
0530 bool scan_again = false;
0531 void __rcu **slot;
0532
0533 again:
0534 radix_tree_for_each_slot (slot, &uapi->radix, &iter, starting_key) {
0535 uapi_key_okay(iter.index);
0536
0537 if (uapi_key_is_object(iter.index)) {
0538 struct uverbs_api_object *obj_elm =
0539 rcu_dereference_protected(*slot, true);
0540
0541 if (obj_elm->disabled) {
0542
0543 scan_again = true;
0544 starting_key = iter.index;
0545 uapi_remove_object(uapi, iter.index);
0546 goto again;
0547 }
0548 continue;
0549 }
0550
0551 if (uapi_key_is_ioctl_method(iter.index)) {
0552 struct uverbs_api_ioctl_method *method_elm =
0553 rcu_dereference_protected(*slot, true);
0554
0555 if (method_elm->disabled) {
0556 starting_key = iter.index;
0557 uapi_remove_method(uapi, iter.index);
0558 goto again;
0559 }
0560 continue;
0561 }
0562
0563 if (uapi_key_is_write_method(iter.index) ||
0564 uapi_key_is_write_ex_method(iter.index)) {
0565 struct uverbs_api_write_method *method_elm =
0566 rcu_dereference_protected(*slot, true);
0567
0568 if (method_elm->disabled) {
0569 kfree(method_elm);
0570 radix_tree_iter_delete(&uapi->radix, &iter, slot);
0571 }
0572 continue;
0573 }
0574
0575 if (uapi_key_is_attr(iter.index)) {
0576 struct uverbs_api_attr *attr_elm =
0577 rcu_dereference_protected(*slot, true);
0578 const struct uverbs_api_object *tmp_obj;
0579 u32 obj_key;
0580
0581
0582
0583
0584
0585
0586 if (!attr_elm->spec.mandatory)
0587 continue;
0588 obj_key = uapi_get_obj_id(&attr_elm->spec);
0589 if (obj_key == UVERBS_API_KEY_ERR)
0590 continue;
0591 tmp_obj = uapi_get_object(uapi, obj_key);
0592 if (IS_ERR(tmp_obj)) {
0593 if (PTR_ERR(tmp_obj) == -ENOMSG)
0594 continue;
0595 } else {
0596 if (!tmp_obj->disabled)
0597 continue;
0598 }
0599
0600 starting_key = iter.index;
0601 uapi_remove_method(
0602 uapi,
0603 iter.index & (UVERBS_API_OBJ_KEY_MASK |
0604 UVERBS_API_METHOD_KEY_MASK));
0605 goto again;
0606 }
0607
0608 WARN_ON(false);
0609 }
0610
0611 if (!scan_again)
0612 return;
0613 scan_again = false;
0614 starting_key = 0;
0615 goto again;
0616 }
0617
0618 void uverbs_destroy_api(struct uverbs_api *uapi)
0619 {
0620 if (!uapi)
0621 return;
0622
0623 uapi_remove_range(uapi, 0, U32_MAX);
0624 kfree(uapi->write_methods);
0625 kfree(uapi);
0626 }
0627
0628 static const struct uapi_definition uverbs_core_api[] = {
0629 UAPI_DEF_CHAIN(uverbs_def_obj_async_fd),
0630 UAPI_DEF_CHAIN(uverbs_def_obj_counters),
0631 UAPI_DEF_CHAIN(uverbs_def_obj_cq),
0632 UAPI_DEF_CHAIN(uverbs_def_obj_device),
0633 UAPI_DEF_CHAIN(uverbs_def_obj_dm),
0634 UAPI_DEF_CHAIN(uverbs_def_obj_flow_action),
0635 UAPI_DEF_CHAIN(uverbs_def_obj_intf),
0636 UAPI_DEF_CHAIN(uverbs_def_obj_mr),
0637 UAPI_DEF_CHAIN(uverbs_def_obj_qp),
0638 UAPI_DEF_CHAIN(uverbs_def_obj_srq),
0639 UAPI_DEF_CHAIN(uverbs_def_obj_wq),
0640 UAPI_DEF_CHAIN(uverbs_def_write_intf),
0641 {},
0642 };
0643
0644 struct uverbs_api *uverbs_alloc_api(struct ib_device *ibdev)
0645 {
0646 struct uverbs_api *uapi;
0647 int rc;
0648
0649 uapi = kzalloc(sizeof(*uapi), GFP_KERNEL);
0650 if (!uapi)
0651 return ERR_PTR(-ENOMEM);
0652
0653 INIT_RADIX_TREE(&uapi->radix, GFP_KERNEL);
0654 uapi->driver_id = ibdev->ops.driver_id;
0655
0656 rc = uapi_merge_def(uapi, ibdev, uverbs_core_api, false);
0657 if (rc)
0658 goto err;
0659 rc = uapi_merge_def(uapi, ibdev, ibdev->driver_def, true);
0660 if (rc)
0661 goto err;
0662
0663 uapi_finalize_disable(uapi);
0664 rc = uapi_finalize(uapi);
0665 if (rc)
0666 goto err;
0667
0668 return uapi;
0669 err:
0670 if (rc != -ENOMEM)
0671 dev_err(&ibdev->dev,
0672 "Setup of uverbs_api failed, kernel parsing tree description is not valid (%d)??\n",
0673 rc);
0674
0675 uverbs_destroy_api(uapi);
0676 return ERR_PTR(rc);
0677 }
0678
0679
0680
0681
0682
0683
0684 void uverbs_disassociate_api_pre(struct ib_uverbs_device *uverbs_dev)
0685 {
0686 struct uverbs_api *uapi = uverbs_dev->uapi;
0687 struct radix_tree_iter iter;
0688 void __rcu **slot;
0689
0690 rcu_assign_pointer(uverbs_dev->ib_dev, NULL);
0691
0692 radix_tree_for_each_slot (slot, &uapi->radix, &iter, 0) {
0693 if (uapi_key_is_ioctl_method(iter.index)) {
0694 struct uverbs_api_ioctl_method *method_elm =
0695 rcu_dereference_protected(*slot, true);
0696
0697 if (method_elm->driver_method)
0698 rcu_assign_pointer(method_elm->handler, NULL);
0699 }
0700 }
0701
0702 synchronize_srcu(&uverbs_dev->disassociate_srcu);
0703 }
0704
0705
0706
0707
0708
0709
0710 void uverbs_disassociate_api(struct uverbs_api *uapi)
0711 {
0712 struct radix_tree_iter iter;
0713 void __rcu **slot;
0714
0715 radix_tree_for_each_slot (slot, &uapi->radix, &iter, 0) {
0716 if (uapi_key_is_object(iter.index)) {
0717 struct uverbs_api_object *object_elm =
0718 rcu_dereference_protected(*slot, true);
0719
0720
0721
0722
0723
0724
0725 object_elm->type_attrs = NULL;
0726 } else if (uapi_key_is_attr(iter.index)) {
0727 struct uverbs_api_attr *elm =
0728 rcu_dereference_protected(*slot, true);
0729
0730 if (elm->spec.type == UVERBS_ATTR_TYPE_ENUM_IN)
0731 elm->spec.u2.enum_def.ids = NULL;
0732 }
0733 }
0734 }