lkml.org 
[lkml]   [2017]   [Jul]   [25]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.12 116/196] vfio: Fix group release deadlock
    Date
    4.12-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Alex Williamson <alex.williamson@redhat.com>

    commit 811642d8d8a82c0cce8dc2debfdaf23c5a144839 upstream.

    If vfio_iommu_group_notifier() acquires a group reference and that
    reference becomes the last reference to the group, then vfio_group_put
    introduces a deadlock code path where we're trying to unregister from
    the iommu notifier chain from within a callout of that chain. Use a
    work_struct to release this reference asynchronously.

    Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
    Reviewed-by: Eric Auger <eric.auger@redhat.com>
    Tested-by: Eric Auger <eric.auger@redhat.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    drivers/vfio/vfio.c | 37 ++++++++++++++++++++++++++++++++++++-
    1 file changed, 36 insertions(+), 1 deletion(-)

    --- a/drivers/vfio/vfio.c
    +++ b/drivers/vfio/vfio.c
    @@ -423,6 +423,34 @@ static void vfio_group_put(struct vfio_g
    kref_put_mutex(&group->kref, vfio_group_release, &vfio.group_lock);
    }

    +struct vfio_group_put_work {
    + struct work_struct work;
    + struct vfio_group *group;
    +};
    +
    +static void vfio_group_put_bg(struct work_struct *work)
    +{
    + struct vfio_group_put_work *do_work;
    +
    + do_work = container_of(work, struct vfio_group_put_work, work);
    +
    + vfio_group_put(do_work->group);
    + kfree(do_work);
    +}
    +
    +static void vfio_group_schedule_put(struct vfio_group *group)
    +{
    + struct vfio_group_put_work *do_work;
    +
    + do_work = kmalloc(sizeof(*do_work), GFP_KERNEL);
    + if (WARN_ON(!do_work))
    + return;
    +
    + INIT_WORK(&do_work->work, vfio_group_put_bg);
    + do_work->group = group;
    + schedule_work(&do_work->work);
    +}
    +
    /* Assume group_lock or group reference is held */
    static void vfio_group_get(struct vfio_group *group)
    {
    @@ -762,7 +790,14 @@ static int vfio_iommu_group_notifier(str
    break;
    }

    - vfio_group_put(group);
    + /*
    + * If we're the last reference to the group, the group will be
    + * released, which includes unregistering the iommu group notifier.
    + * We hold a read-lock on that notifier list, unregistering needs
    + * a write-lock... deadlock. Release our reference asynchronously
    + * to avoid that situation.
    + */
    + vfio_group_schedule_put(group);
    return NOTIFY_OK;
    }


    \
     
     \ /
      Last update: 2017-07-25 21:52    [W:2.251 / U:0.052 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site