Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

RDMA/core: Fix bogus WARN_ON during ib_unregister_device_queued()

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>

+8 -3
+8 -3
drivers/infiniband/core/device.c
··· 1339 1339 return ret; 1340 1340 } 1341 1341 1342 + static void prevent_dealloc_device(struct ib_device *ib_dev) 1343 + { 1344 + } 1345 + 1342 1346 /** 1343 1347 * ib_register_device - Register an IB device with IB core 1344 1348 * @device: Device to register ··· 1413 1409 * possibility for a parallel unregistration along with this 1414 1410 * error flow. Since we have a refcount here we know any 1415 1411 * parallel flow is stopped in disable_device and will see the 1416 - * NULL pointers, causing the responsibility to 1412 + * special dealloc_driver pointer, causing the responsibility to 1417 1413 * ib_dealloc_device() to revert back to this thread. 1418 1414 */ 1419 1415 dealloc_fn = device->ops.dealloc_driver; 1420 - device->ops.dealloc_driver = NULL; 1416 + device->ops.dealloc_driver = prevent_dealloc_device; 1421 1417 ib_device_put(device); 1422 1418 __ib_unregister_device(device); 1423 1419 device->ops.dealloc_driver = dealloc_fn; ··· 1466 1462 * Drivers using the new flow may not call ib_dealloc_device except 1467 1463 * in error unwind prior to registration success. 1468 1464 */ 1469 - if (ib_dev->ops.dealloc_driver) { 1465 + if (ib_dev->ops.dealloc_driver && 1466 + ib_dev->ops.dealloc_driver != prevent_dealloc_device) { 1470 1467 WARN_ON(kref_read(&ib_dev->dev.kobj.kref) <= 1); 1471 1468 ib_dealloc_device(ib_dev); 1472 1469 }