RDMA/core: Fix locking in ib_uverbs_event_read
commit 14e23bd6d22123f6f3b2747701fa6cd4c6d05873 upstream.
This should not be using ib_dev to test for disassociation, during
disassociation is_closed is set under lock and the waitq is triggered.
Instead check is_closed and be sure to re-obtain the lock to test the
value after the wait_event returns.
Fixes: 036b106357
("IB/uverbs: Enable device removal when there are active user space applications")
Link: https://lore.kernel.org/r/1578504126-9400-12-git-send-email-yishaih@mellanox.com
Signed-off-by: Yishai Hadas <yishaih@mellanox.com>
Reviewed-by: Håkon Bugge <haakon.bugge@oracle.com>
Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
ab40fc36d6
commit
14d37518a9
1 changed files with 15 additions and 19 deletions
|
@ -273,7 +273,6 @@ void ib_uverbs_release_file(struct kref *ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t ib_uverbs_event_read(struct ib_uverbs_event_queue *ev_queue,
|
static ssize_t ib_uverbs_event_read(struct ib_uverbs_event_queue *ev_queue,
|
||||||
struct ib_uverbs_file *uverbs_file,
|
|
||||||
struct file *filp, char __user *buf,
|
struct file *filp, char __user *buf,
|
||||||
size_t count, loff_t *pos,
|
size_t count, loff_t *pos,
|
||||||
size_t eventsz)
|
size_t eventsz)
|
||||||
|
@ -291,19 +290,16 @@ static ssize_t ib_uverbs_event_read(struct ib_uverbs_event_queue *ev_queue,
|
||||||
|
|
||||||
if (wait_event_interruptible(ev_queue->poll_wait,
|
if (wait_event_interruptible(ev_queue->poll_wait,
|
||||||
(!list_empty(&ev_queue->event_list) ||
|
(!list_empty(&ev_queue->event_list) ||
|
||||||
/* The barriers built into wait_event_interruptible()
|
ev_queue->is_closed)))
|
||||||
* and wake_up() guarentee this will see the null set
|
|
||||||
* without using RCU
|
|
||||||
*/
|
|
||||||
!uverbs_file->device->ib_dev)))
|
|
||||||
return -ERESTARTSYS;
|
return -ERESTARTSYS;
|
||||||
|
|
||||||
/* If device was disassociated and no event exists set an error */
|
|
||||||
if (list_empty(&ev_queue->event_list) &&
|
|
||||||
!uverbs_file->device->ib_dev)
|
|
||||||
return -EIO;
|
|
||||||
|
|
||||||
spin_lock_irq(&ev_queue->lock);
|
spin_lock_irq(&ev_queue->lock);
|
||||||
|
|
||||||
|
/* If device was disassociated and no event exists set an error */
|
||||||
|
if (list_empty(&ev_queue->event_list) && ev_queue->is_closed) {
|
||||||
|
spin_unlock_irq(&ev_queue->lock);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
event = list_entry(ev_queue->event_list.next, struct ib_uverbs_event, list);
|
event = list_entry(ev_queue->event_list.next, struct ib_uverbs_event, list);
|
||||||
|
@ -338,8 +334,7 @@ static ssize_t ib_uverbs_async_event_read(struct file *filp, char __user *buf,
|
||||||
{
|
{
|
||||||
struct ib_uverbs_async_event_file *file = filp->private_data;
|
struct ib_uverbs_async_event_file *file = filp->private_data;
|
||||||
|
|
||||||
return ib_uverbs_event_read(&file->ev_queue, file->uverbs_file, filp,
|
return ib_uverbs_event_read(&file->ev_queue, filp, buf, count, pos,
|
||||||
buf, count, pos,
|
|
||||||
sizeof(struct ib_uverbs_async_event_desc));
|
sizeof(struct ib_uverbs_async_event_desc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,9 +344,8 @@ static ssize_t ib_uverbs_comp_event_read(struct file *filp, char __user *buf,
|
||||||
struct ib_uverbs_completion_event_file *comp_ev_file =
|
struct ib_uverbs_completion_event_file *comp_ev_file =
|
||||||
filp->private_data;
|
filp->private_data;
|
||||||
|
|
||||||
return ib_uverbs_event_read(&comp_ev_file->ev_queue,
|
return ib_uverbs_event_read(&comp_ev_file->ev_queue, filp, buf, count,
|
||||||
comp_ev_file->uobj.ufile, filp,
|
pos,
|
||||||
buf, count, pos,
|
|
||||||
sizeof(struct ib_uverbs_comp_event_desc));
|
sizeof(struct ib_uverbs_comp_event_desc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,7 +368,9 @@ static __poll_t ib_uverbs_event_poll(struct ib_uverbs_event_queue *ev_queue,
|
||||||
static __poll_t ib_uverbs_async_event_poll(struct file *filp,
|
static __poll_t ib_uverbs_async_event_poll(struct file *filp,
|
||||||
struct poll_table_struct *wait)
|
struct poll_table_struct *wait)
|
||||||
{
|
{
|
||||||
return ib_uverbs_event_poll(filp->private_data, filp, wait);
|
struct ib_uverbs_async_event_file *file = filp->private_data;
|
||||||
|
|
||||||
|
return ib_uverbs_event_poll(&file->ev_queue, filp, wait);
|
||||||
}
|
}
|
||||||
|
|
||||||
static __poll_t ib_uverbs_comp_event_poll(struct file *filp,
|
static __poll_t ib_uverbs_comp_event_poll(struct file *filp,
|
||||||
|
@ -388,9 +384,9 @@ static __poll_t ib_uverbs_comp_event_poll(struct file *filp,
|
||||||
|
|
||||||
static int ib_uverbs_async_event_fasync(int fd, struct file *filp, int on)
|
static int ib_uverbs_async_event_fasync(int fd, struct file *filp, int on)
|
||||||
{
|
{
|
||||||
struct ib_uverbs_event_queue *ev_queue = filp->private_data;
|
struct ib_uverbs_async_event_file *file = filp->private_data;
|
||||||
|
|
||||||
return fasync_helper(fd, filp, on, &ev_queue->async_queue);
|
return fasync_helper(fd, filp, on, &file->ev_queue.async_queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ib_uverbs_comp_event_fasync(int fd, struct file *filp, int on)
|
static int ib_uverbs_comp_event_fasync(int fd, struct file *filp, int on)
|
||||||
|
|
Loading…
Reference in a new issue