Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
0002 /*
0003  * Copyright (c) 2017, Mellanox Technologies inc.  All rights reserved.
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          * This occurs when a driver uses ADD_UVERBS_ATTRIBUTES_SIMPLE
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          * ENUM_IN contains the 'ids' pointer to the driver's .rodata,
0136          * so if it is specified by a driver then it always makes this
0137          * into a driver method.
0138          */
0139         if (attr->attr.type == UVERBS_ATTR_TYPE_ENUM_IN)
0140             method_elm->driver_method |= is_driver;
0141 
0142         /*
0143          * Like other uobject based things we only support a single
0144          * uobject being NEW'd or DESTROY'd
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         /* Attributes are not allowed to be modified by drivers */
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          * Today drivers are only permitted to use idr_class and
0191          * fd_class types. We can revoke the IDR types during
0192          * disassociation, and the FD types require the driver to use
0193          * struct file_operations.owner to prevent the driver module
0194          * code from unloading while the file is open. This provides
0195          * enough safety that uverbs_uobject_fd_release() will
0196          * continue to work.  Drivers using FD are responsible to
0197          * handle disassociation of the device on their own.
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              * Verbs specs may only have one NEW/DESTROY, we don't
0387              * have the infrastructure to abort multiple NEW's or
0388              * cope with multiple DESTROY failure.
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                 /* Have to check all the attrs again */
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              * If the method has a mandatory object handle
0583              * attribute which relies on an object which is not
0584              * present then the entire method is uncallable.
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  * The pre version is done before destroying the HW objects, it only blocks
0681  * off method access. All methods that require the ib_dev or the module data
0682  * must test one of these assignments prior to continuing.
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  * Called when a driver disassociates from the ib_uverbs_device. The
0707  * assumption is that the driver module will unload after. Replace everything
0708  * related to the driver with NULL as a safety measure.
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              * Some type_attrs are in the driver module. We don't
0722              * bother to keep track of which since there should be
0723              * no use of this after disassociate.
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 }