]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
RDMA/core: Make a new module for the uverbs components needed by drivers
authorJason Gunthorpe <jgg@nvidia.com>
Tue, 26 May 2026 01:22:40 +0000 (22:22 -0300)
committerJason Gunthorpe <jgg@nvidia.com>
Tue, 26 May 2026 13:09:37 +0000 (10:09 -0300)
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 because we lacked EXPORT_SYMBOL_NS and I had
a fear that drivers would abuse this interface surface.

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

index 8c2ba2ce0351760d38b7f6ceb69008887df5bdc1..e2ff9c2be9d3774d336fcc102ea17351d69d441c 100644 (file)
@@ -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 \
@@ -34,7 +36,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 \
@@ -46,3 +48,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
index 8934d0d227ab7670ee1762aa6e0cf0d1ca672e91..fd5651c003aed3178188b4f89ede86d893676a9a 100644 (file)
 #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 @@ out_unlock:
        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 @@ free:
        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
@@ -880,41 +925,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;
@@ -955,36 +967,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,
@@ -1022,6 +1005,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,
@@ -1054,6 +1038,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
@@ -1083,3 +1068,6 @@ out:
        return has_cap;
 }
 EXPORT_SYMBOL(rdma_uattrs_has_raw_cap);
+
+MODULE_DESCRIPTION("InfiniBand uverbs objects");
+MODULE_LICENSE("Dual BSD/GPL");
index 55f1e3558856f129d125d44011fe2837130bb457..b626d3d24d087dff066029764ea8a7a8362c3ddb 100644 (file)
@@ -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);
 
index a1de8fe9c90bf104e402d4e66e2caf4a18e860aa..c64dd6b94e106730975d843258e275ab0781716f 100644 (file)
@@ -359,4 +359,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 */
index a937d276c5c076071efd64f6bacb30e042f288e4..ab6f1e3cb47a184aec6fde6f9f257b623ccf0af2 100644 (file)
@@ -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 @@ err:
        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;