The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/ofed/drivers/infiniband/core/ib_uverbs_uapi.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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_uobject_fd_release() will
  199                  * continue to work.  Drivers using FD are responsible to
  200                  * handle disassociation of 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 *)((u8 *)ibdev + 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_async_fd),
  630         UAPI_DEF_CHAIN(uverbs_def_obj_counters),
  631         UAPI_DEF_CHAIN(uverbs_def_obj_cq),
  632         UAPI_DEF_CHAIN(uverbs_def_obj_device),
  633         UAPI_DEF_CHAIN(uverbs_def_obj_dm),
  634         UAPI_DEF_CHAIN(uverbs_def_obj_flow_action),
  635         UAPI_DEF_CHAIN(uverbs_def_obj_intf),
  636         UAPI_DEF_CHAIN(uverbs_def_obj_mr),
  637         UAPI_DEF_CHAIN(uverbs_def_write_intf),
  638         {},
  639 };
  640 
  641 struct uverbs_api *uverbs_alloc_api(struct ib_device *ibdev)
  642 {
  643         struct uverbs_api *uapi;
  644         int rc;
  645 
  646         uapi = kzalloc(sizeof(*uapi), GFP_KERNEL);
  647         if (!uapi)
  648                 return ERR_PTR(-ENOMEM);
  649 
  650         INIT_RADIX_TREE(&uapi->radix, GFP_KERNEL);
  651         uapi->driver_id = ibdev->ops.driver_id;
  652 
  653         rc = uapi_merge_def(uapi, ibdev, uverbs_core_api, false);
  654         if (rc)
  655                 goto err;
  656         rc = uapi_merge_def(uapi, ibdev, ibdev->driver_def, true);
  657         if (rc)
  658                 goto err;
  659 
  660         uapi_finalize_disable(uapi);
  661         rc = uapi_finalize(uapi);
  662         if (rc)
  663                 goto err;
  664 
  665         return uapi;
  666 err:
  667         if (rc != -ENOMEM)
  668                 dev_err(&ibdev->dev,
  669                         "Setup of uverbs_api failed, kernel parsing tree description is not valid (%d)??\n",
  670                         rc);
  671 
  672         uverbs_destroy_api(uapi);
  673         return ERR_PTR(rc);
  674 }
  675 
  676 /*
  677  * The pre version is done before destroying the HW objects, it only blocks
  678  * off method access. All methods that require the ib_dev or the module data
  679  * must test one of these assignments prior to continuing.
  680  */
  681 void uverbs_disassociate_api_pre(struct ib_uverbs_device *uverbs_dev)
  682 {
  683         struct uverbs_api *uapi = uverbs_dev->uapi;
  684         struct radix_tree_iter iter;
  685         void __rcu **slot;
  686 
  687         rcu_assign_pointer(uverbs_dev->ib_dev, NULL);
  688 
  689         radix_tree_for_each_slot (slot, &uapi->radix, &iter, 0) {
  690                 if (uapi_key_is_ioctl_method(iter.index)) {
  691                         struct uverbs_api_ioctl_method *method_elm =
  692                                 rcu_dereference_protected(*slot, true);
  693 
  694                         if (method_elm->driver_method)
  695                                 rcu_assign_pointer(method_elm->handler, NULL);
  696                 }
  697         }
  698 
  699         synchronize_srcu(&uverbs_dev->disassociate_srcu);
  700 }
  701 
  702 /*
  703  * Called when a driver disassociates from the ib_uverbs_device. The
  704  * assumption is that the driver module will unload after. Replace everything
  705  * related to the driver with NULL as a safety measure.
  706  */
  707 void uverbs_disassociate_api(struct uverbs_api *uapi)
  708 {
  709         struct radix_tree_iter iter;
  710         void __rcu **slot;
  711 
  712         radix_tree_for_each_slot (slot, &uapi->radix, &iter, 0) {
  713                 if (uapi_key_is_object(iter.index)) {
  714                         struct uverbs_api_object *object_elm =
  715                                 rcu_dereference_protected(*slot, true);
  716 
  717                         /*
  718                          * Some type_attrs are in the driver module. We don't
  719                          * bother to keep track of which since there should be
  720                          * no use of this after disassociate.
  721                          */
  722                         object_elm->type_attrs = NULL;
  723                 } else if (uapi_key_is_attr(iter.index)) {
  724                         struct uverbs_api_attr *elm =
  725                                 rcu_dereference_protected(*slot, true);
  726 
  727                         if (elm->spec.type == UVERBS_ATTR_TYPE_ENUM_IN)
  728                                 elm->spec.u2.enum_def.ids = NULL;
  729                 }
  730         }
  731 }

Cache object: ffe5dfebfad24439589603b8ed959ed9


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.