In ib_uverbs_event_read(), events are waited for, then pulled off the kernel's event queue, and finally returned to user space. There is an explicit check to see if the device is gone, and if so and the there are no events pending, an -EIO is returned. However, said test does not check for queue empty whilst holding the lock, so there is a race where the existing code perceives the queue to be empty, when it in fact isn't. Fixed by acquiring the lock ahead of the list_empty() test. Fixes: 036b10635739 ("IB/uverbs: Enable device removal when there are active user space applications") Signed-off-by: Håkon Bugge <haakon.bugge@xxxxxxxxxx> --- drivers/infiniband/core/uverbs_main.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 970d8e31dd65..7165e51790ed 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -245,12 +245,14 @@ static ssize_t ib_uverbs_event_read(struct ib_uverbs_event_queue *ev_queue, !uverbs_file->device->ib_dev))) return -ERESTARTSYS; + spin_lock_irq(&ev_queue->lock); + /* If device was disassociated and no event exists set an error */ if (list_empty(&ev_queue->event_list) && - !uverbs_file->device->ib_dev) + !uverbs_file->device->ib_dev) { + spin_unlock_irq(&ev_queue->lock); return -EIO; - - spin_lock_irq(&ev_queue->lock); + } } event = list_entry(ev_queue->event_list.next, struct ib_uverbs_event, list); -- 2.20.1