From: Jason Gunthorpe Date: Tue, 26 May 2026 01:22:39 +0000 (-0300) Subject: RDMA/core: Remove uverbs_async_event_release() X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=2c296df0add86a75356f8bb099ecfcfc42419600;p=thirdparty%2Flinux.git RDMA/core: Remove uverbs_async_event_release() 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. Link: https://patch.msgid.link/r/3-v3-43aba1969751+1988-ib_uverbs_support_ko_jgg@nvidia.com Signed-off-by: Jason Gunthorpe --- diff --git a/drivers/infiniband/core/rdma_core.c b/drivers/infiniband/core/rdma_core.c index 5018ec837056f..8934d0d227ab7 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,37 @@ 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; + const struct uverbs_obj_type *type_attrs; + 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. + */ + type_attrs = READ_ONCE(uobj->uapi_object->type_attrs); + if (type_attrs) + release_cleanup = container_of(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 1563169c65009..a1de8fe9c90bf 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 15d8387718c05..a937d276c5c07 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 cc24cfdf7aee6..671f510bca496 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 31b248295854b..4e2e556c8119b 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 6a253b7dc5ea6..5a07f9a6dcd1f 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 = { \