Commit 63673597 authored by Karsten Graul's avatar Karsten Graul Committed by David S. Miller

net/smc: protect smc ib device initialization

Before an smc ib device is used the first time for an smc link it is
lazily initialized. When there are 2 active link groups and a new ib
device is brought online then it might happen that 2 link creations run
in parallel and enter smc_ib_setup_per_ibdev(). Both allocate new send
and receive completion queues on the device, but only one set of them
keeps assigned and the other leaks.
Fix that by protecting the setup and cleanup code using a mutex.
Reviewed-by: default avatarUrsula Braun <ubraun@linux.ibm.com>
Fixes: f3c1dedd ("net/smc: separate function for link initialization")
Signed-off-by: default avatarKarsten Graul <kgraul@linux.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 7df8bcb5
...@@ -506,6 +506,10 @@ long smc_ib_setup_per_ibdev(struct smc_ib_device *smcibdev) ...@@ -506,6 +506,10 @@ long smc_ib_setup_per_ibdev(struct smc_ib_device *smcibdev)
int cqe_size_order, smc_order; int cqe_size_order, smc_order;
long rc; long rc;
mutex_lock(&smcibdev->mutex);
rc = 0;
if (smcibdev->initialized)
goto out;
/* the calculated number of cq entries fits to mlx5 cq allocation */ /* the calculated number of cq entries fits to mlx5 cq allocation */
cqe_size_order = cache_line_size() == 128 ? 7 : 6; cqe_size_order = cache_line_size() == 128 ? 7 : 6;
smc_order = MAX_ORDER - cqe_size_order - 1; smc_order = MAX_ORDER - cqe_size_order - 1;
...@@ -517,7 +521,7 @@ long smc_ib_setup_per_ibdev(struct smc_ib_device *smcibdev) ...@@ -517,7 +521,7 @@ long smc_ib_setup_per_ibdev(struct smc_ib_device *smcibdev)
rc = PTR_ERR_OR_ZERO(smcibdev->roce_cq_send); rc = PTR_ERR_OR_ZERO(smcibdev->roce_cq_send);
if (IS_ERR(smcibdev->roce_cq_send)) { if (IS_ERR(smcibdev->roce_cq_send)) {
smcibdev->roce_cq_send = NULL; smcibdev->roce_cq_send = NULL;
return rc; goto out;
} }
smcibdev->roce_cq_recv = ib_create_cq(smcibdev->ibdev, smcibdev->roce_cq_recv = ib_create_cq(smcibdev->ibdev,
smc_wr_rx_cq_handler, NULL, smc_wr_rx_cq_handler, NULL,
...@@ -529,21 +533,26 @@ long smc_ib_setup_per_ibdev(struct smc_ib_device *smcibdev) ...@@ -529,21 +533,26 @@ long smc_ib_setup_per_ibdev(struct smc_ib_device *smcibdev)
} }
smc_wr_add_dev(smcibdev); smc_wr_add_dev(smcibdev);
smcibdev->initialized = 1; smcibdev->initialized = 1;
return rc; goto out;
err: err:
ib_destroy_cq(smcibdev->roce_cq_send); ib_destroy_cq(smcibdev->roce_cq_send);
out:
mutex_unlock(&smcibdev->mutex);
return rc; return rc;
} }
static void smc_ib_cleanup_per_ibdev(struct smc_ib_device *smcibdev) static void smc_ib_cleanup_per_ibdev(struct smc_ib_device *smcibdev)
{ {
mutex_lock(&smcibdev->mutex);
if (!smcibdev->initialized) if (!smcibdev->initialized)
return; goto out;
smcibdev->initialized = 0; smcibdev->initialized = 0;
ib_destroy_cq(smcibdev->roce_cq_recv); ib_destroy_cq(smcibdev->roce_cq_recv);
ib_destroy_cq(smcibdev->roce_cq_send); ib_destroy_cq(smcibdev->roce_cq_send);
smc_wr_remove_dev(smcibdev); smc_wr_remove_dev(smcibdev);
out:
mutex_unlock(&smcibdev->mutex);
} }
static struct ib_client smc_ib_client; static struct ib_client smc_ib_client;
...@@ -566,6 +575,7 @@ static int smc_ib_add_dev(struct ib_device *ibdev) ...@@ -566,6 +575,7 @@ static int smc_ib_add_dev(struct ib_device *ibdev)
INIT_WORK(&smcibdev->port_event_work, smc_ib_port_event_work); INIT_WORK(&smcibdev->port_event_work, smc_ib_port_event_work);
atomic_set(&smcibdev->lnk_cnt, 0); atomic_set(&smcibdev->lnk_cnt, 0);
init_waitqueue_head(&smcibdev->lnks_deleted); init_waitqueue_head(&smcibdev->lnks_deleted);
mutex_init(&smcibdev->mutex);
mutex_lock(&smc_ib_devices.mutex); mutex_lock(&smc_ib_devices.mutex);
list_add_tail(&smcibdev->list, &smc_ib_devices.list); list_add_tail(&smcibdev->list, &smc_ib_devices.list);
mutex_unlock(&smc_ib_devices.mutex); mutex_unlock(&smc_ib_devices.mutex);
......
...@@ -52,6 +52,7 @@ struct smc_ib_device { /* ib-device infos for smc */ ...@@ -52,6 +52,7 @@ struct smc_ib_device { /* ib-device infos for smc */
DECLARE_BITMAP(ports_going_away, SMC_MAX_PORTS); DECLARE_BITMAP(ports_going_away, SMC_MAX_PORTS);
atomic_t lnk_cnt; /* number of links on ibdev */ atomic_t lnk_cnt; /* number of links on ibdev */
wait_queue_head_t lnks_deleted; /* wait 4 removal of all links*/ wait_queue_head_t lnks_deleted; /* wait 4 removal of all links*/
struct mutex mutex; /* protect dev setup+cleanup */
}; };
struct smc_buf_desc; struct smc_buf_desc;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment