mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
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 <jgg@nvidia.com>
This commit is contained in:
parent
2c296df0ad
commit
2274d8cb49
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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 @@ 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");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user