mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2025-01-06 22:04:22 +08:00
RDMA/cma: Add missing error handling of listen_id
Don't silently continue if rdma_listen() fails but destroy previously
created CM_ID and return an error to the caller.
Fixes: d02d1f5359
("RDMA/cma: Fix deadlock destroying listen requests")
Link: https://lore.kernel.org/r/20201104144008.3808124-5-leon@kernel.org
Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
This commit is contained in:
parent
0413755c95
commit
c80a0c52d8
@ -2495,8 +2495,8 @@ static int cma_listen_handler(struct rdma_cm_id *id,
|
|||||||
return id_priv->id.event_handler(id, event);
|
return id_priv->id.event_handler(id, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cma_listen_on_dev(struct rdma_id_private *id_priv,
|
static int cma_listen_on_dev(struct rdma_id_private *id_priv,
|
||||||
struct cma_device *cma_dev)
|
struct cma_device *cma_dev)
|
||||||
{
|
{
|
||||||
struct rdma_id_private *dev_id_priv;
|
struct rdma_id_private *dev_id_priv;
|
||||||
struct net *net = id_priv->id.route.addr.dev_addr.net;
|
struct net *net = id_priv->id.route.addr.dev_addr.net;
|
||||||
@ -2505,13 +2505,13 @@ static void cma_listen_on_dev(struct rdma_id_private *id_priv,
|
|||||||
lockdep_assert_held(&lock);
|
lockdep_assert_held(&lock);
|
||||||
|
|
||||||
if (cma_family(id_priv) == AF_IB && !rdma_cap_ib_cm(cma_dev->device, 1))
|
if (cma_family(id_priv) == AF_IB && !rdma_cap_ib_cm(cma_dev->device, 1))
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
dev_id_priv =
|
dev_id_priv =
|
||||||
__rdma_create_id(net, cma_listen_handler, id_priv,
|
__rdma_create_id(net, cma_listen_handler, id_priv,
|
||||||
id_priv->id.ps, id_priv->id.qp_type, id_priv);
|
id_priv->id.ps, id_priv->id.qp_type, id_priv);
|
||||||
if (IS_ERR(dev_id_priv))
|
if (IS_ERR(dev_id_priv))
|
||||||
return;
|
return PTR_ERR(dev_id_priv);
|
||||||
|
|
||||||
dev_id_priv->state = RDMA_CM_ADDR_BOUND;
|
dev_id_priv->state = RDMA_CM_ADDR_BOUND;
|
||||||
memcpy(cma_src_addr(dev_id_priv), cma_src_addr(id_priv),
|
memcpy(cma_src_addr(dev_id_priv), cma_src_addr(id_priv),
|
||||||
@ -2527,19 +2527,34 @@ static void cma_listen_on_dev(struct rdma_id_private *id_priv,
|
|||||||
|
|
||||||
ret = rdma_listen(&dev_id_priv->id, id_priv->backlog);
|
ret = rdma_listen(&dev_id_priv->id, id_priv->backlog);
|
||||||
if (ret)
|
if (ret)
|
||||||
dev_warn(&cma_dev->device->dev,
|
goto err_listen;
|
||||||
"RDMA CMA: cma_listen_on_dev, error %d\n", ret);
|
return 0;
|
||||||
|
err_listen:
|
||||||
|
list_del(&id_priv->listen_list);
|
||||||
|
dev_warn(&cma_dev->device->dev, "RDMA CMA: %s, error %d\n", __func__, ret);
|
||||||
|
rdma_destroy_id(&dev_id_priv->id);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cma_listen_on_all(struct rdma_id_private *id_priv)
|
static int cma_listen_on_all(struct rdma_id_private *id_priv)
|
||||||
{
|
{
|
||||||
struct cma_device *cma_dev;
|
struct cma_device *cma_dev;
|
||||||
|
int ret;
|
||||||
|
|
||||||
mutex_lock(&lock);
|
mutex_lock(&lock);
|
||||||
list_add_tail(&id_priv->list, &listen_any_list);
|
list_add_tail(&id_priv->list, &listen_any_list);
|
||||||
list_for_each_entry(cma_dev, &dev_list, list)
|
list_for_each_entry(cma_dev, &dev_list, list) {
|
||||||
cma_listen_on_dev(id_priv, cma_dev);
|
ret = cma_listen_on_dev(id_priv, cma_dev);
|
||||||
|
if (ret)
|
||||||
|
goto err_listen;
|
||||||
|
}
|
||||||
mutex_unlock(&lock);
|
mutex_unlock(&lock);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_listen:
|
||||||
|
list_del(&id_priv->list);
|
||||||
|
mutex_unlock(&lock);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rdma_set_service_type(struct rdma_cm_id *id, int tos)
|
void rdma_set_service_type(struct rdma_cm_id *id, int tos)
|
||||||
@ -3692,8 +3707,11 @@ int rdma_listen(struct rdma_cm_id *id, int backlog)
|
|||||||
ret = -ENOSYS;
|
ret = -ENOSYS;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
} else
|
} else {
|
||||||
cma_listen_on_all(id_priv);
|
ret = cma_listen_on_all(id_priv);
|
||||||
|
if (ret)
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
err:
|
err:
|
||||||
@ -4745,69 +4763,6 @@ static struct notifier_block cma_nb = {
|
|||||||
.notifier_call = cma_netdev_callback
|
.notifier_call = cma_netdev_callback
|
||||||
};
|
};
|
||||||
|
|
||||||
static int cma_add_one(struct ib_device *device)
|
|
||||||
{
|
|
||||||
struct cma_device *cma_dev;
|
|
||||||
struct rdma_id_private *id_priv;
|
|
||||||
unsigned int i;
|
|
||||||
unsigned long supported_gids = 0;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
cma_dev = kmalloc(sizeof *cma_dev, GFP_KERNEL);
|
|
||||||
if (!cma_dev)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
cma_dev->device = device;
|
|
||||||
cma_dev->default_gid_type = kcalloc(device->phys_port_cnt,
|
|
||||||
sizeof(*cma_dev->default_gid_type),
|
|
||||||
GFP_KERNEL);
|
|
||||||
if (!cma_dev->default_gid_type) {
|
|
||||||
ret = -ENOMEM;
|
|
||||||
goto free_cma_dev;
|
|
||||||
}
|
|
||||||
|
|
||||||
cma_dev->default_roce_tos = kcalloc(device->phys_port_cnt,
|
|
||||||
sizeof(*cma_dev->default_roce_tos),
|
|
||||||
GFP_KERNEL);
|
|
||||||
if (!cma_dev->default_roce_tos) {
|
|
||||||
ret = -ENOMEM;
|
|
||||||
goto free_gid_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
rdma_for_each_port (device, i) {
|
|
||||||
supported_gids = roce_gid_type_mask_support(device, i);
|
|
||||||
WARN_ON(!supported_gids);
|
|
||||||
if (supported_gids & (1 << CMA_PREFERRED_ROCE_GID_TYPE))
|
|
||||||
cma_dev->default_gid_type[i - rdma_start_port(device)] =
|
|
||||||
CMA_PREFERRED_ROCE_GID_TYPE;
|
|
||||||
else
|
|
||||||
cma_dev->default_gid_type[i - rdma_start_port(device)] =
|
|
||||||
find_first_bit(&supported_gids, BITS_PER_LONG);
|
|
||||||
cma_dev->default_roce_tos[i - rdma_start_port(device)] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
init_completion(&cma_dev->comp);
|
|
||||||
refcount_set(&cma_dev->refcount, 1);
|
|
||||||
INIT_LIST_HEAD(&cma_dev->id_list);
|
|
||||||
ib_set_client_data(device, &cma_client, cma_dev);
|
|
||||||
|
|
||||||
mutex_lock(&lock);
|
|
||||||
list_add_tail(&cma_dev->list, &dev_list);
|
|
||||||
list_for_each_entry(id_priv, &listen_any_list, list)
|
|
||||||
cma_listen_on_dev(id_priv, cma_dev);
|
|
||||||
mutex_unlock(&lock);
|
|
||||||
|
|
||||||
trace_cm_add_one(device);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
free_gid_type:
|
|
||||||
kfree(cma_dev->default_gid_type);
|
|
||||||
|
|
||||||
free_cma_dev:
|
|
||||||
kfree(cma_dev);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cma_send_device_removal_put(struct rdma_id_private *id_priv)
|
static void cma_send_device_removal_put(struct rdma_id_private *id_priv)
|
||||||
{
|
{
|
||||||
struct rdma_cm_event event = { .event = RDMA_CM_EVENT_DEVICE_REMOVAL };
|
struct rdma_cm_event event = { .event = RDMA_CM_EVENT_DEVICE_REMOVAL };
|
||||||
@ -4870,6 +4825,78 @@ static void cma_process_remove(struct cma_device *cma_dev)
|
|||||||
wait_for_completion(&cma_dev->comp);
|
wait_for_completion(&cma_dev->comp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int cma_add_one(struct ib_device *device)
|
||||||
|
{
|
||||||
|
struct cma_device *cma_dev;
|
||||||
|
struct rdma_id_private *id_priv;
|
||||||
|
unsigned int i;
|
||||||
|
unsigned long supported_gids = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
cma_dev = kmalloc(sizeof(*cma_dev), GFP_KERNEL);
|
||||||
|
if (!cma_dev)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
cma_dev->device = device;
|
||||||
|
cma_dev->default_gid_type = kcalloc(device->phys_port_cnt,
|
||||||
|
sizeof(*cma_dev->default_gid_type),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!cma_dev->default_gid_type) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto free_cma_dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
cma_dev->default_roce_tos = kcalloc(device->phys_port_cnt,
|
||||||
|
sizeof(*cma_dev->default_roce_tos),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!cma_dev->default_roce_tos) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto free_gid_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
rdma_for_each_port (device, i) {
|
||||||
|
supported_gids = roce_gid_type_mask_support(device, i);
|
||||||
|
WARN_ON(!supported_gids);
|
||||||
|
if (supported_gids & (1 << CMA_PREFERRED_ROCE_GID_TYPE))
|
||||||
|
cma_dev->default_gid_type[i - rdma_start_port(device)] =
|
||||||
|
CMA_PREFERRED_ROCE_GID_TYPE;
|
||||||
|
else
|
||||||
|
cma_dev->default_gid_type[i - rdma_start_port(device)] =
|
||||||
|
find_first_bit(&supported_gids, BITS_PER_LONG);
|
||||||
|
cma_dev->default_roce_tos[i - rdma_start_port(device)] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
init_completion(&cma_dev->comp);
|
||||||
|
refcount_set(&cma_dev->refcount, 1);
|
||||||
|
INIT_LIST_HEAD(&cma_dev->id_list);
|
||||||
|
ib_set_client_data(device, &cma_client, cma_dev);
|
||||||
|
|
||||||
|
mutex_lock(&lock);
|
||||||
|
list_add_tail(&cma_dev->list, &dev_list);
|
||||||
|
list_for_each_entry(id_priv, &listen_any_list, list) {
|
||||||
|
ret = cma_listen_on_dev(id_priv, cma_dev);
|
||||||
|
if (ret)
|
||||||
|
goto free_listen;
|
||||||
|
}
|
||||||
|
mutex_unlock(&lock);
|
||||||
|
|
||||||
|
trace_cm_add_one(device);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
free_listen:
|
||||||
|
list_del(&cma_dev->list);
|
||||||
|
mutex_unlock(&lock);
|
||||||
|
|
||||||
|
cma_process_remove(cma_dev);
|
||||||
|
kfree(cma_dev->default_roce_tos);
|
||||||
|
free_gid_type:
|
||||||
|
kfree(cma_dev->default_gid_type);
|
||||||
|
|
||||||
|
free_cma_dev:
|
||||||
|
kfree(cma_dev);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static void cma_remove_one(struct ib_device *device, void *client_data)
|
static void cma_remove_one(struct ib_device *device, void *client_data)
|
||||||
{
|
{
|
||||||
struct cma_device *cma_dev = client_data;
|
struct cma_device *cma_dev = client_data;
|
||||||
|
Loading…
Reference in New Issue
Block a user