* [PATCH 1/6] RDMA/core: Move the _ib_copy_validate_udata* functions to ib_core_uverbs
2026-05-13 17:33 [PATCH 0/6] Remove driver dependencies on ib_uverbs.ko Jason Gunthorpe
@ 2026-05-13 17:33 ` Jason Gunthorpe
2026-05-15 23:12 ` Jason Gunthorpe
2026-05-13 17:33 ` [PATCH 2/6] RDMA/core: Move many of the little EXPORTs from uverbs_ioctl into ib_core_uverbs Jason Gunthorpe
` (4 subsequent siblings)
5 siblings, 1 reply; 9+ messages in thread
From: Jason Gunthorpe @ 2026-05-13 17:33 UTC (permalink / raw)
To: Leon Romanovsky, linux-rdma; +Cc: Jiri Pirko, patches, Sriharsha Basavapatna
It was incorrect to place them in uverbs_ioctl because that makes every
driver depends on ib_uverbs.ko, which is undesired. ib_core_uverbs.c is
for functions used by alot of drivers that are linked into ib_core
instead.
Fixes: 1de9287ece44 ("RDMA: Add ib_copy_validate_udata_in()")
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
drivers/infiniband/core/ib_core_uverbs.c | 87 ++++++++++++++++
drivers/infiniband/core/uverbs.h | 35 +++++++
drivers/infiniband/core/uverbs_ioctl.c | 122 -----------------------
3 files changed, 122 insertions(+), 122 deletions(-)
diff --git a/drivers/infiniband/core/ib_core_uverbs.c b/drivers/infiniband/core/ib_core_uverbs.c
index 1f7a5c119cc9c1..c94d03857318eb 100644
--- a/drivers/infiniband/core/ib_core_uverbs.c
+++ b/drivers/infiniband/core/ib_core_uverbs.c
@@ -9,6 +9,7 @@
#include <linux/dma-resv.h>
#include "uverbs.h"
#include "core_priv.h"
+#include "rdma_core.h"
MODULE_IMPORT_NS("DMA_BUF");
@@ -416,3 +417,89 @@ struct ib_device *rdma_udata_to_dev(struct ib_udata *udata)
}
EXPORT_SYMBOL(rdma_udata_to_dev);
+uverbs_api_ioctl_handler_fn uverbs_get_handler_fn(struct ib_udata *udata)
+{
+ struct uverbs_attr_bundle *bundle =
+ rdma_udata_to_uverbs_attr_bundle(udata);
+ struct bundle_priv *pbundle =
+ container_of(&bundle->hdr, struct bundle_priv, bundle);
+
+ lockdep_assert_held(&bundle->ufile->device->disassociate_srcu);
+
+ return srcu_dereference(pbundle->method_elm->handler,
+ &bundle->ufile->device->disassociate_srcu);
+}
+
+int _ib_copy_validate_udata_in(struct ib_udata *udata, void *req,
+ size_t kernel_size, size_t minimum_size)
+{
+ int err;
+
+ if (udata->inlen < minimum_size) {
+ ibdev_dbg(
+ rdma_udata_to_dev(udata),
+ "System call driver input udata too small (%zu < %zu) for ioctl %ps called by %pSR\n",
+ udata->inlen, minimum_size,
+ uverbs_get_handler_fn(udata),
+ __builtin_return_address(0));
+ return -EINVAL;
+ }
+
+ err = copy_struct_from_user(req, kernel_size, udata->inbuf,
+ udata->inlen);
+ if (err) {
+ if (err == -E2BIG) {
+ ibdev_dbg(
+ rdma_udata_to_dev(udata),
+ "System call driver input udata not zero from %zu -> %zu for ioctl %ps called by %pSR\n",
+ minimum_size, udata->inlen,
+ uverbs_get_handler_fn(udata),
+ __builtin_return_address(0));
+ return -EOPNOTSUPP;
+ }
+ ibdev_dbg(
+ rdma_udata_to_dev(udata),
+ "System call driver input udata EFAULT for ioctl %ps called by %pSR\n",
+ uverbs_get_handler_fn(udata),
+ __builtin_return_address(0));
+ return err;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(_ib_copy_validate_udata_in);
+
+int _ib_copy_validate_udata_cm_fail(struct ib_udata *udata, u64 req_cm,
+ u64 valid_cm)
+{
+ ibdev_dbg(
+ rdma_udata_to_dev(udata),
+ "System call driver input udata has unsupported comp_mask %llx & ~%llx = %llx for ioctl %ps called by %pSR\n",
+ req_cm, valid_cm, req_cm & ~valid_cm,
+ uverbs_get_handler_fn(udata), __builtin_return_address(0));
+ return -EOPNOTSUPP;
+}
+EXPORT_SYMBOL(_ib_copy_validate_udata_cm_fail);
+
+int _ib_respond_udata(struct ib_udata *udata, const void *src, size_t len)
+{
+ size_t copy_len;
+
+ /* 0 length copy_len is a NOP for copy_to_user() and doesn't fail. */
+ copy_len = min(len, udata->outlen);
+ if (copy_to_user(udata->outbuf, src, copy_len))
+ goto err_fault;
+ if (copy_len < udata->outlen) {
+ if (clear_user(udata->outbuf + copy_len,
+ udata->outlen - copy_len))
+ goto err_fault;
+ }
+ return 0;
+err_fault:
+ ibdev_dbg(
+ rdma_udata_to_dev(udata),
+ "System call driver out udata has EFAULT (%zu into %zu) for ioctl %ps called by %pSR\n",
+ len, udata->outlen, uverbs_get_handler_fn(udata),
+ __builtin_return_address(0));
+ return -EFAULT;
+}
+EXPORT_SYMBOL(_ib_respond_udata);
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h
index 6d4295277e0e5f..a74a2dff1301ed 100644
--- a/drivers/infiniband/core/uverbs.h
+++ b/drivers/infiniband/core/uverbs.h
@@ -229,6 +229,41 @@ int uverbs_dealloc_mw(struct ib_mw *mw);
void ib_uverbs_detach_umcast(struct ib_qp *qp,
struct ib_uqp_object *uobj);
+struct bundle_alloc_head {
+ struct_group_tagged(bundle_alloc_head_hdr, hdr,
+ struct bundle_alloc_head *next;
+ );
+ u8 data[];
+};
+
+struct bundle_priv {
+ /* Must be first */
+ struct bundle_alloc_head_hdr alloc_head;
+ struct bundle_alloc_head *allocated_mem;
+ size_t internal_avail;
+ size_t internal_used;
+
+ struct radix_tree_root *radix;
+ const struct uverbs_api_ioctl_method *method_elm;
+ void __rcu **radix_slots;
+ unsigned long radix_slots_len;
+ u32 method_key;
+
+ struct ib_uverbs_attr __user *user_attrs;
+ struct ib_uverbs_attr *uattrs;
+
+ DECLARE_BITMAP(uobj_finalize, UVERBS_API_ATTR_BKEY_LEN);
+ DECLARE_BITMAP(spec_finalize, UVERBS_API_ATTR_BKEY_LEN);
+ DECLARE_BITMAP(uobj_hw_obj_valid, UVERBS_API_ATTR_BKEY_LEN);
+
+ /*
+ * Must be last. bundle ends in a flex array which overlaps
+ * internal_buffer.
+ */
+ struct uverbs_attr_bundle_hdr bundle;
+ u64 internal_buffer[32];
+};
+
long ib_uverbs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
struct ib_uverbs_flow_spec {
diff --git a/drivers/infiniband/core/uverbs_ioctl.c b/drivers/infiniband/core/uverbs_ioctl.c
index b61af625e679b2..33feb88d652b6a 100644
--- a/drivers/infiniband/core/uverbs_ioctl.c
+++ b/drivers/infiniband/core/uverbs_ioctl.c
@@ -35,54 +35,6 @@
#include "rdma_core.h"
#include "uverbs.h"
-struct bundle_alloc_head {
- struct_group_tagged(bundle_alloc_head_hdr, hdr,
- struct bundle_alloc_head *next;
- );
- u8 data[];
-};
-
-struct bundle_priv {
- /* Must be first */
- struct bundle_alloc_head_hdr alloc_head;
- struct bundle_alloc_head *allocated_mem;
- size_t internal_avail;
- size_t internal_used;
-
- struct radix_tree_root *radix;
- const struct uverbs_api_ioctl_method *method_elm;
- void __rcu **radix_slots;
- unsigned long radix_slots_len;
- u32 method_key;
-
- struct ib_uverbs_attr __user *user_attrs;
- struct ib_uverbs_attr *uattrs;
-
- DECLARE_BITMAP(uobj_finalize, UVERBS_API_ATTR_BKEY_LEN);
- DECLARE_BITMAP(spec_finalize, UVERBS_API_ATTR_BKEY_LEN);
- DECLARE_BITMAP(uobj_hw_obj_valid, UVERBS_API_ATTR_BKEY_LEN);
-
- /*
- * Must be last. bundle ends in a flex array which overlaps
- * internal_buffer.
- */
- struct uverbs_attr_bundle_hdr bundle;
- u64 internal_buffer[32];
-};
-
-uverbs_api_ioctl_handler_fn uverbs_get_handler_fn(struct ib_udata *udata)
-{
- struct uverbs_attr_bundle *bundle =
- rdma_udata_to_uverbs_attr_bundle(udata);
- struct bundle_priv *pbundle =
- container_of(&bundle->hdr, struct bundle_priv, bundle);
-
- lockdep_assert_held(&bundle->ufile->device->disassociate_srcu);
-
- return srcu_dereference(pbundle->method_elm->handler,
- &bundle->ufile->device->disassociate_srcu);
-}
-
/*
* Each method has an absolute minimum amount of memory it needs to allocate,
* precompute that amount and determine if the onstack memory can be used or
@@ -860,77 +812,3 @@ void uverbs_finalize_uobj_create(const struct uverbs_attr_bundle *bundle,
pbundle->uobj_hw_obj_valid);
}
EXPORT_SYMBOL(uverbs_finalize_uobj_create);
-
-int _ib_copy_validate_udata_in(struct ib_udata *udata, void *req,
- size_t kernel_size, size_t minimum_size)
-{
- int err;
-
- if (udata->inlen < minimum_size) {
- ibdev_dbg(
- rdma_udata_to_dev(udata),
- "System call driver input udata too small (%zu < %zu) for ioctl %ps called by %pSR\n",
- udata->inlen, minimum_size,
- uverbs_get_handler_fn(udata),
- __builtin_return_address(0));
- return -EINVAL;
- }
-
- err = copy_struct_from_user(req, kernel_size, udata->inbuf,
- udata->inlen);
- if (err) {
- if (err == -E2BIG) {
- ibdev_dbg(
- rdma_udata_to_dev(udata),
- "System call driver input udata not zero from %zu -> %zu for ioctl %ps called by %pSR\n",
- minimum_size, udata->inlen,
- uverbs_get_handler_fn(udata),
- __builtin_return_address(0));
- return -EOPNOTSUPP;
- }
- ibdev_dbg(
- rdma_udata_to_dev(udata),
- "System call driver input udata EFAULT for ioctl %ps called by %pSR\n",
- uverbs_get_handler_fn(udata),
- __builtin_return_address(0));
- return err;
- }
- return 0;
-}
-EXPORT_SYMBOL(_ib_copy_validate_udata_in);
-
-int _ib_copy_validate_udata_cm_fail(struct ib_udata *udata, u64 req_cm,
- u64 valid_cm)
-{
- ibdev_dbg(
- rdma_udata_to_dev(udata),
- "System call driver input udata has unsupported comp_mask %llx & ~%llx = %llx for ioctl %ps called by %pSR\n",
- req_cm, valid_cm, req_cm & ~valid_cm,
- uverbs_get_handler_fn(udata), __builtin_return_address(0));
- return -EOPNOTSUPP;
-}
-EXPORT_SYMBOL(_ib_copy_validate_udata_cm_fail);
-
-int _ib_respond_udata(struct ib_udata *udata, const void *src, size_t len)
-{
- size_t copy_len;
-
- /* 0 length copy_len is a NOP for copy_to_user() and doesn't fail. */
- copy_len = min(len, udata->outlen);
- if (copy_to_user(udata->outbuf, src, copy_len))
- goto err_fault;
- if (copy_len < udata->outlen) {
- if (clear_user(udata->outbuf + copy_len,
- udata->outlen - copy_len))
- goto err_fault;
- }
- return 0;
-err_fault:
- ibdev_dbg(
- rdma_udata_to_dev(udata),
- "System call driver out udata has EFAULT (%zu into %zu) for ioctl %ps called by %pSR\n",
- len, udata->outlen, uverbs_get_handler_fn(udata),
- __builtin_return_address(0));
- return -EFAULT;
-}
-EXPORT_SYMBOL(_ib_respond_udata);
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH 1/6] RDMA/core: Move the _ib_copy_validate_udata* functions to ib_core_uverbs
2026-05-13 17:33 ` [PATCH 1/6] RDMA/core: Move the _ib_copy_validate_udata* functions to ib_core_uverbs Jason Gunthorpe
@ 2026-05-15 23:12 ` Jason Gunthorpe
0 siblings, 0 replies; 9+ messages in thread
From: Jason Gunthorpe @ 2026-05-15 23:12 UTC (permalink / raw)
To: Leon Romanovsky, linux-rdma; +Cc: Jiri Pirko, patches, Sriharsha Basavapatna
On Wed, May 13, 2026 at 02:33:23PM -0300, Jason Gunthorpe wrote:
> It was incorrect to place them in uverbs_ioctl because that makes every
> driver depends on ib_uverbs.ko, which is undesired. ib_core_uverbs.c is
> for functions used by alot of drivers that are linked into ib_core
> instead.
>
> Fixes: 1de9287ece44 ("RDMA: Add ib_copy_validate_udata_in()")
> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
> ---
> drivers/infiniband/core/ib_core_uverbs.c | 87 ++++++++++++++++
> drivers/infiniband/core/uverbs.h | 35 +++++++
> drivers/infiniband/core/uverbs_ioctl.c | 122 -----------------------
> 3 files changed, 122 insertions(+), 122 deletions(-)
Applied to for-rc
Jason
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 2/6] RDMA/core: Move many of the little EXPORTs from uverbs_ioctl into ib_core_uverbs
2026-05-13 17:33 [PATCH 0/6] Remove driver dependencies on ib_uverbs.ko Jason Gunthorpe
2026-05-13 17:33 ` [PATCH 1/6] RDMA/core: Move the _ib_copy_validate_udata* functions to ib_core_uverbs Jason Gunthorpe
@ 2026-05-13 17:33 ` Jason Gunthorpe
2026-05-13 17:33 ` [PATCH 3/6] RDMA/core: Remove uverbs_async_event_release() Jason Gunthorpe
` (3 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Jason Gunthorpe @ 2026-05-13 17:33 UTC (permalink / raw)
To: Leon Romanovsky, linux-rdma; +Cc: Jiri Pirko, patches, Sriharsha Basavapatna
Not as many drivers need these functions but it does free efa from the
ib_uverbs.ko dependency and follows the general design better.
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
drivers/infiniband/core/ib_core_uverbs.c | 218 +++++++++++++++++++++
drivers/infiniband/core/uverbs.h | 15 ++
drivers/infiniband/core/uverbs_ioctl.c | 204 -------------------
drivers/infiniband/core/uverbs_main.c | 24 ---
drivers/infiniband/core/uverbs_std_types.c | 6 -
5 files changed, 233 insertions(+), 234 deletions(-)
diff --git a/drivers/infiniband/core/ib_core_uverbs.c b/drivers/infiniband/core/ib_core_uverbs.c
index c94d03857318eb..11e43a711207e6 100644
--- a/drivers/infiniband/core/ib_core_uverbs.c
+++ b/drivers/infiniband/core/ib_core_uverbs.c
@@ -503,3 +503,221 @@ int _ib_respond_udata(struct ib_udata *udata, const void *src, size_t len)
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);
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h
index a74a2dff1301ed..e353e195a49c74 100644
--- a/drivers/infiniband/core/uverbs.h
+++ b/drivers/infiniband/core/uverbs.h
@@ -264,6 +264,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 {
diff --git a/drivers/infiniband/core/uverbs_ioctl.c b/drivers/infiniband/core/uverbs_ioctl.c
index 33feb88d652b6a..0e67de0fff570d 100644
--- a/drivers/infiniband/core/uverbs_ioctl.c
+++ b/drivers/infiniband/core/uverbs_ioctl.c
@@ -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,
@@ -614,57 +555,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
@@ -705,24 +595,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.
@@ -736,79 +608,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);
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index f5837da47299c1..15d8387718c050 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -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;
diff --git a/drivers/infiniband/core/uverbs_std_types.c b/drivers/infiniband/core/uverbs_std_types.c
index 13776a66e2e43a..e160786e1df164 100644
--- a/drivers/infiniband/core/uverbs_std_types.c
+++ b/drivers/infiniband/core/uverbs_std_types.c
@@ -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),
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH 3/6] RDMA/core: Remove uverbs_async_event_release()
2026-05-13 17:33 [PATCH 0/6] Remove driver dependencies on ib_uverbs.ko Jason Gunthorpe
2026-05-13 17:33 ` [PATCH 1/6] RDMA/core: Move the _ib_copy_validate_udata* functions to ib_core_uverbs Jason Gunthorpe
2026-05-13 17:33 ` [PATCH 2/6] RDMA/core: Move many of the little EXPORTs from uverbs_ioctl into ib_core_uverbs Jason Gunthorpe
@ 2026-05-13 17:33 ` Jason Gunthorpe
2026-05-13 17:33 ` [PATCH 4/6] RDMA/core: Make a new module for the uverbs components needed by drivers Jason Gunthorpe
` (2 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Jason Gunthorpe @ 2026-05-13 17:33 UTC (permalink / raw)
To: Leon Romanovsky, linux-rdma; +Cc: Jiri Pirko, patches, Sriharsha Basavapatna
Instead of having an alternative fops release always use the standard
uverbs_uobject_fd_release() and route the special async behavior back up
through uverbs_obj_fd_type ops pointer.
This removes a dependency where the technically lower level rdma_core.c is
referring to a symbol from uverbs_std_types_async_fd.c.
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
drivers/infiniband/core/rdma_core.c | 30 ++++++++++++++++---
drivers/infiniband/core/uverbs.h | 1 -
drivers/infiniband/core/uverbs_main.c | 2 +-
.../core/uverbs_std_types_async_fd.c | 22 +++++---------
drivers/infiniband/core/uverbs_uapi.c | 13 ++++++++
include/rdma/uverbs_types.h | 8 ++++-
6 files changed, 54 insertions(+), 22 deletions(-)
diff --git a/drivers/infiniband/core/rdma_core.c b/drivers/infiniband/core/rdma_core.c
index 5018ec837056ff..71e3d58d26e654 100644
--- a/drivers/infiniband/core/rdma_core.c
+++ b/drivers/infiniband/core/rdma_core.c
@@ -465,8 +465,8 @@ alloc_begin_fd_uobject(const struct uverbs_api_object *obj,
fd_type =
container_of(obj->type_attrs, struct uverbs_obj_fd_type, type);
- if (WARN_ON(fd_type->fops && fd_type->fops->release != &uverbs_uobject_fd_release &&
- fd_type->fops->release != &uverbs_async_event_release)) {
+ if (WARN_ON(fd_type->fops &&
+ fd_type->fops->release != &uverbs_uobject_fd_release)) {
ret = ERR_PTR(-EINVAL);
goto err_fd;
}
@@ -846,13 +846,35 @@ int uverbs_uobject_release(struct ib_uobject *uobj)
*/
int uverbs_uobject_fd_release(struct inode *inode, struct file *filp)
{
+ void (*release_cleanup)(struct ib_uobject *uobj) = NULL;
+ struct ib_uobject *uobj = filp->private_data;
+ int ret;
+
/*
* This can only happen if the fput came from alloc_abort_fd_uobject()
*/
- if (!filp->private_data)
+ if (!uobj)
return 0;
- return uverbs_uobject_release(filp->private_data);
+ /*
+ * uverbs_disassociate_api() can NULL type_attrs after disassociate, but
+ * it won't if release_cleanup is used.
+ */
+ if (uobj->uapi_object->type_attrs)
+ release_cleanup = container_of(uobj->uapi_object->type_attrs,
+ struct uverbs_obj_fd_type, type)
+ ->release_cleanup;
+ if (release_cleanup)
+ uverbs_uobject_get(uobj);
+
+ ret = uverbs_uobject_release(uobj);
+
+ if (release_cleanup) {
+ release_cleanup(uobj);
+ uverbs_uobject_put(uobj);
+ }
+
+ return ret;
}
EXPORT_SYMBOL(uverbs_uobject_fd_release);
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h
index e353e195a49c74..31ce2e77fa3a64 100644
--- a/drivers/infiniband/core/uverbs.h
+++ b/drivers/infiniband/core/uverbs.h
@@ -203,7 +203,6 @@ void ib_uverbs_init_event_queue(struct ib_uverbs_event_queue *ev_queue);
void ib_uverbs_init_async_event_file(struct ib_uverbs_async_event_file *ev_file);
void ib_uverbs_free_event_queue(struct ib_uverbs_event_queue *event_queue);
void ib_uverbs_flow_resources_free(struct ib_uflow_resources *uflow_res);
-int uverbs_async_event_release(struct inode *inode, struct file *filp);
int ib_alloc_ucontext(struct uverbs_attr_bundle *attrs);
int ib_init_ucontext(struct uverbs_attr_bundle *attrs);
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index 15d8387718c050..a937d276c5c076 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -338,7 +338,7 @@ const struct file_operations uverbs_async_event_fops = {
.owner = THIS_MODULE,
.read = ib_uverbs_async_event_read,
.poll = ib_uverbs_async_event_poll,
- .release = uverbs_async_event_release,
+ .release = uverbs_uobject_fd_release,
.fasync = ib_uverbs_async_event_fasync,
};
diff --git a/drivers/infiniband/core/uverbs_std_types_async_fd.c b/drivers/infiniband/core/uverbs_std_types_async_fd.c
index cc24cfdf7aee66..671f510bca496f 100644
--- a/drivers/infiniband/core/uverbs_std_types_async_fd.c
+++ b/drivers/infiniband/core/uverbs_std_types_async_fd.c
@@ -32,14 +32,9 @@ static void uverbs_async_event_destroy_uobj(struct ib_uobject *uobj,
NULL, NULL);
}
-int uverbs_async_event_release(struct inode *inode, struct file *filp)
+static void uverbs_async_event_free_event_queue(struct ib_uobject *uobj)
{
struct ib_uverbs_async_event_file *event_file;
- struct ib_uobject *uobj = filp->private_data;
- int ret;
-
- if (!uobj)
- return uverbs_uobject_fd_release(inode, filp);
event_file =
container_of(uobj, struct ib_uverbs_async_event_file, uobj);
@@ -50,11 +45,7 @@ int uverbs_async_event_release(struct inode *inode, struct file *filp)
* release. The user knows it has reached the end of the event stream
* when it sees IB_EVENT_DEVICE_FATAL.
*/
- uverbs_uobject_get(uobj);
- ret = uverbs_uobject_fd_release(inode, filp);
ib_uverbs_free_event_queue(&event_file->ev_queue);
- uverbs_uobject_put(uobj);
- return ret;
}
DECLARE_UVERBS_NAMED_METHOD(
@@ -66,11 +57,12 @@ DECLARE_UVERBS_NAMED_METHOD(
DECLARE_UVERBS_NAMED_OBJECT(
UVERBS_OBJECT_ASYNC_EVENT,
- UVERBS_TYPE_ALLOC_FD(sizeof(struct ib_uverbs_async_event_file),
- uverbs_async_event_destroy_uobj,
- &uverbs_async_event_fops,
- "[infinibandevent]",
- O_RDONLY),
+ UVERBS_TYPE_ALLOC_FD_RELEASE(sizeof(struct ib_uverbs_async_event_file),
+ uverbs_async_event_destroy_uobj,
+ uverbs_async_event_free_event_queue,
+ &uverbs_async_event_fops,
+ "[infinibandevent]",
+ O_RDONLY),
&UVERBS_METHOD(UVERBS_METHOD_ASYNC_EVENT_ALLOC));
const struct uapi_definition uverbs_def_obj_async_fd[] = {
diff --git a/drivers/infiniband/core/uverbs_uapi.c b/drivers/infiniband/core/uverbs_uapi.c
index 31b248295854bd..4e2e556c8119b5 100644
--- a/drivers/infiniband/core/uverbs_uapi.c
+++ b/drivers/infiniband/core/uverbs_uapi.c
@@ -718,12 +718,25 @@ void uverbs_disassociate_api(struct uverbs_api *uapi)
if (uapi_key_is_object(iter.index)) {
struct uverbs_api_object *object_elm =
rcu_dereference_protected(*slot, true);
+ const struct uverbs_obj_type *type_attrs =
+ object_elm->type_attrs;
/*
* Some type_attrs are in the driver module. We don't
* bother to keep track of which since there should be
* no use of this after disassociate.
+ *
+ * release_cleanup is the exception because
+ * uverbs_uobject_fd_release() needs it. In this case
+ * the module reference held by the fops will guarentee
+ * the type_class remains valid too.
*/
+ if (type_attrs &&
+ type_attrs->type_class == &uverbs_fd_class &&
+ container_of(type_attrs, struct uverbs_obj_fd_type,
+ type)->release_cleanup)
+ continue;
+
object_elm->type_attrs = NULL;
} else if (uapi_key_is_attr(iter.index)) {
struct uverbs_api_attr *elm =
diff --git a/include/rdma/uverbs_types.h b/include/rdma/uverbs_types.h
index 6a253b7dc5ea66..5a07f9a6dcd1f6 100644
--- a/include/rdma/uverbs_types.h
+++ b/include/rdma/uverbs_types.h
@@ -147,6 +147,7 @@ struct uverbs_obj_fd_type {
struct uverbs_obj_type type;
void (*destroy_object)(struct ib_uobject *uobj,
enum rdma_remove_reason why);
+ void (*release_cleanup)(struct ib_uobject *uobj);
const struct file_operations *fops;
const char *name;
int flags;
@@ -190,7 +191,8 @@ int uverbs_uobject_release(struct ib_uobject *uobj);
#define UVERBS_BUILD_BUG_ON(cond) (sizeof(char[1 - 2 * !!(cond)]) - \
sizeof(char))
-#define UVERBS_TYPE_ALLOC_FD(_obj_size, _destroy_object, _fops, _name, _flags) \
+#define UVERBS_TYPE_ALLOC_FD_RELEASE(_obj_size, _destroy_object, \
+ _release_cleanup, _fops, _name, _flags) \
((&((const struct uverbs_obj_fd_type) \
{.type = { \
.type_class = &uverbs_fd_class, \
@@ -199,9 +201,13 @@ int uverbs_uobject_release(struct ib_uobject *uobj);
sizeof(struct ib_uobject)), \
}, \
.destroy_object = _destroy_object, \
+ .release_cleanup = _release_cleanup, \
.fops = _fops, \
.name = _name, \
.flags = _flags}))->type)
+#define UVERBS_TYPE_ALLOC_FD(_obj_size, _destroy_object, _fops, _name, _flags) \
+ UVERBS_TYPE_ALLOC_FD_RELEASE(_obj_size, _destroy_object, NULL, \
+ _fops, _name, _flags)
#define UVERBS_TYPE_ALLOC_IDR_SZ(_size, _destroy_object) \
((&((const struct uverbs_obj_idr_type) \
{.type = { \
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH 4/6] RDMA/core: Make a new module for the uverbs components needed by drivers
2026-05-13 17:33 [PATCH 0/6] Remove driver dependencies on ib_uverbs.ko Jason Gunthorpe
` (2 preceding siblings ...)
2026-05-13 17:33 ` [PATCH 3/6] RDMA/core: Remove uverbs_async_event_release() Jason Gunthorpe
@ 2026-05-13 17:33 ` Jason Gunthorpe
2026-05-13 17:33 ` [PATCH 5/6] RDMA/core: Move ucaps into ib_uverbs_support.ko Jason Gunthorpe
2026-05-13 17:33 ` [PATCH 6/6] RDMA/core: Move flow related functions to ib_uverbs_support.ko Jason Gunthorpe
5 siblings, 0 replies; 9+ messages in thread
From: Jason Gunthorpe @ 2026-05-13 17:33 UTC (permalink / raw)
To: Leon Romanovsky, linux-rdma; +Cc: Jiri Pirko, patches, Sriharsha Basavapatna
To maintain the split where ib_uverbs.ko should not be depended on by
drivers, add a new module ib_uverbs_support.ko which contains the driver
called functions that are too large or too rare to be placed in
ib_uverbs_core.ko
Start by moving most of rdma_core.c into this module, making some
adjustments to split it from the actual uverbs FD code.
This was not done originally beacuse we lacked EXPORT_SYMBOL_NS and I had
a fear that drivers would abuse this interface surface.
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
drivers/infiniband/core/Makefile | 8 +-
drivers/infiniband/core/rdma_core.c | 120 ++++++++++++--------------
drivers/infiniband/core/rdma_core.h | 1 -
drivers/infiniband/core/uverbs.h | 9 ++
drivers/infiniband/core/uverbs_main.c | 100 +++++++++++++--------
5 files changed, 133 insertions(+), 105 deletions(-)
diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile
index dce798d8cfe67b..6bdb220f89c0b1 100644
--- a/drivers/infiniband/core/Makefile
+++ b/drivers/infiniband/core/Makefile
@@ -5,7 +5,9 @@ user_access-$(CONFIG_INFINIBAND_ADDR_TRANS) := rdma_ucm.o
obj-$(CONFIG_INFINIBAND) += ib_core.o ib_cm.o iw_cm.o \
$(infiniband-y)
obj-$(CONFIG_INFINIBAND_USER_MAD) += ib_umad.o
-obj-$(CONFIG_INFINIBAND_USER_ACCESS) += ib_uverbs.o $(user_access-y)
+obj-$(CONFIG_INFINIBAND_USER_ACCESS) += ib_uverbs.o \
+ $(user_access-y) \
+ ib_uverbs_support.o
ib_core-y := packer.o ud_header.o verbs.o cq.o rw.o sysfs.o \
device.o cache.o netlink.o \
@@ -33,7 +35,7 @@ rdma_ucm-y := ucma.o
ib_umad-y := user_mad.o
ib_uverbs-y := uverbs_main.o uverbs_cmd.o uverbs_marshall.o \
- rdma_core.o uverbs_std_types.o uverbs_ioctl.o \
+ uverbs_std_types.o uverbs_ioctl.o \
uverbs_std_types_cq.o \
uverbs_std_types_dmabuf.o \
uverbs_std_types_dmah.o \
@@ -45,3 +47,5 @@ ib_uverbs-y := uverbs_main.o uverbs_cmd.o uverbs_marshall.o \
uverbs_std_types_wq.o \
uverbs_std_types_qp.o \
ucaps.o
+
+ib_uverbs_support-y := rdma_core.o
diff --git a/drivers/infiniband/core/rdma_core.c b/drivers/infiniband/core/rdma_core.c
index 71e3d58d26e654..b81a1540d0fb59 100644
--- a/drivers/infiniband/core/rdma_core.c
+++ b/drivers/infiniband/core/rdma_core.c
@@ -42,6 +42,40 @@
#include "core_priv.h"
#include "rdma_core.h"
+static void release_ufile_idr_uobject(struct ib_uverbs_file *ufile);
+
+void ib_uverbs_release_file(struct kref *ref)
+{
+ struct ib_uverbs_file *file =
+ container_of(ref, struct ib_uverbs_file, ref);
+ struct ib_device *ib_dev;
+ int srcu_key;
+
+ release_ufile_idr_uobject(file);
+
+ srcu_key = srcu_read_lock(&file->device->disassociate_srcu);
+ ib_dev = srcu_dereference(file->device->ib_dev,
+ &file->device->disassociate_srcu);
+ if (ib_dev && !ib_dev->ops.disassociate_ucontext)
+ module_put(ib_dev->ops.owner);
+ srcu_read_unlock(&file->device->disassociate_srcu, srcu_key);
+
+ if (refcount_dec_and_test(&file->device->refcount))
+ ib_uverbs_comp_dev(file->device);
+
+ if (file->default_async_file)
+ uverbs_uobject_put(&file->default_async_file->uobj);
+ put_device(&file->device->dev);
+
+ if (file->disassociate_page)
+ __free_pages(file->disassociate_page, 0);
+ mutex_destroy(&file->disassociation_lock);
+ mutex_destroy(&file->umap_lock);
+ mutex_destroy(&file->ucontext_lock);
+ kfree(file);
+}
+EXPORT_SYMBOL_NS_GPL(ib_uverbs_release_file, "rdma_core");
+
static void uverbs_uobject_free(struct kref *ref)
{
kfree_rcu(container_of(ref, struct ib_uobject, ref), rcu);
@@ -214,6 +248,7 @@ int uobj_destroy(struct ib_uobject *uobj, struct uverbs_attr_bundle *attrs)
up_read(&ufile->hw_destroy_rwsem);
return ret;
}
+EXPORT_SYMBOL_NS_GPL(uobj_destroy, "rdma_core");
/*
* uobj_get_destroy destroys the HW object and returns a handle to the uobj
@@ -239,6 +274,7 @@ struct ib_uobject *__uobj_get_destroy(const struct uverbs_api_object *obj,
return uobj;
}
+EXPORT_SYMBOL_NS_GPL(__uobj_get_destroy, "rdma_core");
/*
* Does both uobj_get_destroy() and uobj_put_destroy(). Returns 0 on success
@@ -255,6 +291,7 @@ int __uobj_perform_destroy(const struct uverbs_api_object *obj, u32 id,
uobj_put_destroy(uobj);
return 0;
}
+EXPORT_SYMBOL_NS_GPL(__uobj_perform_destroy, "rdma_core");
/* alloc_uobj must be undone by uverbs_destroy_uobject() */
static struct ib_uobject *alloc_uobj(struct uverbs_attr_bundle *attrs,
@@ -420,6 +457,7 @@ struct ib_uobject *rdma_lookup_get_uobject(const struct uverbs_api_object *obj,
uverbs_uobject_put(uobj);
return ERR_PTR(ret);
}
+EXPORT_SYMBOL_NS_GPL(rdma_lookup_get_uobject, "rdma_core");
static struct ib_uobject *
alloc_begin_idr_uobject(const struct uverbs_api_object *obj,
@@ -522,6 +560,7 @@ struct ib_uobject *rdma_alloc_begin_uobject(const struct uverbs_api_object *obj,
}
return ret;
}
+EXPORT_SYMBOL_NS_GPL(rdma_alloc_begin_uobject, "rdma_core");
static void alloc_abort_idr_uobject(struct ib_uobject *uobj)
{
@@ -668,6 +707,7 @@ void rdma_alloc_commit_uobject(struct ib_uobject *uobj,
/* Matches the down_read in rdma_alloc_begin_uobject */
up_read(&ufile->hw_destroy_rwsem);
}
+EXPORT_SYMBOL_NS_GPL(rdma_alloc_commit_uobject, "rdma_core");
/*
* new_uobj will be assigned to the handle currently used by to_uobj, and
@@ -697,6 +737,7 @@ void rdma_assign_uobject(struct ib_uobject *to_uobj, struct ib_uobject *new_uobj
*/
uverbs_destroy_uobject(to_uobj, RDMA_REMOVE_DESTROY, attrs);
}
+EXPORT_SYMBOL_NS_GPL(rdma_assign_uobject, "rdma_core");
/*
* This consumes the kref for uobj. It is up to the caller to unwind the HW
@@ -727,6 +768,7 @@ void rdma_alloc_abort_uobject(struct ib_uobject *uobj,
/* Matches the down_read in rdma_alloc_begin_uobject */
up_read(&ufile->hw_destroy_rwsem);
}
+EXPORT_SYMBOL_NS_GPL(rdma_alloc_abort_uobject, "rdma_core");
static void lookup_put_idr_uobject(struct ib_uobject *uobj,
enum rdma_lookup_mode mode)
@@ -770,13 +812,15 @@ void rdma_lookup_put_uobject(struct ib_uobject *uobj,
/* Pairs with the kref obtained by type->lookup_get */
uverbs_uobject_put(uobj);
}
+EXPORT_SYMBOL_NS_GPL(rdma_lookup_put_uobject, "rdma_core");
void setup_ufile_idr_uobject(struct ib_uverbs_file *ufile)
{
xa_init_flags(&ufile->idr, XA_FLAGS_ALLOC);
}
+EXPORT_SYMBOL_NS_GPL(setup_ufile_idr_uobject, "rdma_core");
-void release_ufile_idr_uobject(struct ib_uverbs_file *ufile)
+static void release_ufile_idr_uobject(struct ib_uverbs_file *ufile)
{
struct ib_uobject *entry;
unsigned long id;
@@ -839,6 +883,7 @@ int uverbs_uobject_release(struct ib_uobject *uobj)
uverbs_uobject_put(uobj);
return 0;
}
+EXPORT_SYMBOL_NS_GPL(uverbs_uobject_release, "rdma_core");
/*
* Users of UVERBS_TYPE_ALLOC_FD should set this function as the struct
@@ -878,41 +923,8 @@ int uverbs_uobject_fd_release(struct inode *inode, struct file *filp)
}
EXPORT_SYMBOL(uverbs_uobject_fd_release);
-/*
- * Drop the ucontext off the ufile and completely disconnect it from the
- * ib_device
- */
-static void ufile_destroy_ucontext(struct ib_uverbs_file *ufile,
- enum rdma_remove_reason reason)
-{
- struct ib_ucontext *ucontext = ufile->ucontext;
- struct ib_device *ib_dev = ucontext->device;
-
- /*
- * If we are closing the FD then the user mmap VMAs must have
- * already been destroyed as they hold on to the filep, otherwise
- * they need to be zap'd.
- */
- if (reason == RDMA_REMOVE_DRIVER_REMOVE) {
- uverbs_user_mmap_disassociate(ufile);
- if (ib_dev->ops.disassociate_ucontext)
- ib_dev->ops.disassociate_ucontext(ucontext);
- }
-
- ib_rdmacg_uncharge(&ucontext->cg_obj, ib_dev,
- RDMACG_RESOURCE_HCA_HANDLE);
-
- rdma_restrack_del(&ucontext->res);
-
- ib_dev->ops.dealloc_ucontext(ucontext);
- WARN_ON(!xa_empty(&ucontext->mmap_xa));
- kfree(ucontext);
-
- ufile->ucontext = NULL;
-}
-
-static int __uverbs_cleanup_ufile(struct ib_uverbs_file *ufile,
- enum rdma_remove_reason reason)
+int __uverbs_cleanup_ufile(struct ib_uverbs_file *ufile,
+ enum rdma_remove_reason reason)
{
struct uverbs_attr_bundle attrs = { .ufile = ufile };
struct ib_ucontext *ucontext = ufile->ucontext;
@@ -953,36 +965,7 @@ static int __uverbs_cleanup_ufile(struct ib_uverbs_file *ufile,
}
return ret;
}
-
-/*
- * Destroy the ucontext and every uobject associated with it.
- *
- * This is internally locked and can be called in parallel from multiple
- * contexts.
- */
-void uverbs_destroy_ufile_hw(struct ib_uverbs_file *ufile,
- enum rdma_remove_reason reason)
-{
- down_write(&ufile->hw_destroy_rwsem);
-
- /*
- * If a ucontext was never created then we can't have any uobjects to
- * cleanup, nothing to do.
- */
- if (!ufile->ucontext)
- goto done;
-
- while (!list_empty(&ufile->uobjects) &&
- !__uverbs_cleanup_ufile(ufile, reason)) {
- }
-
- if (WARN_ON(!list_empty(&ufile->uobjects)))
- __uverbs_cleanup_ufile(ufile, RDMA_REMOVE_DRIVER_FAILURE);
- ufile_destroy_ucontext(ufile, reason);
-
-done:
- up_write(&ufile->hw_destroy_rwsem);
-}
+EXPORT_SYMBOL_NS_GPL(__uverbs_cleanup_ufile, "rdma_core");
const struct uverbs_obj_type_class uverbs_fd_class = {
.alloc_begin = alloc_begin_fd_uobject,
@@ -1020,6 +1003,7 @@ uverbs_get_uobject_from_file(u16 object_id, enum uverbs_obj_access access,
return ERR_PTR(-EOPNOTSUPP);
}
}
+EXPORT_SYMBOL_NS_GPL(uverbs_get_uobject_from_file, "rdma_core");
void uverbs_finalize_object(struct ib_uobject *uobj,
enum uverbs_obj_access access, bool hw_obj_valid,
@@ -1052,6 +1036,7 @@ void uverbs_finalize_object(struct ib_uobject *uobj,
WARN_ON(true);
}
}
+EXPORT_SYMBOL_NS_GPL(uverbs_finalize_object, "rdma_core");
/**
* rdma_uattrs_has_raw_cap() - Returns whether a rdma device linked to the
@@ -1081,3 +1066,6 @@ bool rdma_uattrs_has_raw_cap(const struct uverbs_attr_bundle *attrs)
return has_cap;
}
EXPORT_SYMBOL(rdma_uattrs_has_raw_cap);
+
+MODULE_DESCRIPTION("InfiniBand uverbs objects");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/infiniband/core/rdma_core.h b/drivers/infiniband/core/rdma_core.h
index 269b393799abbc..d6656d14eebaa4 100644
--- a/drivers/infiniband/core/rdma_core.h
+++ b/drivers/infiniband/core/rdma_core.h
@@ -70,7 +70,6 @@ void uverbs_finalize_object(struct ib_uobject *uobj,
int uverbs_output_written(const struct uverbs_attr_bundle *bundle, size_t idx);
void setup_ufile_idr_uobject(struct ib_uverbs_file *ufile);
-void release_ufile_idr_uobject(struct ib_uverbs_file *ufile);
struct ib_udata *uverbs_get_cleared_udata(struct uverbs_attr_bundle *attrs);
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h
index 31ce2e77fa3a64..280fa99860a1de 100644
--- a/drivers/infiniband/core/uverbs.h
+++ b/drivers/infiniband/core/uverbs.h
@@ -360,4 +360,13 @@ static inline void ib_uverbs_dmabuf_done(struct kref *kref)
complete(&priv->comp);
}
+int __uverbs_cleanup_ufile(struct ib_uverbs_file *ufile,
+ enum rdma_remove_reason reason);
+
+static inline void ib_uverbs_comp_dev(struct ib_uverbs_device *dev)
+{
+ complete(&dev->comp);
+}
+
+
#endif /* UVERBS_H */
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index a937d276c5c076..ab6f1e3cb47a18 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -61,6 +61,7 @@
MODULE_AUTHOR("Roland Dreier");
MODULE_DESCRIPTION("InfiniBand userspace verbs access");
MODULE_LICENSE("Dual BSD/GPL");
+MODULE_IMPORT_NS("rdma_core");
enum {
IB_UVERBS_MAJOR = 231,
@@ -165,42 +166,6 @@ void ib_uverbs_detach_umcast(struct ib_qp *qp,
}
}
-static void ib_uverbs_comp_dev(struct ib_uverbs_device *dev)
-{
- complete(&dev->comp);
-}
-
-void ib_uverbs_release_file(struct kref *ref)
-{
- struct ib_uverbs_file *file =
- container_of(ref, struct ib_uverbs_file, ref);
- struct ib_device *ib_dev;
- int srcu_key;
-
- release_ufile_idr_uobject(file);
-
- srcu_key = srcu_read_lock(&file->device->disassociate_srcu);
- ib_dev = srcu_dereference(file->device->ib_dev,
- &file->device->disassociate_srcu);
- if (ib_dev && !ib_dev->ops.disassociate_ucontext)
- module_put(ib_dev->ops.owner);
- srcu_read_unlock(&file->device->disassociate_srcu, srcu_key);
-
- if (refcount_dec_and_test(&file->device->refcount))
- ib_uverbs_comp_dev(file->device);
-
- if (file->default_async_file)
- uverbs_uobject_put(&file->default_async_file->uobj);
- put_device(&file->device->dev);
-
- if (file->disassociate_page)
- __free_pages(file->disassociate_page, 0);
- mutex_destroy(&file->disassociation_lock);
- mutex_destroy(&file->umap_lock);
- mutex_destroy(&file->ucontext_lock);
- kfree(file);
-}
-
static ssize_t ib_uverbs_event_read(struct ib_uverbs_event_queue *ev_queue,
struct file *filp, char __user *buf,
size_t count, loff_t *pos,
@@ -985,6 +950,69 @@ static int ib_uverbs_open(struct inode *inode, struct file *filp)
return ret;
}
+/*
+ * Drop the ucontext off the ufile and completely disconnect it from the
+ * ib_device
+ */
+static void ufile_destroy_ucontext(struct ib_uverbs_file *ufile,
+ enum rdma_remove_reason reason)
+{
+ struct ib_ucontext *ucontext = ufile->ucontext;
+ struct ib_device *ib_dev = ucontext->device;
+
+ /*
+ * If we are closing the FD then the user mmap VMAs must have
+ * already been destroyed as they hold on to the filep, otherwise
+ * they need to be zap'd.
+ */
+ if (reason == RDMA_REMOVE_DRIVER_REMOVE) {
+ uverbs_user_mmap_disassociate(ufile);
+ if (ib_dev->ops.disassociate_ucontext)
+ ib_dev->ops.disassociate_ucontext(ucontext);
+ }
+
+ ib_rdmacg_uncharge(&ucontext->cg_obj, ib_dev,
+ RDMACG_RESOURCE_HCA_HANDLE);
+
+ rdma_restrack_del(&ucontext->res);
+
+ ib_dev->ops.dealloc_ucontext(ucontext);
+ WARN_ON(!xa_empty(&ucontext->mmap_xa));
+ kfree(ucontext);
+
+ ufile->ucontext = NULL;
+}
+
+/*
+ * Destroy the ucontext and every uobject associated with it.
+ *
+ * This is internally locked and can be called in parallel from multiple
+ * contexts.
+ */
+void uverbs_destroy_ufile_hw(struct ib_uverbs_file *ufile,
+ enum rdma_remove_reason reason)
+{
+ down_write(&ufile->hw_destroy_rwsem);
+
+ /*
+ * If a ucontext was never created then we can't have any uobjects to
+ * cleanup, nothing to do.
+ */
+ if (!ufile->ucontext)
+ goto done;
+
+ while (!list_empty(&ufile->uobjects) &&
+ !__uverbs_cleanup_ufile(ufile, reason)) {
+ }
+
+ if (WARN_ON(!list_empty(&ufile->uobjects)))
+ __uverbs_cleanup_ufile(ufile, RDMA_REMOVE_DRIVER_FAILURE);
+ ufile_destroy_ucontext(ufile, reason);
+
+done:
+ up_write(&ufile->hw_destroy_rwsem);
+}
+
static int ib_uverbs_close(struct inode *inode, struct file *filp)
{
struct ib_uverbs_file *file = filp->private_data;
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH 5/6] RDMA/core: Move ucaps into ib_uverbs_support.ko
2026-05-13 17:33 [PATCH 0/6] Remove driver dependencies on ib_uverbs.ko Jason Gunthorpe
` (3 preceding siblings ...)
2026-05-13 17:33 ` [PATCH 4/6] RDMA/core: Make a new module for the uverbs components needed by drivers Jason Gunthorpe
@ 2026-05-13 17:33 ` Jason Gunthorpe
2026-05-13 17:33 ` [PATCH 6/6] RDMA/core: Move flow related functions to ib_uverbs_support.ko Jason Gunthorpe
5 siblings, 0 replies; 9+ messages in thread
From: Jason Gunthorpe @ 2026-05-13 17:33 UTC (permalink / raw)
To: Leon Romanovsky, linux-rdma; +Cc: Jiri Pirko, patches, Sriharsha Basavapatna
mlx5 uses these move them into the support module from ib_uverbs.ko.
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
drivers/infiniband/core/Makefile | 6 +++---
drivers/infiniband/core/ucaps.c | 6 +++++-
drivers/infiniband/core/uverbs_main.c | 1 -
include/rdma/ib_ucaps.h | 1 -
4 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile
index 6bdb220f89c0b1..697468cf88b16f 100644
--- a/drivers/infiniband/core/Makefile
+++ b/drivers/infiniband/core/Makefile
@@ -45,7 +45,7 @@ ib_uverbs-y := uverbs_main.o uverbs_cmd.o uverbs_marshall.o \
uverbs_std_types_async_fd.o \
uverbs_std_types_srq.o \
uverbs_std_types_wq.o \
- uverbs_std_types_qp.o \
- ucaps.o
+ uverbs_std_types_qp.o
-ib_uverbs_support-y := rdma_core.o
+ib_uverbs_support-y := rdma_core.o \
+ ucaps.o
diff --git a/drivers/infiniband/core/ucaps.c b/drivers/infiniband/core/ucaps.c
index 948093260dbda1..ce1750a0f90a45 100644
--- a/drivers/infiniband/core/ucaps.c
+++ b/drivers/infiniband/core/ucaps.c
@@ -51,7 +51,7 @@ static const struct file_operations ucaps_cdev_fops = {
*
* This is called once, when removing the ib_uverbs module.
*/
-void ib_cleanup_ucaps(void)
+static int ib_cleanup_ucaps(void)
{
mutex_lock(&ucaps_mutex);
if (!ucaps_class_is_registered) {
@@ -66,6 +66,7 @@ void ib_cleanup_ucaps(void)
ucaps_class_is_registered = false;
unregister_chrdev_region(ucaps_base_dev, RDMA_UCAP_MAX);
mutex_unlock(&ucaps_mutex);
+ return 0;
}
static int get_ucap_from_devt(dev_t devt, u64 *idx_mask)
@@ -265,3 +266,6 @@ int ib_get_ucaps(int *fds, int fd_count, uint64_t *idx_mask)
mutex_unlock(&ucaps_mutex);
return ret;
}
+EXPORT_SYMBOL_NS_GPL(ib_get_ucaps, "rdma_core");
+
+module_init(ib_cleanup_ucaps);
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index ab6f1e3cb47a18..3ccf58e96aedeb 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -1350,7 +1350,6 @@ static void __exit ib_uverbs_cleanup(void)
IB_UVERBS_NUM_FIXED_MINOR);
unregister_chrdev_region(dynamic_uverbs_dev,
IB_UVERBS_NUM_DYNAMIC_MINOR);
- ib_cleanup_ucaps();
mmu_notifier_synchronize();
}
diff --git a/include/rdma/ib_ucaps.h b/include/rdma/ib_ucaps.h
index d9f96be3a553f8..b629c99117d8fe 100644
--- a/include/rdma/ib_ucaps.h
+++ b/include/rdma/ib_ucaps.h
@@ -14,7 +14,6 @@ enum rdma_user_cap {
RDMA_UCAP_MAX
};
-void ib_cleanup_ucaps(void);
int ib_get_ucaps(int *fds, int fd_count, uint64_t *idx_mask);
#if IS_ENABLED(CONFIG_INFINIBAND_USER_ACCESS)
int ib_create_ucap(enum rdma_user_cap type);
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH 6/6] RDMA/core: Move flow related functions to ib_uverbs_support.ko
2026-05-13 17:33 [PATCH 0/6] Remove driver dependencies on ib_uverbs.ko Jason Gunthorpe
` (4 preceding siblings ...)
2026-05-13 17:33 ` [PATCH 5/6] RDMA/core: Move ucaps into ib_uverbs_support.ko Jason Gunthorpe
@ 2026-05-13 17:33 ` Jason Gunthorpe
2026-05-15 18:23 ` kernel test robot
5 siblings, 1 reply; 9+ messages in thread
From: Jason Gunthorpe @ 2026-05-13 17:33 UTC (permalink / raw)
To: Leon Romanovsky, linux-rdma; +Cc: Jiri Pirko, patches, Sriharsha Basavapatna
mlx5 uses these as part of the driver implementation, move them to the
support module instead.
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
drivers/infiniband/core/Makefile | 3 +-
drivers/infiniband/core/uverbs_cmd.c | 76 --------------------------
drivers/infiniband/core/uverbs_flow.c | 78 +++++++++++++++++++++++++++
3 files changed, 80 insertions(+), 77 deletions(-)
create mode 100644 drivers/infiniband/core/uverbs_flow.c
diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile
index 697468cf88b16f..69f72b63e961ab 100644
--- a/drivers/infiniband/core/Makefile
+++ b/drivers/infiniband/core/Makefile
@@ -48,4 +48,5 @@ ib_uverbs-y := uverbs_main.o uverbs_cmd.o uverbs_marshall.o \
uverbs_std_types_qp.o
ib_uverbs_support-y := rdma_core.o \
- ucaps.o
+ ucaps.o \
+ uverbs_flow.o
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index a768436ba46805..fce6eb18287a19 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -2589,82 +2589,6 @@ static int ib_uverbs_detach_mcast(struct uverbs_attr_bundle *attrs)
return ret;
}
-struct ib_uflow_resources *flow_resources_alloc(size_t num_specs)
-{
- struct ib_uflow_resources *resources;
-
- resources = kzalloc_obj(*resources);
-
- if (!resources)
- return NULL;
-
- if (!num_specs)
- goto out;
-
- resources->counters =
- kzalloc_objs(*resources->counters, num_specs);
- resources->collection =
- kzalloc_objs(*resources->collection, num_specs);
-
- if (!resources->counters || !resources->collection)
- goto err;
-
-out:
- resources->max = num_specs;
- return resources;
-
-err:
- kfree(resources->counters);
- kfree(resources);
-
- return NULL;
-}
-EXPORT_SYMBOL(flow_resources_alloc);
-
-void ib_uverbs_flow_resources_free(struct ib_uflow_resources *uflow_res)
-{
- unsigned int i;
-
- if (!uflow_res)
- return;
-
- for (i = 0; i < uflow_res->collection_num; i++)
- atomic_dec(&uflow_res->collection[i]->usecnt);
-
- for (i = 0; i < uflow_res->counters_num; i++)
- atomic_dec(&uflow_res->counters[i]->usecnt);
-
- kfree(uflow_res->collection);
- kfree(uflow_res->counters);
- kfree(uflow_res);
-}
-EXPORT_SYMBOL(ib_uverbs_flow_resources_free);
-
-void flow_resources_add(struct ib_uflow_resources *uflow_res,
- enum ib_flow_spec_type type,
- void *ibobj)
-{
- WARN_ON(uflow_res->num >= uflow_res->max);
-
- switch (type) {
- case IB_FLOW_SPEC_ACTION_HANDLE:
- atomic_inc(&((struct ib_flow_action *)ibobj)->usecnt);
- uflow_res->collection[uflow_res->collection_num++] =
- (struct ib_flow_action *)ibobj;
- break;
- case IB_FLOW_SPEC_ACTION_COUNT:
- atomic_inc(&((struct ib_counters *)ibobj)->usecnt);
- uflow_res->counters[uflow_res->counters_num++] =
- (struct ib_counters *)ibobj;
- break;
- default:
- WARN_ON(1);
- }
-
- uflow_res->num++;
-}
-EXPORT_SYMBOL(flow_resources_add);
-
static int kern_spec_to_ib_spec_action(struct uverbs_attr_bundle *attrs,
struct ib_uverbs_flow_spec *kern_spec,
union ib_flow_spec *ib_spec,
diff --git a/drivers/infiniband/core/uverbs_flow.c b/drivers/infiniband/core/uverbs_flow.c
new file mode 100644
index 00000000000000..1528a294f7f85f
--- /dev/null
+++ b/drivers/infiniband/core/uverbs_flow.c
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+#include "uverbs.h"
+
+struct ib_uflow_resources *flow_resources_alloc(size_t num_specs)
+{
+ struct ib_uflow_resources *resources;
+
+ resources = kzalloc_obj(*resources);
+
+ if (!resources)
+ return NULL;
+
+ if (!num_specs)
+ goto out;
+
+ resources->counters =
+ kzalloc_objs(*resources->counters, num_specs);
+ resources->collection =
+ kzalloc_objs(*resources->collection, num_specs);
+
+ if (!resources->counters || !resources->collection)
+ goto err;
+
+out:
+ resources->max = num_specs;
+ return resources;
+
+err:
+ kfree(resources->counters);
+ kfree(resources);
+
+ return NULL;
+}
+EXPORT_SYMBOL(flow_resources_alloc);
+
+void ib_uverbs_flow_resources_free(struct ib_uflow_resources *uflow_res)
+{
+ unsigned int i;
+
+ if (!uflow_res)
+ return;
+
+ for (i = 0; i < uflow_res->collection_num; i++)
+ atomic_dec(&uflow_res->collection[i]->usecnt);
+
+ for (i = 0; i < uflow_res->counters_num; i++)
+ atomic_dec(&uflow_res->counters[i]->usecnt);
+
+ kfree(uflow_res->collection);
+ kfree(uflow_res->counters);
+ kfree(uflow_res);
+}
+EXPORT_SYMBOL(ib_uverbs_flow_resources_free);
+
+void flow_resources_add(struct ib_uflow_resources *uflow_res,
+ enum ib_flow_spec_type type,
+ void *ibobj)
+{
+ WARN_ON(uflow_res->num >= uflow_res->max);
+
+ switch (type) {
+ case IB_FLOW_SPEC_ACTION_HANDLE:
+ atomic_inc(&((struct ib_flow_action *)ibobj)->usecnt);
+ uflow_res->collection[uflow_res->collection_num++] =
+ (struct ib_flow_action *)ibobj;
+ break;
+ case IB_FLOW_SPEC_ACTION_COUNT:
+ atomic_inc(&((struct ib_counters *)ibobj)->usecnt);
+ uflow_res->counters[uflow_res->counters_num++] =
+ (struct ib_counters *)ibobj;
+ break;
+ default:
+ WARN_ON(1);
+ }
+
+ uflow_res->num++;
+}
+EXPORT_SYMBOL(flow_resources_add);
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH 6/6] RDMA/core: Move flow related functions to ib_uverbs_support.ko
2026-05-13 17:33 ` [PATCH 6/6] RDMA/core: Move flow related functions to ib_uverbs_support.ko Jason Gunthorpe
@ 2026-05-15 18:23 ` kernel test robot
0 siblings, 0 replies; 9+ messages in thread
From: kernel test robot @ 2026-05-15 18:23 UTC (permalink / raw)
To: Jason Gunthorpe, Leon Romanovsky, linux-rdma
Cc: oe-kbuild-all, Jiri Pirko, patches, Sriharsha Basavapatna
Hi Jason,
kernel test robot noticed the following build warnings:
[auto build test WARNING on 254f49634ee16a731174d2ae34bc50bd5f45e731]
url: https://github.com/intel-lab-lkp/linux/commits/Jason-Gunthorpe/RDMA-core-Move-the-_ib_copy_validate_udata-functions-to-ib_core_uverbs/20260515-124950
base: 254f49634ee16a731174d2ae34bc50bd5f45e731
patch link: https://lore.kernel.org/r/6-v1-045258567bd6%2B9fe-ib_uverbs_support_ko_jgg%40nvidia.com
patch subject: [PATCH 6/6] RDMA/core: Move flow related functions to ib_uverbs_support.ko
config: x86_64-randconfig-123 (https://download.01.org/0day-ci/archive/20260516/202605160258.313mCXe3-lkp@intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
sparse: v0.6.5-rc1
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260516/202605160258.313mCXe3-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202605160258.313mCXe3-lkp@intel.com/
sparse warnings: (new ones prefixed by >>)
>> drivers/infiniband/core/ib_core_uverbs.c:429:16: sparse: sparse: incorrect type in return expression (different modifiers) @@ expected int ( * )( ... ) @@ got int ( [noderef] *__v )( ... ) @@
drivers/infiniband/core/ib_core_uverbs.c:429:16: sparse: expected int ( * )( ... )
drivers/infiniband/core/ib_core_uverbs.c:429:16: sparse: got int ( [noderef] *__v )( ... )
vim +429 drivers/infiniband/core/ib_core_uverbs.c
419
420 uverbs_api_ioctl_handler_fn uverbs_get_handler_fn(struct ib_udata *udata)
421 {
422 struct uverbs_attr_bundle *bundle =
423 rdma_udata_to_uverbs_attr_bundle(udata);
424 struct bundle_priv *pbundle =
425 container_of(&bundle->hdr, struct bundle_priv, bundle);
426
427 lockdep_assert_held(&bundle->ufile->device->disassociate_srcu);
428
> 429 return srcu_dereference(pbundle->method_elm->handler,
430 &bundle->ufile->device->disassociate_srcu);
431 }
432
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 9+ messages in thread