]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
RDMA/core: Move many of the little EXPORTs from uverbs_ioctl into ib_core_uverbs
authorJason Gunthorpe <jgg@nvidia.com>
Tue, 26 May 2026 01:22:38 +0000 (22:22 -0300)
committerJason Gunthorpe <jgg@nvidia.com>
Tue, 26 May 2026 13:07:26 +0000 (10:07 -0300)
Not as many drivers need these functions but it does free efa from the
ib_uverbs.ko dependency and follows the general design better.

Link: https://patch.msgid.link/r/2-v3-43aba1969751+1988-ib_uverbs_support_ko_jgg@nvidia.com
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
drivers/infiniband/core/ib_core_uverbs.c
drivers/infiniband/core/uverbs.h
drivers/infiniband/core/uverbs_ioctl.c
drivers/infiniband/core/uverbs_main.c
drivers/infiniband/core/uverbs_std_types.c

index 0acb0d4967cb6ba81c265ec57c6a4fe4ca47cc89..b4fc693a3bd8b7abf2e500b011e74349dd701298 100644 (file)
@@ -501,3 +501,221 @@ err_fault:
        return -EFAULT;
 }
 EXPORT_SYMBOL(_ib_respond_udata);
+
+/*
+ * Must be called with the ufile->device->disassociate_srcu held, and the lock
+ * must be held until use of the ucontext is finished.
+ */
+struct ib_ucontext *ib_uverbs_get_ucontext_file(struct ib_uverbs_file *ufile)
+{
+       /*
+        * We do not hold the hw_destroy_rwsem lock for this flow, instead
+        * srcu is used. It does not matter if someone races this with
+        * get_context, we get NULL or valid ucontext.
+        */
+       struct ib_ucontext *ucontext = smp_load_acquire(&ufile->ucontext);
+
+       if (!srcu_dereference(ufile->device->ib_dev,
+                             &ufile->device->disassociate_srcu))
+               return ERR_PTR(-EIO);
+
+       if (!ucontext)
+               return ERR_PTR(-EINVAL);
+
+       return ucontext;
+}
+EXPORT_SYMBOL(ib_uverbs_get_ucontext_file);
+
+int uverbs_destroy_def_handler(struct uverbs_attr_bundle *attrs)
+{
+       return 0;
+}
+EXPORT_SYMBOL(uverbs_destroy_def_handler);
+
+/**
+ * _uverbs_alloc() - Quickly allocate memory for use with a bundle
+ * @bundle: The bundle
+ * @size: Number of bytes to allocate
+ * @flags: Allocator flags
+ *
+ * The bundle allocator is intended for allocations that are connected with
+ * processing the system call related to the bundle. The allocated memory is
+ * always freed once the system call completes, and cannot be freed any other
+ * way.
+ *
+ * This tries to use a small pool of pre-allocated memory for performance.
+ */
+__malloc void *_uverbs_alloc(struct uverbs_attr_bundle *bundle, size_t size,
+                            gfp_t flags)
+{
+       struct bundle_priv *pbundle =
+               container_of(&bundle->hdr, struct bundle_priv, bundle);
+       size_t new_used;
+       void *res;
+
+       if (check_add_overflow(size, pbundle->internal_used, &new_used))
+               return ERR_PTR(-EOVERFLOW);
+
+       if (new_used > pbundle->internal_avail) {
+               struct bundle_alloc_head *buf;
+
+               buf = kvmalloc_flex(*buf, data, size, flags);
+               if (!buf)
+                       return ERR_PTR(-ENOMEM);
+               buf->next = pbundle->allocated_mem;
+               pbundle->allocated_mem = buf;
+               return buf->data;
+       }
+
+       res = (void *)pbundle->internal_buffer + pbundle->internal_used;
+       pbundle->internal_used =
+               ALIGN(new_used, sizeof(*pbundle->internal_buffer));
+       if (want_init_on_alloc(flags))
+               memset(res, 0, size);
+       return res;
+}
+EXPORT_SYMBOL(_uverbs_alloc);
+
+int uverbs_copy_to(const struct uverbs_attr_bundle *bundle, size_t idx,
+                  const void *from, size_t size)
+{
+       const struct uverbs_attr *attr = uverbs_attr_get(bundle, idx);
+       size_t min_size;
+
+       if (IS_ERR(attr))
+               return PTR_ERR(attr);
+
+       min_size = min_t(size_t, attr->ptr_attr.len, size);
+       if (copy_to_user(u64_to_user_ptr(attr->ptr_attr.data), from, min_size))
+               return -EFAULT;
+
+       return uverbs_set_output(bundle, attr);
+}
+EXPORT_SYMBOL(uverbs_copy_to);
+
+int uverbs_copy_to_struct_or_zero(const struct uverbs_attr_bundle *bundle,
+                                 size_t idx, const void *from, size_t size)
+{
+       const struct uverbs_attr *attr = uverbs_attr_get(bundle, idx);
+
+       if (IS_ERR(attr))
+               return PTR_ERR(attr);
+
+       if (size < attr->ptr_attr.len) {
+               if (clear_user(u64_to_user_ptr(attr->ptr_attr.data) + size,
+                              attr->ptr_attr.len - size))
+                       return -EFAULT;
+       }
+       return uverbs_copy_to(bundle, idx, from, size);
+}
+EXPORT_SYMBOL(uverbs_copy_to_struct_or_zero);
+
+int _uverbs_get_const_unsigned(u64 *to,
+                              const struct uverbs_attr_bundle *attrs_bundle,
+                              size_t idx, u64 upper_bound, u64 *def_val)
+{
+       const struct uverbs_attr *attr;
+
+       attr = uverbs_attr_get(attrs_bundle, idx);
+       if (IS_ERR(attr)) {
+               if ((PTR_ERR(attr) != -ENOENT) || !def_val)
+                       return PTR_ERR(attr);
+
+               *to = *def_val;
+       } else {
+               *to = attr->ptr_attr.data;
+       }
+
+       if (*to > upper_bound)
+               return -EINVAL;
+
+       return 0;
+}
+EXPORT_SYMBOL(_uverbs_get_const_unsigned);
+
+int _uverbs_get_const_signed(s64 *to,
+                            const struct uverbs_attr_bundle *attrs_bundle,
+                            size_t idx, s64 lower_bound, u64 upper_bound,
+                            s64  *def_val)
+{
+       const struct uverbs_attr *attr;
+
+       attr = uverbs_attr_get(attrs_bundle, idx);
+       if (IS_ERR(attr)) {
+               if ((PTR_ERR(attr) != -ENOENT) || !def_val)
+                       return PTR_ERR(attr);
+
+               *to = *def_val;
+       } else {
+               *to = attr->ptr_attr.data;
+       }
+
+       if (*to < lower_bound || (*to > 0 && (u64)*to > upper_bound))
+               return -EINVAL;
+
+       return 0;
+}
+EXPORT_SYMBOL(_uverbs_get_const_signed);
+
+int uverbs_get_flags64(u64 *to, const struct uverbs_attr_bundle *attrs_bundle,
+                      size_t idx, u64 allowed_bits)
+{
+       const struct uverbs_attr *attr;
+       u64 flags;
+
+       attr = uverbs_attr_get(attrs_bundle, idx);
+       /* Missing attribute means 0 flags */
+       if (IS_ERR(attr)) {
+               *to = 0;
+               return 0;
+       }
+
+       /*
+        * New userspace code should use 8 bytes to pass flags, but we
+        * transparently support old userspaces that were using 4 bytes as
+        * well.
+        */
+       if (attr->ptr_attr.len == 8)
+               flags = attr->ptr_attr.data;
+       else if (attr->ptr_attr.len == 4)
+               flags = *(u32 *)&attr->ptr_attr.data;
+       else
+               return -EINVAL;
+
+       if (flags & ~allowed_bits)
+               return -EINVAL;
+
+       *to = flags;
+       return 0;
+}
+EXPORT_SYMBOL(uverbs_get_flags64);
+
+int uverbs_get_flags32(u32 *to, const struct uverbs_attr_bundle *attrs_bundle,
+                      size_t idx, u64 allowed_bits)
+{
+       u64 flags;
+       int ret;
+
+       ret = uverbs_get_flags64(&flags, attrs_bundle, idx, allowed_bits);
+       if (ret)
+               return ret;
+
+       if (flags > U32_MAX)
+               return -EINVAL;
+       *to = flags;
+
+       return 0;
+}
+EXPORT_SYMBOL(uverbs_get_flags32);
+
+/* Once called an abort will call through to the type's destroy_hw() */
+void uverbs_finalize_uobj_create(const struct uverbs_attr_bundle *bundle,
+                                u16 idx)
+{
+       struct bundle_priv *pbundle =
+               container_of(&bundle->hdr, struct bundle_priv, bundle);
+
+       __set_bit(uapi_bkey_attr(uapi_key_attr(idx)),
+                 pbundle->uobj_hw_obj_valid);
+}
+EXPORT_SYMBOL(uverbs_finalize_uobj_create);
index f2e192b51e609cb59b166914088ecea45ead2120..1563169c65009eec540848e0f54f3f447a3a0950 100644 (file)
@@ -263,6 +263,21 @@ struct bundle_priv {
        u64 internal_buffer[32];
 };
 
+static inline int uverbs_set_output(const struct uverbs_attr_bundle *bundle,
+                                   const struct uverbs_attr *attr)
+{
+       struct bundle_priv *pbundle =
+               container_of(&bundle->hdr, struct bundle_priv, bundle);
+       u16 flags;
+
+       flags = pbundle->uattrs[attr->ptr_attr.uattr_idx].flags |
+               UVERBS_ATTR_F_VALID_OUTPUT;
+       if (put_user(flags,
+                    &pbundle->user_attrs[attr->ptr_attr.uattr_idx].flags))
+               return -EFAULT;
+       return 0;
+}
+
 long ib_uverbs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
 
 struct ib_uverbs_flow_spec {
index 2552a7efe2fbe2145ab227966ac6ec7623c54354..6a78288e27a1c7eaddd6a5180e637721548187e3 100644 (file)
@@ -58,50 +58,6 @@ void uapi_compute_bundle_size(struct uverbs_api_ioctl_method *method_elm,
        WARN_ON_ONCE(method_elm->bundle_size > PAGE_SIZE);
 }
 
-/**
- * _uverbs_alloc() - Quickly allocate memory for use with a bundle
- * @bundle: The bundle
- * @size: Number of bytes to allocate
- * @flags: Allocator flags
- *
- * The bundle allocator is intended for allocations that are connected with
- * processing the system call related to the bundle. The allocated memory is
- * always freed once the system call completes, and cannot be freed any other
- * way.
- *
- * This tries to use a small pool of pre-allocated memory for performance.
- */
-__malloc void *_uverbs_alloc(struct uverbs_attr_bundle *bundle, size_t size,
-                            gfp_t flags)
-{
-       struct bundle_priv *pbundle =
-               container_of(&bundle->hdr, struct bundle_priv, bundle);
-       size_t new_used;
-       void *res;
-
-       if (check_add_overflow(size, pbundle->internal_used, &new_used))
-               return ERR_PTR(-EOVERFLOW);
-
-       if (new_used > pbundle->internal_avail) {
-               struct bundle_alloc_head *buf;
-
-               buf = kvmalloc_flex(*buf, data, size, flags);
-               if (!buf)
-                       return ERR_PTR(-ENOMEM);
-               buf->next = pbundle->allocated_mem;
-               pbundle->allocated_mem = buf;
-               return buf->data;
-       }
-
-       res = (void *)pbundle->internal_buffer + pbundle->internal_used;
-       pbundle->internal_used =
-               ALIGN(new_used, sizeof(*pbundle->internal_buffer));
-       if (want_init_on_alloc(flags))
-               memset(res, 0, size);
-       return res;
-}
-EXPORT_SYMBOL(_uverbs_alloc);
-
 static bool uverbs_is_attr_cleared(const struct ib_uverbs_attr *uattr,
                                   u16 len)
 {
@@ -113,21 +69,6 @@ static bool uverbs_is_attr_cleared(const struct ib_uverbs_attr *uattr,
                           0, uattr->len - len);
 }
 
-static int uverbs_set_output(const struct uverbs_attr_bundle *bundle,
-                            const struct uverbs_attr *attr)
-{
-       struct bundle_priv *pbundle =
-               container_of(&bundle->hdr, struct bundle_priv, bundle);
-       u16 flags;
-
-       flags = pbundle->uattrs[attr->ptr_attr.uattr_idx].flags |
-               UVERBS_ATTR_F_VALID_OUTPUT;
-       if (put_user(flags,
-                    &pbundle->user_attrs[attr->ptr_attr.uattr_idx].flags))
-               return -EFAULT;
-       return 0;
-}
-
 static int uverbs_process_idrs_array(struct bundle_priv *pbundle,
                                     const struct uverbs_api_attr *attr_uapi,
                                     struct uverbs_objs_arr_attr *attr,
@@ -616,57 +557,6 @@ long ib_uverbs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
        return err;
 }
 
-int uverbs_get_flags64(u64 *to, const struct uverbs_attr_bundle *attrs_bundle,
-                      size_t idx, u64 allowed_bits)
-{
-       const struct uverbs_attr *attr;
-       u64 flags;
-
-       attr = uverbs_attr_get(attrs_bundle, idx);
-       /* Missing attribute means 0 flags */
-       if (IS_ERR(attr)) {
-               *to = 0;
-               return 0;
-       }
-
-       /*
-        * New userspace code should use 8 bytes to pass flags, but we
-        * transparently support old userspaces that were using 4 bytes as
-        * well.
-        */
-       if (attr->ptr_attr.len == 8)
-               flags = attr->ptr_attr.data;
-       else if (attr->ptr_attr.len == 4)
-               flags = *(u32 *)&attr->ptr_attr.data;
-       else
-               return -EINVAL;
-
-       if (flags & ~allowed_bits)
-               return -EINVAL;
-
-       *to = flags;
-       return 0;
-}
-EXPORT_SYMBOL(uverbs_get_flags64);
-
-int uverbs_get_flags32(u32 *to, const struct uverbs_attr_bundle *attrs_bundle,
-                      size_t idx, u64 allowed_bits)
-{
-       u64 flags;
-       int ret;
-
-       ret = uverbs_get_flags64(&flags, attrs_bundle, idx, allowed_bits);
-       if (ret)
-               return ret;
-
-       if (flags > U32_MAX)
-               return -EINVAL;
-       *to = flags;
-
-       return 0;
-}
-EXPORT_SYMBOL(uverbs_get_flags32);
-
 /*
  * Fill a ib_udata struct (core or uhw) using the given attribute IDs.
  * This is primarily used to convert the UVERBS_ATTR_UHW() into the
@@ -707,24 +597,6 @@ void uverbs_fill_udata(struct uverbs_attr_bundle *bundle,
        }
 }
 
-int uverbs_copy_to(const struct uverbs_attr_bundle *bundle, size_t idx,
-                  const void *from, size_t size)
-{
-       const struct uverbs_attr *attr = uverbs_attr_get(bundle, idx);
-       size_t min_size;
-
-       if (IS_ERR(attr))
-               return PTR_ERR(attr);
-
-       min_size = min_t(size_t, attr->ptr_attr.len, size);
-       if (copy_to_user(u64_to_user_ptr(attr->ptr_attr.data), from, min_size))
-               return -EFAULT;
-
-       return uverbs_set_output(bundle, attr);
-}
-EXPORT_SYMBOL(uverbs_copy_to);
-
-
 /*
  * This is only used if the caller has directly used copy_to_use to write the
  * data.  It signals to user space that the buffer is filled in.
@@ -738,79 +610,3 @@ int uverbs_output_written(const struct uverbs_attr_bundle *bundle, size_t idx)
 
        return uverbs_set_output(bundle, attr);
 }
-
-int _uverbs_get_const_signed(s64 *to,
-                            const struct uverbs_attr_bundle *attrs_bundle,
-                            size_t idx, s64 lower_bound, u64 upper_bound,
-                            s64  *def_val)
-{
-       const struct uverbs_attr *attr;
-
-       attr = uverbs_attr_get(attrs_bundle, idx);
-       if (IS_ERR(attr)) {
-               if ((PTR_ERR(attr) != -ENOENT) || !def_val)
-                       return PTR_ERR(attr);
-
-               *to = *def_val;
-       } else {
-               *to = attr->ptr_attr.data;
-       }
-
-       if (*to < lower_bound || (*to > 0 && (u64)*to > upper_bound))
-               return -EINVAL;
-
-       return 0;
-}
-EXPORT_SYMBOL(_uverbs_get_const_signed);
-
-int _uverbs_get_const_unsigned(u64 *to,
-                              const struct uverbs_attr_bundle *attrs_bundle,
-                              size_t idx, u64 upper_bound, u64 *def_val)
-{
-       const struct uverbs_attr *attr;
-
-       attr = uverbs_attr_get(attrs_bundle, idx);
-       if (IS_ERR(attr)) {
-               if ((PTR_ERR(attr) != -ENOENT) || !def_val)
-                       return PTR_ERR(attr);
-
-               *to = *def_val;
-       } else {
-               *to = attr->ptr_attr.data;
-       }
-
-       if (*to > upper_bound)
-               return -EINVAL;
-
-       return 0;
-}
-EXPORT_SYMBOL(_uverbs_get_const_unsigned);
-
-int uverbs_copy_to_struct_or_zero(const struct uverbs_attr_bundle *bundle,
-                                 size_t idx, const void *from, size_t size)
-{
-       const struct uverbs_attr *attr = uverbs_attr_get(bundle, idx);
-
-       if (IS_ERR(attr))
-               return PTR_ERR(attr);
-
-       if (size < attr->ptr_attr.len) {
-               if (clear_user(u64_to_user_ptr(attr->ptr_attr.data) + size,
-                              attr->ptr_attr.len - size))
-                       return -EFAULT;
-       }
-       return uverbs_copy_to(bundle, idx, from, size);
-}
-EXPORT_SYMBOL(uverbs_copy_to_struct_or_zero);
-
-/* Once called an abort will call through to the type's destroy_hw() */
-void uverbs_finalize_uobj_create(const struct uverbs_attr_bundle *bundle,
-                                u16 idx)
-{
-       struct bundle_priv *pbundle =
-               container_of(&bundle->hdr, struct bundle_priv, bundle);
-
-       __set_bit(uapi_bkey_attr(uapi_key_attr(idx)),
-                 pbundle->uobj_hw_obj_valid);
-}
-EXPORT_SYMBOL(uverbs_finalize_uobj_create);
index f5837da47299c1294c0bfc94ddbf0768a2bc75cb..15d8387718c050dee9366fe02b4ff298cef777bc 100644 (file)
@@ -91,30 +91,6 @@ static const struct class uverbs_class = {
        .devnode = uverbs_devnode,
 };
 
-/*
- * Must be called with the ufile->device->disassociate_srcu held, and the lock
- * must be held until use of the ucontext is finished.
- */
-struct ib_ucontext *ib_uverbs_get_ucontext_file(struct ib_uverbs_file *ufile)
-{
-       /*
-        * We do not hold the hw_destroy_rwsem lock for this flow, instead
-        * srcu is used. It does not matter if someone races this with
-        * get_context, we get NULL or valid ucontext.
-        */
-       struct ib_ucontext *ucontext = smp_load_acquire(&ufile->ucontext);
-
-       if (!srcu_dereference(ufile->device->ib_dev,
-                             &ufile->device->disassociate_srcu))
-               return ERR_PTR(-EIO);
-
-       if (!ucontext)
-               return ERR_PTR(-EINVAL);
-
-       return ucontext;
-}
-EXPORT_SYMBOL(ib_uverbs_get_ucontext_file);
-
 int uverbs_dealloc_mw(struct ib_mw *mw)
 {
        struct ib_pd *pd = mw->pd;
index 13776a66e2e43a54e6324750dfa0521c3fa7b883..e160786e1df164bfc4a781bb824925d38178b1a6 100644 (file)
@@ -165,12 +165,6 @@ uverbs_completion_event_file_destroy_uobj(struct ib_uobject *uobj,
        ib_uverbs_free_event_queue(&file->ev_queue);
 }
 
-int uverbs_destroy_def_handler(struct uverbs_attr_bundle *attrs)
-{
-       return 0;
-}
-EXPORT_SYMBOL(uverbs_destroy_def_handler);
-
 DECLARE_UVERBS_NAMED_OBJECT(
        UVERBS_OBJECT_COMP_CHANNEL,
        UVERBS_TYPE_ALLOC_FD(sizeof(struct ib_uverbs_completion_event_file),