From: Jason Gunthorpe <jgg@nvidia.com>
To: Leon Romanovsky <leon@kernel.org>, linux-rdma@vger.kernel.org
Cc: Jiri Pirko <jiri@resnulli.us>,
patches@lists.linux.dev,
Sriharsha Basavapatna <sriharsha.basavapatna@broadcom.com>
Subject: [PATCH 4/6] RDMA/core: Make a new module for the uverbs components needed by drivers
Date: Wed, 13 May 2026 14:33:26 -0300 [thread overview]
Message-ID: <4-v1-045258567bd6+9fe-ib_uverbs_support_ko_jgg@nvidia.com> (raw)
In-Reply-To: <0-v1-045258567bd6+9fe-ib_uverbs_support_ko_jgg@nvidia.com>
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
next prev parent reply other threads:[~2026-05-13 17:33 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
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-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
2026-05-13 17:33 ` [PATCH 3/6] RDMA/core: Remove uverbs_async_event_release() Jason Gunthorpe
2026-05-13 17:33 ` Jason Gunthorpe [this message]
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
2026-05-15 18:23 ` kernel test robot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4-v1-045258567bd6+9fe-ib_uverbs_support_ko_jgg@nvidia.com \
--to=jgg@nvidia.com \
--cc=jiri@resnulli.us \
--cc=leon@kernel.org \
--cc=linux-rdma@vger.kernel.org \
--cc=patches@lists.linux.dev \
--cc=sriharsha.basavapatna@broadcom.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox