RDMA/uverbs: Do not discard the IB_EVENT_DEVICE_FATAL event
The commit below moved all of the destruction to the disassociate step and cleaned up the event channel during destroy_uobj. However, when ib_uverbs_free_hw_resources() pushes IB_EVENT_DEVICE_FATAL and then immediately goes to destroy all uobjects this causes ib_uverbs_free_event_queue() to discard the queued event if userspace hasn't already read() it. Unlike all other event queues async FD needs to defer the ib_uverbs_free_event_queue() until FD release. This still unregisters the handler from the IB device during disassociation. Fixes: 3e032c0e92aa ("RDMA/core: Make ib_uverbs_async_event_file into a uobject") Link: https://lore.kernel.org/r/20200507063348.98713-2-leon@kernel.org Signed-off-by: Yishai Hadas <yishaih@mellanox.com> Signed-off-by: Leon Romanovsky <leonro@mellanox.com> Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
This commit is contained in:
parent
c8b1f340e5
commit
c485b19d52
@ -459,7 +459,8 @@ alloc_begin_fd_uobject(const struct uverbs_api_object *obj,
|
||||
struct ib_uobject *uobj;
|
||||
struct file *filp;
|
||||
|
||||
if (WARN_ON(fd_type->fops->release != &uverbs_uobject_fd_release))
|
||||
if (WARN_ON(fd_type->fops->release != &uverbs_uobject_fd_release &&
|
||||
fd_type->fops->release != &uverbs_async_event_release))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
new_fd = get_unused_fd_flags(O_CLOEXEC);
|
||||
|
@ -219,6 +219,7 @@ 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);
|
||||
|
@ -346,7 +346,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_uobject_fd_release,
|
||||
.release = uverbs_async_event_release,
|
||||
.fasync = ib_uverbs_async_event_fasync,
|
||||
.llseek = no_llseek,
|
||||
};
|
||||
|
@ -26,10 +26,34 @@ static int uverbs_async_event_destroy_uobj(struct ib_uobject *uobj,
|
||||
container_of(uobj, struct ib_uverbs_async_event_file, uobj);
|
||||
|
||||
ib_unregister_event_handler(&event_file->event_handler);
|
||||
ib_uverbs_free_event_queue(&event_file->ev_queue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uverbs_async_event_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
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);
|
||||
|
||||
/*
|
||||
* The async event FD has to deliver IB_EVENT_DEVICE_FATAL even after
|
||||
* disassociation, so cleaning the event list must only happen after
|
||||
* 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(
|
||||
UVERBS_METHOD_ASYNC_EVENT_ALLOC,
|
||||
UVERBS_ATTR_FD(UVERBS_ATTR_ASYNC_EVENT_ALLOC_FD_HANDLE,
|
||||
|
Loading…
x
Reference in New Issue
Block a user