From: Jason Gunthorpe Date: Tue, 26 May 2026 01:22:40 +0000 (-0300) Subject: RDMA/core: Make a new module for the uverbs components needed by drivers X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=2274d8cb4912ab32bcff80d6c7cbae453614ae08;p=thirdparty%2Flinux.git RDMA/core: Make a new module for the uverbs components needed by drivers 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 --- diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile index 8c2ba2ce03517..e2ff9c2be9d37 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 \ @@ -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 diff --git a/drivers/infiniband/core/rdma_core.c b/drivers/infiniband/core/rdma_core.c index 8934d0d227ab7..fd5651c003aed 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 @@ 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"); diff --git a/drivers/infiniband/core/rdma_core.h b/drivers/infiniband/core/rdma_core.h index 55f1e3558856f..b626d3d24d087 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 a1de8fe9c90bf..c64dd6b94e106 100644 --- a/drivers/infiniband/core/uverbs.h +++ b/drivers/infiniband/core/uverbs.h @@ -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 */ diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index a937d276c5c07..ab6f1e3cb47a1 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 @@ 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;