lkml.org 
[lkml]   [2020]   [Feb]   [14]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH AUTOSEL 5.5 314/542] RDMA/core: Fix locking in ib_uverbs_event_read
    Date
    From: Jason Gunthorpe <jgg@mellanox.com>

    [ Upstream commit 14e23bd6d22123f6f3b2747701fa6cd4c6d05873 ]

    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: Sasha Levin <sashal@kernel.org>
    ---
    drivers/infiniband/core/uverbs_main.c | 32 ++++++++++++---------------
    1 file changed, 14 insertions(+), 18 deletions(-)

    diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
    index 970d8e31dd658..8f5de4dcad97c 100644
    --- a/drivers/infiniband/core/uverbs_main.c
    +++ b/drivers/infiniband/core/uverbs_main.c
    @@ -220,7 +220,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)
    @@ -238,19 +237,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);
    @@ -285,8 +281,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));
    }

    @@ -296,9 +291,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.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));
    }

    @@ -321,7 +315,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,
    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,
    @@ -335,9 +331,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)
    {
    - 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)
    --
    2.20.1
    \
     
     \ /
      Last update: 2020-02-14 16:56    [W:4.020 / U:8.492 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site