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_ioctl.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 /*
    2  * Copyright (c) 2017, Mellanox Technologies inc.  All rights reserved.
    3  *
    4  * This software is available to you under a choice of one of two
    5  * licenses.  You may choose to be licensed under the terms of the GNU
    6  * General Public License (GPL) Version 2, available from the file
    7  * COPYING in the main directory of this source tree, or the
    8  * OpenIB.org BSD license below:
    9  *
   10  *     Redistribution and use in source and binary forms, with or
   11  *     without modification, are permitted provided that the following
   12  *     conditions are met:
   13  *
   14  *      - Redistributions of source code must retain the above
   15  *        copyright notice, this list of conditions and the following
   16  *        disclaimer.
   17  *
   18  *      - Redistributions in binary form must reproduce the above
   19  *        copyright notice, this list of conditions and the following
   20  *        disclaimer in the documentation and/or other materials
   21  *        provided with the distribution.
   22  *
   23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
   26  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
   27  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
   28  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   29  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   30  * SOFTWARE.
   31  */
   32 
   33 #include <linux/radix-tree.h>
   34 #include <linux/file.h>
   35 #include <linux/overflow.h>
   36 
   37 #include <rdma/rdma_user_ioctl.h>
   38 #include <rdma/uverbs_ioctl.h>
   39 #include "rdma_core.h"
   40 #include "uverbs.h"
   41 
   42 struct bundle_alloc_head {
   43         struct bundle_alloc_head *next;
   44         uint8_t data[0];
   45 };
   46 
   47 struct bundle_priv {
   48         /* Must be first */
   49         struct bundle_alloc_head alloc_head;
   50         struct bundle_alloc_head *allocated_mem;
   51         size_t internal_avail;
   52         size_t internal_used;
   53 
   54         struct radix_tree_root *radix;
   55         const struct uverbs_api_ioctl_method *method_elm;
   56         u32 method_key;
   57 
   58         struct ib_uverbs_attr __user *user_attrs;
   59         struct ib_uverbs_attr *uattrs;
   60 
   61         DECLARE_BITMAP(uobj_finalize, UVERBS_API_ATTR_BKEY_LEN);
   62         DECLARE_BITMAP(spec_finalize, UVERBS_API_ATTR_BKEY_LEN);
   63 
   64         /*
   65          * Must be last. bundle ends in a flex array which overlaps
   66          * internal_buffer.
   67          */
   68         struct uverbs_attr_bundle bundle;
   69         u64 internal_buffer[32];
   70 };
   71 
   72 /*
   73  * Each method has an absolute minimum amount of memory it needs to allocate,
   74  * precompute that amount and determine if the onstack memory can be used or
   75  * if allocation is need.
   76  */
   77 void uapi_compute_bundle_size(struct uverbs_api_ioctl_method *method_elm,
   78                               unsigned int num_attrs)
   79 {
   80         struct bundle_priv *pbundle;
   81         size_t bundle_size =
   82                 offsetof(struct bundle_priv, internal_buffer) +
   83                 sizeof(*pbundle->bundle.attrs) * method_elm->key_bitmap_len +
   84                 sizeof(*pbundle->uattrs) * num_attrs;
   85 
   86         method_elm->use_stack = bundle_size <= sizeof(*pbundle);
   87         method_elm->bundle_size =
   88                 ALIGN(bundle_size + 256, sizeof(*pbundle->internal_buffer));
   89 
   90         /* Do not want order-2 allocations for this. */
   91         WARN_ON_ONCE(method_elm->bundle_size > PAGE_SIZE);
   92 }
   93 
   94 /**
   95  * uverbs_alloc() - Quickly allocate memory for use with a bundle
   96  * @bundle: The bundle
   97  * @size: Number of bytes to allocate
   98  * @flags: Allocator flags
   99  *
  100  * The bundle allocator is intended for allocations that are connected with
  101  * processing the system call related to the bundle. The allocated memory is
  102  * always freed once the system call completes, and cannot be freed any other
  103  * way.
  104  *
  105  * This tries to use a small pool of pre-allocated memory for performance.
  106  */
  107 __malloc void *_uverbs_alloc(struct uverbs_attr_bundle *bundle, size_t size,
  108                              gfp_t flags)
  109 {
  110         struct bundle_priv *pbundle =
  111                 container_of(bundle, struct bundle_priv, bundle);
  112         size_t new_used;
  113         void *res;
  114 
  115         new_used = size + pbundle->internal_used;
  116         if (new_used < size)
  117                 return ERR_PTR(-EOVERFLOW);
  118 
  119         if (new_used > pbundle->internal_avail) {
  120                 struct bundle_alloc_head *buf;
  121 
  122                 buf = kvmalloc(struct_size(buf, data, size), flags);
  123                 if (!buf)
  124                         return ERR_PTR(-ENOMEM);
  125                 buf->next = pbundle->allocated_mem;
  126                 pbundle->allocated_mem = buf;
  127                 return buf->data;
  128         }
  129 
  130         res = (u8 *)pbundle->internal_buffer + pbundle->internal_used;
  131         pbundle->internal_used =
  132                 ALIGN(new_used, sizeof(*pbundle->internal_buffer));
  133         if (flags & __GFP_ZERO)
  134                 memset(res, 0, size);
  135         return res;
  136 }
  137 EXPORT_SYMBOL(_uverbs_alloc);
  138 
  139 static bool uverbs_is_attr_cleared(const struct ib_uverbs_attr *uattr,
  140                                    u16 len)
  141 {
  142         if (uattr->len > sizeof(((struct ib_uverbs_attr *)0)->data))
  143                 return ib_is_buffer_cleared(u64_to_user_ptr(uattr->data + len),
  144                                             uattr->len - len);
  145 
  146         return !memchr_inv((const u8 *)&uattr->data + len,
  147                            0, uattr->len - len);
  148 }
  149 
  150 static int uverbs_set_output(const struct uverbs_attr_bundle *bundle,
  151                              const struct uverbs_attr *attr)
  152 {
  153         struct bundle_priv *pbundle =
  154                 container_of(bundle, struct bundle_priv, bundle);
  155         u16 flags;
  156 
  157         flags = pbundle->uattrs[attr->ptr_attr.uattr_idx].flags |
  158                 UVERBS_ATTR_F_VALID_OUTPUT;
  159         if (put_user(flags,
  160                      &pbundle->user_attrs[attr->ptr_attr.uattr_idx].flags))
  161                 return -EFAULT;
  162         return 0;
  163 }
  164 
  165 static int uverbs_process_idrs_array(struct bundle_priv *pbundle,
  166                                      const struct uverbs_api_attr *attr_uapi,
  167                                      struct uverbs_objs_arr_attr *attr,
  168                                      struct ib_uverbs_attr *uattr,
  169                                      u32 attr_bkey)
  170 {
  171         const struct uverbs_attr_spec *spec = &attr_uapi->spec;
  172         size_t array_len;
  173         u32 *idr_vals;
  174         int ret = 0;
  175         size_t i;
  176 
  177         if (uattr->attr_data.reserved)
  178                 return -EINVAL;
  179 
  180         if (uattr->len % sizeof(u32))
  181                 return -EINVAL;
  182 
  183         array_len = uattr->len / sizeof(u32);
  184         if (array_len < spec->u2.objs_arr.min_len ||
  185             array_len > spec->u2.objs_arr.max_len)
  186                 return -EINVAL;
  187 
  188         attr->uobjects =
  189                 uverbs_alloc(&pbundle->bundle,
  190                              array_size(array_len, sizeof(*attr->uobjects)));
  191         if (IS_ERR(attr->uobjects))
  192                 return PTR_ERR(attr->uobjects);
  193 
  194         /*
  195          * Since idr is 4B and *uobjects is >= 4B, we can use attr->uobjects
  196          * to store idrs array and avoid additional memory allocation. The
  197          * idrs array is offset to the end of the uobjects array so we will be
  198          * able to read idr and replace with a pointer.
  199          */
  200         idr_vals = (u32 *)(attr->uobjects + array_len) - array_len;
  201 
  202         if (uattr->len > sizeof(uattr->data)) {
  203                 ret = copy_from_user(idr_vals, u64_to_user_ptr(uattr->data),
  204                                      uattr->len);
  205                 if (ret)
  206                         return -EFAULT;
  207         } else {
  208                 memcpy(idr_vals, &uattr->data, uattr->len);
  209         }
  210 
  211         for (i = 0; i != array_len; i++) {
  212                 attr->uobjects[i] = uverbs_get_uobject_from_file(
  213                         spec->u2.objs_arr.obj_type, spec->u2.objs_arr.access,
  214                         idr_vals[i], &pbundle->bundle);
  215                 if (IS_ERR(attr->uobjects[i])) {
  216                         ret = PTR_ERR(attr->uobjects[i]);
  217                         break;
  218                 }
  219         }
  220 
  221         attr->len = i;
  222         __set_bit(attr_bkey, pbundle->spec_finalize);
  223         return ret;
  224 }
  225 
  226 static void uverbs_free_idrs_array(const struct uverbs_api_attr *attr_uapi,
  227                                    struct uverbs_objs_arr_attr *attr,
  228                                    bool commit,
  229                                    struct uverbs_attr_bundle *attrs)
  230 {
  231         const struct uverbs_attr_spec *spec = &attr_uapi->spec;
  232         size_t i;
  233 
  234         for (i = 0; i != attr->len; i++)
  235                 uverbs_finalize_object(attr->uobjects[i],
  236                                        spec->u2.objs_arr.access, commit, attrs);
  237 }
  238 
  239 static int uverbs_process_attr(struct bundle_priv *pbundle,
  240                                const struct uverbs_api_attr *attr_uapi,
  241                                struct ib_uverbs_attr *uattr, u32 attr_bkey)
  242 {
  243         const struct uverbs_attr_spec *spec = &attr_uapi->spec;
  244         struct uverbs_attr *e = &pbundle->bundle.attrs[attr_bkey];
  245         const struct uverbs_attr_spec *val_spec = spec;
  246         struct uverbs_obj_attr *o_attr;
  247 
  248         switch (spec->type) {
  249         case UVERBS_ATTR_TYPE_ENUM_IN:
  250                 if (uattr->attr_data.enum_data.elem_id >= spec->u.enum_def.num_elems)
  251                         return -EOPNOTSUPP;
  252 
  253                 if (uattr->attr_data.enum_data.reserved)
  254                         return -EINVAL;
  255 
  256                 val_spec = &spec->u2.enum_def.ids[uattr->attr_data.enum_data.elem_id];
  257 
  258                 /* Currently we only support PTR_IN based enums */
  259                 if (val_spec->type != UVERBS_ATTR_TYPE_PTR_IN)
  260                         return -EOPNOTSUPP;
  261 
  262                 e->ptr_attr.enum_id = uattr->attr_data.enum_data.elem_id;
  263         /* fall through */
  264         case UVERBS_ATTR_TYPE_PTR_IN:
  265                 /* Ensure that any data provided by userspace beyond the known
  266                  * struct is zero. Userspace that knows how to use some future
  267                  * longer struct will fail here if used with an old kernel and
  268                  * non-zero content, making ABI compat/discovery simpler.
  269                  */
  270                 if (uattr->len > val_spec->u.ptr.len &&
  271                     val_spec->zero_trailing &&
  272                     !uverbs_is_attr_cleared(uattr, val_spec->u.ptr.len))
  273                         return -EOPNOTSUPP;
  274 
  275         /* fall through */
  276         case UVERBS_ATTR_TYPE_PTR_OUT:
  277                 if (uattr->len < val_spec->u.ptr.min_len ||
  278                     (!val_spec->zero_trailing &&
  279                      uattr->len > val_spec->u.ptr.len))
  280                         return -EINVAL;
  281 
  282                 if (spec->type != UVERBS_ATTR_TYPE_ENUM_IN &&
  283                     uattr->attr_data.reserved)
  284                         return -EINVAL;
  285 
  286                 e->ptr_attr.uattr_idx = uattr - pbundle->uattrs;
  287                 e->ptr_attr.len = uattr->len;
  288 
  289                 if (val_spec->alloc_and_copy && !uverbs_attr_ptr_is_inline(e)) {
  290                         void *p;
  291 
  292                         p = uverbs_alloc(&pbundle->bundle, uattr->len);
  293                         if (IS_ERR(p))
  294                                 return PTR_ERR(p);
  295 
  296                         e->ptr_attr.ptr = p;
  297 
  298                         if (copy_from_user(p, u64_to_user_ptr(uattr->data),
  299                                            uattr->len))
  300                                 return -EFAULT;
  301                 } else {
  302                         e->ptr_attr.data = uattr->data;
  303                 }
  304                 break;
  305 
  306         case UVERBS_ATTR_TYPE_IDR:
  307         case UVERBS_ATTR_TYPE_FD:
  308                 if (uattr->attr_data.reserved)
  309                         return -EINVAL;
  310 
  311                 if (uattr->len != 0)
  312                         return -EINVAL;
  313 
  314                 o_attr = &e->obj_attr;
  315                 o_attr->attr_elm = attr_uapi;
  316 
  317                 /*
  318                  * The type of uattr->data is u64 for UVERBS_ATTR_TYPE_IDR and
  319                  * s64 for UVERBS_ATTR_TYPE_FD. We can cast the u64 to s64
  320                  * here without caring about truncation as we know that the
  321                  * IDR implementation today rejects negative IDs
  322                  */
  323                 o_attr->uobject = uverbs_get_uobject_from_file(
  324                         spec->u.obj.obj_type, spec->u.obj.access,
  325                         uattr->data_s64, &pbundle->bundle);
  326                 if (IS_ERR(o_attr->uobject))
  327                         return PTR_ERR(o_attr->uobject);
  328                 __set_bit(attr_bkey, pbundle->uobj_finalize);
  329 
  330                 if (spec->u.obj.access == UVERBS_ACCESS_NEW) {
  331                         unsigned int uattr_idx = uattr - pbundle->uattrs;
  332                         s64 id = o_attr->uobject->id;
  333 
  334                         /* Copy the allocated id to the user-space */
  335                         if (put_user(id, &pbundle->user_attrs[uattr_idx].data))
  336                                 return -EFAULT;
  337                 }
  338 
  339                 break;
  340 
  341         case UVERBS_ATTR_TYPE_IDRS_ARRAY:
  342                 return uverbs_process_idrs_array(pbundle, attr_uapi,
  343                                                  &e->objs_arr_attr, uattr,
  344                                                  attr_bkey);
  345         default:
  346                 return -EOPNOTSUPP;
  347         }
  348 
  349         return 0;
  350 }
  351 
  352 static void *uapi_get_attr_for_method(struct bundle_priv *pbundle,
  353                                       u32 attr_key)
  354 {
  355         return radix_tree_lookup(pbundle->radix,
  356                                  pbundle->method_key | attr_key);
  357 }
  358 
  359 static int uverbs_set_attr(struct bundle_priv *pbundle,
  360                            struct ib_uverbs_attr *uattr)
  361 {
  362         u32 attr_key = uapi_key_attr(uattr->attr_id);
  363         u32 attr_bkey = uapi_bkey_attr(attr_key);
  364         const struct uverbs_api_attr *attr;
  365         void *slot;
  366         int ret;
  367 
  368         slot = uapi_get_attr_for_method(pbundle, attr_key);
  369         if (!slot) {
  370                 /*
  371                  * Kernel does not support the attribute but user-space says it
  372                  * is mandatory
  373                  */
  374                 if (uattr->flags & UVERBS_ATTR_F_MANDATORY)
  375                         return -EPROTONOSUPPORT;
  376                 return 0;
  377         }
  378         attr = slot;
  379 
  380         /* Reject duplicate attributes from user-space */
  381         if (test_bit(attr_bkey, pbundle->bundle.attr_present))
  382                 return -EINVAL;
  383 
  384         ret = uverbs_process_attr(pbundle, attr, uattr, attr_bkey);
  385         if (ret)
  386                 return ret;
  387 
  388         __set_bit(attr_bkey, pbundle->bundle.attr_present);
  389 
  390         return 0;
  391 }
  392 
  393 static int ib_uverbs_run_method(struct bundle_priv *pbundle,
  394                                 unsigned int num_attrs)
  395 {
  396         int (*handler)(struct uverbs_attr_bundle *attrs);
  397         size_t uattrs_size = array_size(sizeof(*pbundle->uattrs), num_attrs);
  398         unsigned int destroy_bkey = pbundle->method_elm->destroy_bkey;
  399         unsigned int i;
  400         int ret;
  401 
  402         /* See uverbs_disassociate_api() */
  403         handler = srcu_dereference(
  404                 pbundle->method_elm->handler,
  405                 &pbundle->bundle.ufile->device->disassociate_srcu);
  406         if (!handler)
  407                 return -EIO;
  408 
  409         pbundle->uattrs = uverbs_alloc(&pbundle->bundle, uattrs_size);
  410         if (IS_ERR(pbundle->uattrs))
  411                 return PTR_ERR(pbundle->uattrs);
  412         if (copy_from_user(pbundle->uattrs, pbundle->user_attrs, uattrs_size))
  413                 return -EFAULT;
  414 
  415         for (i = 0; i != num_attrs; i++) {
  416                 ret = uverbs_set_attr(pbundle, &pbundle->uattrs[i]);
  417                 if (unlikely(ret))
  418                         return ret;
  419         }
  420 
  421         /* User space did not provide all the mandatory attributes */
  422         if (unlikely(!bitmap_subset(pbundle->method_elm->attr_mandatory,
  423                                     pbundle->bundle.attr_present,
  424                                     pbundle->method_elm->key_bitmap_len)))
  425                 return -EINVAL;
  426 
  427         if (pbundle->method_elm->has_udata)
  428                 uverbs_fill_udata(&pbundle->bundle,
  429                                   &pbundle->bundle.driver_udata,
  430                                   UVERBS_ATTR_UHW_IN, UVERBS_ATTR_UHW_OUT);
  431         else
  432                 pbundle->bundle.driver_udata = (struct ib_udata){};
  433 
  434         if (destroy_bkey != UVERBS_API_ATTR_BKEY_LEN) {
  435                 struct uverbs_obj_attr *destroy_attr =
  436                         &pbundle->bundle.attrs[destroy_bkey].obj_attr;
  437 
  438                 ret = uobj_destroy(destroy_attr->uobject, &pbundle->bundle);
  439                 if (ret)
  440                         return ret;
  441                 __clear_bit(destroy_bkey, pbundle->uobj_finalize);
  442 
  443                 ret = handler(&pbundle->bundle);
  444                 uobj_put_destroy(destroy_attr->uobject);
  445         } else {
  446                 ret = handler(&pbundle->bundle);
  447         }
  448 
  449         /*
  450          * Until the drivers are revised to use the bundle directly we have to
  451          * assume that the driver wrote to its UHW_OUT and flag userspace
  452          * appropriately.
  453          */
  454         if (!ret && pbundle->method_elm->has_udata) {
  455                 const struct uverbs_attr *attr =
  456                         uverbs_attr_get(&pbundle->bundle, UVERBS_ATTR_UHW_OUT);
  457 
  458                 if (!IS_ERR(attr))
  459                         ret = uverbs_set_output(&pbundle->bundle, attr);
  460         }
  461 
  462         /*
  463          * EPROTONOSUPPORT is ONLY to be returned if the ioctl framework can
  464          * not invoke the method because the request is not supported.  No
  465          * other cases should return this code.
  466          */
  467         if (WARN_ON_ONCE(ret == -EPROTONOSUPPORT))
  468                 return -EINVAL;
  469 
  470         return ret;
  471 }
  472 
  473 static void bundle_destroy(struct bundle_priv *pbundle, bool commit)
  474 {
  475         unsigned int key_bitmap_len = pbundle->method_elm->key_bitmap_len;
  476         struct bundle_alloc_head *memblock;
  477         unsigned int i;
  478 
  479         /* fast path for simple uobjects */
  480         i = -1;
  481         while ((i = find_next_bit(pbundle->uobj_finalize, key_bitmap_len,
  482                                   i + 1)) < key_bitmap_len) {
  483                 struct uverbs_attr *attr = &pbundle->bundle.attrs[i];
  484 
  485                 uverbs_finalize_object(
  486                         attr->obj_attr.uobject,
  487                         attr->obj_attr.attr_elm->spec.u.obj.access, commit,
  488                         &pbundle->bundle);
  489         }
  490 
  491         i = -1;
  492         while ((i = find_next_bit(pbundle->spec_finalize, key_bitmap_len,
  493                                   i + 1)) < key_bitmap_len) {
  494                 struct uverbs_attr *attr = &pbundle->bundle.attrs[i];
  495                 const struct uverbs_api_attr *attr_uapi;
  496                 void *slot;
  497 
  498                 slot = uapi_get_attr_for_method(
  499                         pbundle,
  500                         pbundle->method_key | uapi_bkey_to_key_attr(i));
  501                 if (WARN_ON(!slot))
  502                         continue;
  503 
  504                 attr_uapi = slot;
  505 
  506                 if (attr_uapi->spec.type == UVERBS_ATTR_TYPE_IDRS_ARRAY) {
  507                         uverbs_free_idrs_array(attr_uapi, &attr->objs_arr_attr,
  508                                                commit, &pbundle->bundle);
  509                 }
  510         }
  511 
  512         for (memblock = pbundle->allocated_mem; memblock;) {
  513                 struct bundle_alloc_head *tmp = memblock;
  514 
  515                 memblock = memblock->next;
  516                 kvfree(tmp);
  517         }
  518 }
  519 
  520 static int ib_uverbs_cmd_verbs(struct ib_uverbs_file *ufile,
  521                                struct ib_uverbs_ioctl_hdr *hdr,
  522                                struct ib_uverbs_attr __user *user_attrs)
  523 {
  524         const struct uverbs_api_ioctl_method *method_elm;
  525         struct uverbs_api *uapi = ufile->device->uapi;
  526         struct bundle_priv *pbundle;
  527         struct bundle_priv onstack;
  528         void *slot;
  529         int ret;
  530 
  531         if (unlikely(hdr->driver_id != uapi->driver_id))
  532                 return -EINVAL;
  533 
  534         slot = radix_tree_lookup(
  535                 &uapi->radix,
  536                 uapi_key_obj(hdr->object_id) |
  537                 uapi_key_ioctl_method(hdr->method_id));
  538         if (unlikely(!slot))
  539                 return -EPROTONOSUPPORT;
  540         method_elm = slot;
  541 
  542         if (!method_elm->use_stack) {
  543                 pbundle = kmalloc(method_elm->bundle_size, GFP_KERNEL);
  544                 if (!pbundle)
  545                         return -ENOMEM;
  546                 pbundle->internal_avail =
  547                         method_elm->bundle_size -
  548                         offsetof(struct bundle_priv, internal_buffer);
  549                 pbundle->alloc_head.next = NULL;
  550                 pbundle->allocated_mem = &pbundle->alloc_head;
  551         } else {
  552                 pbundle = &onstack;
  553                 pbundle->internal_avail = sizeof(pbundle->internal_buffer);
  554                 pbundle->allocated_mem = NULL;
  555         }
  556 
  557         /* Space for the pbundle->bundle.attrs flex array */
  558         pbundle->method_elm = method_elm;
  559         pbundle->method_key =
  560             uapi_key_obj(hdr->object_id) |
  561             uapi_key_ioctl_method(hdr->method_id);
  562         pbundle->bundle.ufile = ufile;
  563         pbundle->bundle.context = NULL; /* only valid if bundle has uobject */
  564         pbundle->radix = &uapi->radix;
  565         pbundle->user_attrs = user_attrs;
  566 
  567         pbundle->internal_used = ALIGN(pbundle->method_elm->key_bitmap_len *
  568                                                sizeof(*pbundle->bundle.attrs),
  569                                        sizeof(*pbundle->internal_buffer));
  570         memset(pbundle->bundle.attr_present, 0,
  571                sizeof(pbundle->bundle.attr_present));
  572         memset(pbundle->uobj_finalize, 0, sizeof(pbundle->uobj_finalize));
  573         memset(pbundle->spec_finalize, 0, sizeof(pbundle->spec_finalize));
  574 
  575         ret = ib_uverbs_run_method(pbundle, hdr->num_attrs);
  576         bundle_destroy(pbundle, ret == 0);
  577         return ret;
  578 }
  579 
  580 long ib_uverbs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
  581 {
  582         struct ib_uverbs_file *file = filp->private_data;
  583         struct ib_uverbs_ioctl_hdr __user *user_hdr =
  584                 (struct ib_uverbs_ioctl_hdr __user *)arg;
  585         struct ib_uverbs_ioctl_hdr hdr;
  586         int srcu_key;
  587         int err;
  588 
  589         if (unlikely(cmd != RDMA_VERBS_IOCTL))
  590                 return -ENOIOCTLCMD;
  591 
  592         err = copy_from_user(&hdr, user_hdr, sizeof(hdr));
  593         if (err)
  594                 return -EFAULT;
  595 
  596         if (hdr.length > PAGE_SIZE ||
  597             hdr.length != struct_size(&hdr, attrs, hdr.num_attrs))
  598                 return -EINVAL;
  599 
  600         if (hdr.reserved1 || hdr.reserved2)
  601                 return -EPROTONOSUPPORT;
  602 
  603         srcu_key = srcu_read_lock(&file->device->disassociate_srcu);
  604         err = ib_uverbs_cmd_verbs(file, &hdr, user_hdr->attrs);
  605         srcu_read_unlock(&file->device->disassociate_srcu, srcu_key);
  606         return err;
  607 }
  608 
  609 int uverbs_get_flags64(u64 *to, const struct uverbs_attr_bundle *attrs_bundle,
  610                        size_t idx, u64 allowed_bits)
  611 {
  612         const struct uverbs_attr *attr;
  613         u64 flags;
  614 
  615         attr = uverbs_attr_get(attrs_bundle, idx);
  616         /* Missing attribute means 0 flags */
  617         if (IS_ERR(attr)) {
  618                 *to = 0;
  619                 return 0;
  620         }
  621 
  622         /*
  623          * New userspace code should use 8 bytes to pass flags, but we
  624          * transparently support old userspaces that were using 4 bytes as
  625          * well.
  626          */
  627         if (attr->ptr_attr.len == 8)
  628                 flags = attr->ptr_attr.data;
  629         else if (attr->ptr_attr.len == 4)
  630                 flags = *(const u32 *)&attr->ptr_attr.data;
  631         else
  632                 return -EINVAL;
  633 
  634         if (flags & ~allowed_bits)
  635                 return -EINVAL;
  636 
  637         *to = flags;
  638         return 0;
  639 }
  640 EXPORT_SYMBOL(uverbs_get_flags64);
  641 
  642 int uverbs_get_flags32(u32 *to, const struct uverbs_attr_bundle *attrs_bundle,
  643                        size_t idx, u64 allowed_bits)
  644 {
  645         u64 flags;
  646         int ret;
  647 
  648         ret = uverbs_get_flags64(&flags, attrs_bundle, idx, allowed_bits);
  649         if (ret)
  650                 return ret;
  651 
  652         if (flags > U32_MAX)
  653                 return -EINVAL;
  654         *to = flags;
  655 
  656         return 0;
  657 }
  658 EXPORT_SYMBOL(uverbs_get_flags32);
  659 
  660 /*
  661  * Fill a ib_udata struct (core or uhw) using the given attribute IDs.
  662  * This is primarily used to convert the UVERBS_ATTR_UHW() into the
  663  * ib_udata format used by the drivers.
  664  */
  665 void uverbs_fill_udata(struct uverbs_attr_bundle *bundle,
  666                        struct ib_udata *udata, unsigned int attr_in,
  667                        unsigned int attr_out)
  668 {
  669         struct bundle_priv *pbundle =
  670                 container_of(bundle, struct bundle_priv, bundle);
  671         const struct uverbs_attr *in =
  672                 uverbs_attr_get(&pbundle->bundle, attr_in);
  673         const struct uverbs_attr *out =
  674                 uverbs_attr_get(&pbundle->bundle, attr_out);
  675 
  676         if (!IS_ERR(in)) {
  677                 udata->inlen = in->ptr_attr.len;
  678                 if (uverbs_attr_ptr_is_inline(in))
  679                         udata->inbuf = (void *)
  680                                 &pbundle->user_attrs[in->ptr_attr.uattr_idx]
  681                                          .data;
  682                 else
  683                         udata->inbuf = u64_to_user_ptr(in->ptr_attr.data);
  684         } else {
  685                 udata->inbuf = NULL;
  686                 udata->inlen = 0;
  687         }
  688 
  689         if (!IS_ERR(out)) {
  690                 udata->outbuf = u64_to_user_ptr(out->ptr_attr.data);
  691                 udata->outlen = out->ptr_attr.len;
  692         } else {
  693                 udata->outbuf = NULL;
  694                 udata->outlen = 0;
  695         }
  696 }
  697 
  698 int uverbs_copy_to(const struct uverbs_attr_bundle *bundle, size_t idx,
  699                    const void *from, size_t size)
  700 {
  701         const struct uverbs_attr *attr = uverbs_attr_get(bundle, idx);
  702         size_t min_size;
  703 
  704         if (IS_ERR(attr))
  705                 return PTR_ERR(attr);
  706 
  707         min_size = min_t(size_t, attr->ptr_attr.len, size);
  708         if (copy_to_user(u64_to_user_ptr(attr->ptr_attr.data), from, min_size))
  709                 return -EFAULT;
  710 
  711         return uverbs_set_output(bundle, attr);
  712 }
  713 EXPORT_SYMBOL(uverbs_copy_to);
  714 
  715 
  716 /*
  717  * This is only used if the caller has directly used copy_to_use to write the
  718  * data.  It signals to user space that the buffer is filled in.
  719  */
  720 int uverbs_output_written(const struct uverbs_attr_bundle *bundle, size_t idx)
  721 {
  722         const struct uverbs_attr *attr = uverbs_attr_get(bundle, idx);
  723 
  724         if (IS_ERR(attr))
  725                 return PTR_ERR(attr);
  726 
  727         return uverbs_set_output(bundle, attr);
  728 }
  729 
  730 int _uverbs_get_const(s64 *to, const struct uverbs_attr_bundle *attrs_bundle,
  731                       size_t idx, s64 lower_bound, u64 upper_bound,
  732                       s64  *def_val)
  733 {
  734         const struct uverbs_attr *attr;
  735 
  736         attr = uverbs_attr_get(attrs_bundle, idx);
  737         if (IS_ERR(attr)) {
  738                 if ((PTR_ERR(attr) != -ENOENT) || !def_val)
  739                         return PTR_ERR(attr);
  740 
  741                 *to = *def_val;
  742         } else {
  743                 *to = attr->ptr_attr.data;
  744         }
  745 
  746         if (*to < lower_bound || (*to > 0 && (u64)*to > upper_bound))
  747                 return -EINVAL;
  748 
  749         return 0;
  750 }
  751 EXPORT_SYMBOL(_uverbs_get_const);
  752 
  753 int uverbs_copy_to_struct_or_zero(const struct uverbs_attr_bundle *bundle,
  754                                   size_t idx, const void *from, size_t size)
  755 {
  756         const struct uverbs_attr *attr = uverbs_attr_get(bundle, idx);
  757 
  758         if (IS_ERR(attr))
  759                 return PTR_ERR(attr);
  760 
  761         if (size < attr->ptr_attr.len) {
  762                 if (clear_user(u64_to_user_ptr(attr->ptr_attr.data + size),
  763                                attr->ptr_attr.len - size))
  764                         return -EFAULT;
  765         }
  766         return uverbs_copy_to(bundle, idx, from, size);
  767 }

Cache object: dbd230acaa0ab8564667da289f672578


[ 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.