]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
RDMA/core: Fix locking in ib_uverbs_event_read
authorJason Gunthorpe <jgg@mellanox.com>
Wed, 8 Jan 2020 17:22:03 +0000 (19:22 +0200)
committerKhalid Elmously <khalid.elmously@canonical.com>
Fri, 13 Mar 2020 04:31:00 +0000 (00:31 -0400)
BugLink: https://bugs.launchpad.net/bugs/1867194
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: 036b10635739 ("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>
Signed-off-by: Kamal Mostafa <kamal@canonical.com>
Signed-off-by: Khalid Elmously <khalid.elmously@canonical.com>
drivers/infiniband/core/uverbs_main.c

index 236537b6d3264f29b81f2d83f29756f90b5b387a..ccb962cca691d712a8a04e5602831b5e241b5cac 100644 (file)
@@ -260,7 +260,6 @@ void ib_uverbs_release_file(struct kref *ref)
 }
 
 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,
                                    size_t count, loff_t *pos,
                                    size_t eventsz)
@@ -278,19 +277,16 @@ static ssize_t ib_uverbs_event_read(struct ib_uverbs_event_queue *ev_queue,
 
                if (wait_event_interruptible(ev_queue->poll_wait,
                                             (!list_empty(&ev_queue->event_list) ||
-                       /* The barriers built into wait_event_interruptible()
-                        * and wake_up() guarentee this will see the null set
-                        * without using RCU
-                        */
-                                            !uverbs_file->device->ib_dev)))
+                                             ev_queue->is_closed)))
                        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)
+               if (list_empty(&ev_queue->event_list) && ev_queue->is_closed) {
+                       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);
@@ -325,8 +321,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;
 
-       return ib_uverbs_event_read(&file->ev_queue, file->uverbs_file, filp,
-                                   buf, count, pos,
+       return ib_uverbs_event_read(&file->ev_queue, filp, buf, count, pos,
                                    sizeof(struct ib_uverbs_async_event_desc));
 }
 
@@ -336,9 +331,8 @@ static ssize_t ib_uverbs_comp_event_read(struct file *filp, char __user *buf,
        struct ib_uverbs_completion_event_file *comp_ev_file =
                filp->private_data;
 
-       return ib_uverbs_event_read(&comp_ev_file->ev_queue,
-                                   comp_ev_file->uobj_file.ufile, filp,
-                                   buf, count, pos,
+       return ib_uverbs_event_read(&comp_ev_file->ev_queue, filp, buf, count,
+                                   pos,
                                    sizeof(struct ib_uverbs_comp_event_desc));
 }
 
@@ -361,7 +355,9 @@ static unsigned int ib_uverbs_event_poll(struct ib_uverbs_event_queue *ev_queue,
 static unsigned int ib_uverbs_async_event_poll(struct file *filp,
                                               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 unsigned int ib_uverbs_comp_event_poll(struct file *filp,
@@ -375,9 +371,9 @@ static unsigned int ib_uverbs_comp_event_poll(struct file *filp,
 
 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)