When the driver needs to dynamically allocate char device numbers in systems with more than IB_UVERBS_MAX_DEVICES devices, it releases map lock, allocates a new range and a new device number from that range, and only then re-acquires the lock. This must be protected for the same reasoning that the map_lock spinlock is used. Without protecting we could also end up calling alloc_chrdev_region() a nubmer of times and cause a leakage. Fix this by replacing map_lock with a mutex and apply on the all the allocation code.
Signed-off-by: Eli Cohen <e...@mellanox.co.il> --- Changes from previous version: Protect with the mutex the clear_bit on the map allocations. drivers/infiniband/core/uverbs_main.c | 16 ++++++++++------ 1 files changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index d805cf3..a16d90d 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -72,7 +72,7 @@ DEFINE_IDR(ib_uverbs_cq_idr); DEFINE_IDR(ib_uverbs_qp_idr); DEFINE_IDR(ib_uverbs_srq_idr); -static DEFINE_SPINLOCK(map_lock); +static DEFINE_MUTEX(map_lock); static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES); static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file, @@ -738,15 +738,15 @@ static void ib_uverbs_add_one(struct ib_device *device) kref_init(&uverbs_dev->ref); init_completion(&uverbs_dev->comp); - spin_lock(&map_lock); + mutex_lock(&map_lock); devnum = find_first_zero_bit(dev_map, IB_UVERBS_MAX_DEVICES); if (devnum >= IB_UVERBS_MAX_DEVICES) { - spin_unlock(&map_lock); devnum = find_overflow_devnum(); - if (devnum < 0) + if (devnum < 0) { + mutex_unlock(&map_lock); goto err; + } - spin_lock(&map_lock); uverbs_dev->devnum = devnum + IB_UVERBS_MAX_DEVICES; base = devnum + overflow_maj; set_bit(devnum, overflow_map); @@ -755,7 +755,7 @@ static void ib_uverbs_add_one(struct ib_device *device) base = devnum + IB_UVERBS_BASE_DEV; set_bit(devnum, dev_map); } - spin_unlock(&map_lock); + mutex_unlock(&map_lock); uverbs_dev->ib_dev = device; uverbs_dev->num_comp_vectors = device->num_comp_vectors; @@ -787,10 +787,12 @@ err_class: err_cdev: cdev_del(&uverbs_dev->cdev); + mutex_lock(&map_lock); if (uverbs_dev->devnum < IB_UVERBS_MAX_DEVICES) clear_bit(devnum, dev_map); else clear_bit(devnum, overflow_map); + mutex_unlock(&map_lock); err: kref_put(&uverbs_dev->ref, ib_uverbs_release_dev); @@ -810,10 +812,12 @@ static void ib_uverbs_remove_one(struct ib_device *device) device_destroy(uverbs_class, uverbs_dev->cdev.dev); cdev_del(&uverbs_dev->cdev); + mutex_lock(&map_lock); if (uverbs_dev->devnum < IB_UVERBS_MAX_DEVICES) clear_bit(uverbs_dev->devnum, dev_map); else clear_bit(uverbs_dev->devnum - IB_UVERBS_MAX_DEVICES, overflow_map); + mutex_unlock(&map_lock); kref_put(&uverbs_dev->ref, ib_uverbs_release_dev); wait_for_completion(&uverbs_dev->comp); -- 1.7.0.3 -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html