lkml.org 
[lkml]   [2020]   [Aug]   [17]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.8 200/464] RDMA/core: Fix bogus WARN_ON during ib_unregister_device_queued()
    Date
    From: Jason Gunthorpe <jgg@nvidia.com>

    [ Upstream commit 0cb42c0265837fafa2b4f302c8a7fed2631d7869 ]

    ib_unregister_device_queued() can only be used by drivers using the new
    dealloc_device callback flow, and it has a safety WARN_ON to ensure
    drivers are using it properly.

    However, if unregister and register are raced there is a special
    destruction path that maintains the uniform error handling semantic of
    'caller does ib_dealloc_device() on failure'. This requires disabling the
    dealloc_device callback which triggers the WARN_ON.

    Instead of using NULL to disable the callback use a special function
    pointer so the WARN_ON does not trigger.

    Fixes: d0899892edd0 ("RDMA/device: Provide APIs from the core code to help unregistration")
    Link: https://lore.kernel.org/r/0-v1-a36d512e0a99+762-syz_dealloc_driver_jgg@nvidia.com
    Reported-by: syzbot+4088ed905e4ae2b0e13b@syzkaller.appspotmail.com
    Suggested-by: Hillf Danton <hdanton@sina.com>
    Reviewed-by: Leon Romanovsky <leonro@mellanox.com>
    Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    drivers/infiniband/core/device.c | 11 ++++++++---
    1 file changed, 8 insertions(+), 3 deletions(-)

    diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c
    index 905a2beaf8850..eadba29432dd7 100644
    --- a/drivers/infiniband/core/device.c
    +++ b/drivers/infiniband/core/device.c
    @@ -1339,6 +1339,10 @@ static int enable_device_and_get(struct ib_device *device)
    return ret;
    }

    +static void prevent_dealloc_device(struct ib_device *ib_dev)
    +{
    +}
    +
    /**
    * ib_register_device - Register an IB device with IB core
    * @device: Device to register
    @@ -1409,11 +1413,11 @@ int ib_register_device(struct ib_device *device, const char *name)
    * possibility for a parallel unregistration along with this
    * error flow. Since we have a refcount here we know any
    * parallel flow is stopped in disable_device and will see the
    - * NULL pointers, causing the responsibility to
    + * special dealloc_driver pointer, causing the responsibility to
    * ib_dealloc_device() to revert back to this thread.
    */
    dealloc_fn = device->ops.dealloc_driver;
    - device->ops.dealloc_driver = NULL;
    + device->ops.dealloc_driver = prevent_dealloc_device;
    ib_device_put(device);
    __ib_unregister_device(device);
    device->ops.dealloc_driver = dealloc_fn;
    @@ -1462,7 +1466,8 @@ static void __ib_unregister_device(struct ib_device *ib_dev)
    * Drivers using the new flow may not call ib_dealloc_device except
    * in error unwind prior to registration success.
    */
    - if (ib_dev->ops.dealloc_driver) {
    + if (ib_dev->ops.dealloc_driver &&
    + ib_dev->ops.dealloc_driver != prevent_dealloc_device) {
    WARN_ON(kref_read(&ib_dev->dev.kobj.kref) <= 1);
    ib_dealloc_device(ib_dev);
    }
    --
    2.25.1


    \
     
     \ /
      Last update: 2020-08-17 21:36    [W:6.581 / U:0.588 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site