Commit d89b9f50 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma

Pull rdma fixes from Jason Gunthorpe:
 "It has been fairly silent lately on our -rc front. Big queue of
  patches on the mailing list going to for-next though.

  Bug fixes:
   - qedr driver bugfixes causing application hangs, wrong uapi errnos,
     and a race condition
   - three syzkaller found bugfixes in the ucma uapi

  Regression fixes for things introduced in 4.16:
   - Crash on error introduced in mlx5 UMR flow
   - Crash on module unload/etc introduced by bad interaction of
     restrack and mlx5 patches this cycle
   - Typo in a two line syzkaller bugfix causing a bad regression
   - Coverity report of nonsense code in hns driver"

* tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma:
  RDMA/ucma: Introduce safer rdma_addr_size() variants
  RDMA/hns: ensure for-loop actually iterates and free's buffers
  RDMA/ucma: Check that device exists prior to accessing it
  RDMA/ucma: Check that device is connected prior to access it
  RDMA/rdma_cm: Fix use after free race with process_one_req
  RDMA/qedr: Fix QP state initialization race
  RDMA/qedr: Fix rc initialization on CNQ allocation failure
  RDMA/qedr: fix QP's ack timeout configuration
  RDMA/ucma: Correct option size check using optlen
  RDMA/restrack: Move restrack_clean to be symmetrical to restrack_init
  IB/mlx5: Don't clean uninitialized UMR resources
parents ab12762b 84652aef
...@@ -207,6 +207,22 @@ int rdma_addr_size(struct sockaddr *addr) ...@@ -207,6 +207,22 @@ int rdma_addr_size(struct sockaddr *addr)
} }
EXPORT_SYMBOL(rdma_addr_size); EXPORT_SYMBOL(rdma_addr_size);
int rdma_addr_size_in6(struct sockaddr_in6 *addr)
{
int ret = rdma_addr_size((struct sockaddr *) addr);
return ret <= sizeof(*addr) ? ret : 0;
}
EXPORT_SYMBOL(rdma_addr_size_in6);
int rdma_addr_size_kss(struct __kernel_sockaddr_storage *addr)
{
int ret = rdma_addr_size((struct sockaddr *) addr);
return ret <= sizeof(*addr) ? ret : 0;
}
EXPORT_SYMBOL(rdma_addr_size_kss);
static struct rdma_addr_client self; static struct rdma_addr_client self;
void rdma_addr_register_client(struct rdma_addr_client *client) void rdma_addr_register_client(struct rdma_addr_client *client)
...@@ -586,6 +602,15 @@ static void process_one_req(struct work_struct *_work) ...@@ -586,6 +602,15 @@ static void process_one_req(struct work_struct *_work)
list_del(&req->list); list_del(&req->list);
mutex_unlock(&lock); mutex_unlock(&lock);
/*
* Although the work will normally have been canceled by the
* workqueue, it can still be requeued as long as it is on the
* req_list, so it could have been requeued before we grabbed &lock.
* We need to cancel it after it is removed from req_list to really be
* sure it is safe to free.
*/
cancel_delayed_work(&req->work);
req->callback(req->status, (struct sockaddr *)&req->src_addr, req->callback(req->status, (struct sockaddr *)&req->src_addr,
req->addr, req->context); req->addr, req->context);
put_client(req->client); put_client(req->client);
......
...@@ -290,6 +290,7 @@ void ib_dealloc_device(struct ib_device *device) ...@@ -290,6 +290,7 @@ void ib_dealloc_device(struct ib_device *device)
{ {
WARN_ON(device->reg_state != IB_DEV_UNREGISTERED && WARN_ON(device->reg_state != IB_DEV_UNREGISTERED &&
device->reg_state != IB_DEV_UNINITIALIZED); device->reg_state != IB_DEV_UNINITIALIZED);
rdma_restrack_clean(&device->res);
put_device(&device->dev); put_device(&device->dev);
} }
EXPORT_SYMBOL(ib_dealloc_device); EXPORT_SYMBOL(ib_dealloc_device);
...@@ -600,8 +601,6 @@ void ib_unregister_device(struct ib_device *device) ...@@ -600,8 +601,6 @@ void ib_unregister_device(struct ib_device *device)
} }
up_read(&lists_rwsem); up_read(&lists_rwsem);
rdma_restrack_clean(&device->res);
ib_device_unregister_rdmacg(device); ib_device_unregister_rdmacg(device);
ib_device_unregister_sysfs(device); ib_device_unregister_sysfs(device);
......
...@@ -632,6 +632,9 @@ static ssize_t ucma_bind_ip(struct ucma_file *file, const char __user *inbuf, ...@@ -632,6 +632,9 @@ static ssize_t ucma_bind_ip(struct ucma_file *file, const char __user *inbuf,
if (copy_from_user(&cmd, inbuf, sizeof(cmd))) if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
return -EFAULT; return -EFAULT;
if (!rdma_addr_size_in6(&cmd.addr))
return -EINVAL;
ctx = ucma_get_ctx(file, cmd.id); ctx = ucma_get_ctx(file, cmd.id);
if (IS_ERR(ctx)) if (IS_ERR(ctx))
return PTR_ERR(ctx); return PTR_ERR(ctx);
...@@ -645,22 +648,21 @@ static ssize_t ucma_bind(struct ucma_file *file, const char __user *inbuf, ...@@ -645,22 +648,21 @@ static ssize_t ucma_bind(struct ucma_file *file, const char __user *inbuf,
int in_len, int out_len) int in_len, int out_len)
{ {
struct rdma_ucm_bind cmd; struct rdma_ucm_bind cmd;
struct sockaddr *addr;
struct ucma_context *ctx; struct ucma_context *ctx;
int ret; int ret;
if (copy_from_user(&cmd, inbuf, sizeof(cmd))) if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
return -EFAULT; return -EFAULT;
addr = (struct sockaddr *) &cmd.addr; if (cmd.reserved || !cmd.addr_size ||
if (cmd.reserved || !cmd.addr_size || (cmd.addr_size != rdma_addr_size(addr))) cmd.addr_size != rdma_addr_size_kss(&cmd.addr))
return -EINVAL; return -EINVAL;
ctx = ucma_get_ctx(file, cmd.id); ctx = ucma_get_ctx(file, cmd.id);
if (IS_ERR(ctx)) if (IS_ERR(ctx))
return PTR_ERR(ctx); return PTR_ERR(ctx);
ret = rdma_bind_addr(ctx->cm_id, addr); ret = rdma_bind_addr(ctx->cm_id, (struct sockaddr *) &cmd.addr);
ucma_put_ctx(ctx); ucma_put_ctx(ctx);
return ret; return ret;
} }
...@@ -670,23 +672,22 @@ static ssize_t ucma_resolve_ip(struct ucma_file *file, ...@@ -670,23 +672,22 @@ static ssize_t ucma_resolve_ip(struct ucma_file *file,
int in_len, int out_len) int in_len, int out_len)
{ {
struct rdma_ucm_resolve_ip cmd; struct rdma_ucm_resolve_ip cmd;
struct sockaddr *src, *dst;
struct ucma_context *ctx; struct ucma_context *ctx;
int ret; int ret;
if (copy_from_user(&cmd, inbuf, sizeof(cmd))) if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
return -EFAULT; return -EFAULT;
src = (struct sockaddr *) &cmd.src_addr; if (!rdma_addr_size_in6(&cmd.src_addr) ||
dst = (struct sockaddr *) &cmd.dst_addr; !rdma_addr_size_in6(&cmd.dst_addr))
if (!rdma_addr_size(src) || !rdma_addr_size(dst))
return -EINVAL; return -EINVAL;
ctx = ucma_get_ctx(file, cmd.id); ctx = ucma_get_ctx(file, cmd.id);
if (IS_ERR(ctx)) if (IS_ERR(ctx))
return PTR_ERR(ctx); return PTR_ERR(ctx);
ret = rdma_resolve_addr(ctx->cm_id, src, dst, cmd.timeout_ms); ret = rdma_resolve_addr(ctx->cm_id, (struct sockaddr *) &cmd.src_addr,
(struct sockaddr *) &cmd.dst_addr, cmd.timeout_ms);
ucma_put_ctx(ctx); ucma_put_ctx(ctx);
return ret; return ret;
} }
...@@ -696,24 +697,23 @@ static ssize_t ucma_resolve_addr(struct ucma_file *file, ...@@ -696,24 +697,23 @@ static ssize_t ucma_resolve_addr(struct ucma_file *file,
int in_len, int out_len) int in_len, int out_len)
{ {
struct rdma_ucm_resolve_addr cmd; struct rdma_ucm_resolve_addr cmd;
struct sockaddr *src, *dst;
struct ucma_context *ctx; struct ucma_context *ctx;
int ret; int ret;
if (copy_from_user(&cmd, inbuf, sizeof(cmd))) if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
return -EFAULT; return -EFAULT;
src = (struct sockaddr *) &cmd.src_addr; if (cmd.reserved ||
dst = (struct sockaddr *) &cmd.dst_addr; (cmd.src_size && (cmd.src_size != rdma_addr_size_kss(&cmd.src_addr))) ||
if (cmd.reserved || (cmd.src_size && (cmd.src_size != rdma_addr_size(src))) || !cmd.dst_size || (cmd.dst_size != rdma_addr_size_kss(&cmd.dst_addr)))
!cmd.dst_size || (cmd.dst_size != rdma_addr_size(dst)))
return -EINVAL; return -EINVAL;
ctx = ucma_get_ctx(file, cmd.id); ctx = ucma_get_ctx(file, cmd.id);
if (IS_ERR(ctx)) if (IS_ERR(ctx))
return PTR_ERR(ctx); return PTR_ERR(ctx);
ret = rdma_resolve_addr(ctx->cm_id, src, dst, cmd.timeout_ms); ret = rdma_resolve_addr(ctx->cm_id, (struct sockaddr *) &cmd.src_addr,
(struct sockaddr *) &cmd.dst_addr, cmd.timeout_ms);
ucma_put_ctx(ctx); ucma_put_ctx(ctx);
return ret; return ret;
} }
...@@ -1166,6 +1166,11 @@ static ssize_t ucma_init_qp_attr(struct ucma_file *file, ...@@ -1166,6 +1166,11 @@ static ssize_t ucma_init_qp_attr(struct ucma_file *file,
if (IS_ERR(ctx)) if (IS_ERR(ctx))
return PTR_ERR(ctx); return PTR_ERR(ctx);
if (!ctx->cm_id->device) {
ret = -EINVAL;
goto out;
}
resp.qp_attr_mask = 0; resp.qp_attr_mask = 0;
memset(&qp_attr, 0, sizeof qp_attr); memset(&qp_attr, 0, sizeof qp_attr);
qp_attr.qp_state = cmd.qp_state; qp_attr.qp_state = cmd.qp_state;
...@@ -1307,7 +1312,7 @@ static ssize_t ucma_set_option(struct ucma_file *file, const char __user *inbuf, ...@@ -1307,7 +1312,7 @@ static ssize_t ucma_set_option(struct ucma_file *file, const char __user *inbuf,
if (IS_ERR(ctx)) if (IS_ERR(ctx))
return PTR_ERR(ctx); return PTR_ERR(ctx);
if (unlikely(cmd.optval > KMALLOC_MAX_SIZE)) if (unlikely(cmd.optlen > KMALLOC_MAX_SIZE))
return -EINVAL; return -EINVAL;
optval = memdup_user((void __user *) (unsigned long) cmd.optval, optval = memdup_user((void __user *) (unsigned long) cmd.optval,
...@@ -1331,7 +1336,7 @@ static ssize_t ucma_notify(struct ucma_file *file, const char __user *inbuf, ...@@ -1331,7 +1336,7 @@ static ssize_t ucma_notify(struct ucma_file *file, const char __user *inbuf,
{ {
struct rdma_ucm_notify cmd; struct rdma_ucm_notify cmd;
struct ucma_context *ctx; struct ucma_context *ctx;
int ret; int ret = -EINVAL;
if (copy_from_user(&cmd, inbuf, sizeof(cmd))) if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
return -EFAULT; return -EFAULT;
...@@ -1340,7 +1345,9 @@ static ssize_t ucma_notify(struct ucma_file *file, const char __user *inbuf, ...@@ -1340,7 +1345,9 @@ static ssize_t ucma_notify(struct ucma_file *file, const char __user *inbuf,
if (IS_ERR(ctx)) if (IS_ERR(ctx))
return PTR_ERR(ctx); return PTR_ERR(ctx);
ret = rdma_notify(ctx->cm_id, (enum ib_event_type) cmd.event); if (ctx->cm_id->device)
ret = rdma_notify(ctx->cm_id, (enum ib_event_type)cmd.event);
ucma_put_ctx(ctx); ucma_put_ctx(ctx);
return ret; return ret;
} }
...@@ -1426,7 +1433,7 @@ static ssize_t ucma_join_ip_multicast(struct ucma_file *file, ...@@ -1426,7 +1433,7 @@ static ssize_t ucma_join_ip_multicast(struct ucma_file *file,
join_cmd.response = cmd.response; join_cmd.response = cmd.response;
join_cmd.uid = cmd.uid; join_cmd.uid = cmd.uid;
join_cmd.id = cmd.id; join_cmd.id = cmd.id;
join_cmd.addr_size = rdma_addr_size((struct sockaddr *) &cmd.addr); join_cmd.addr_size = rdma_addr_size_in6(&cmd.addr);
if (!join_cmd.addr_size) if (!join_cmd.addr_size)
return -EINVAL; return -EINVAL;
...@@ -1445,7 +1452,7 @@ static ssize_t ucma_join_multicast(struct ucma_file *file, ...@@ -1445,7 +1452,7 @@ static ssize_t ucma_join_multicast(struct ucma_file *file,
if (copy_from_user(&cmd, inbuf, sizeof(cmd))) if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
return -EFAULT; return -EFAULT;
if (!rdma_addr_size((struct sockaddr *)&cmd.addr)) if (!rdma_addr_size_kss(&cmd.addr))
return -EINVAL; return -EINVAL;
return ucma_process_join(file, &cmd, out_len); return ucma_process_join(file, &cmd, out_len);
......
...@@ -4383,7 +4383,7 @@ static int hns_roce_mhop_alloc_eq(struct hns_roce_dev *hr_dev, ...@@ -4383,7 +4383,7 @@ static int hns_roce_mhop_alloc_eq(struct hns_roce_dev *hr_dev,
eq->l0_dma = 0; eq->l0_dma = 0;
if (mhop_num == 1) if (mhop_num == 1)
for (i -= i; i >= 0; i--) for (i -= 1; i >= 0; i--)
dma_free_coherent(dev, buf_chk_sz, eq->buf[i], dma_free_coherent(dev, buf_chk_sz, eq->buf[i],
eq->buf_dma[i]); eq->buf_dma[i]);
else if (mhop_num == 2) { else if (mhop_num == 2) {
......
...@@ -3448,8 +3448,11 @@ static void destroy_umrc_res(struct mlx5_ib_dev *dev) ...@@ -3448,8 +3448,11 @@ static void destroy_umrc_res(struct mlx5_ib_dev *dev)
if (err) if (err)
mlx5_ib_warn(dev, "mr cache cleanup failed\n"); mlx5_ib_warn(dev, "mr cache cleanup failed\n");
if (dev->umrc.qp)
mlx5_ib_destroy_qp(dev->umrc.qp); mlx5_ib_destroy_qp(dev->umrc.qp);
if (dev->umrc.cq)
ib_free_cq(dev->umrc.cq); ib_free_cq(dev->umrc.cq);
if (dev->umrc.pd)
ib_dealloc_pd(dev->umrc.pd); ib_dealloc_pd(dev->umrc.pd);
} }
...@@ -3552,12 +3555,15 @@ static int create_umr_res(struct mlx5_ib_dev *dev) ...@@ -3552,12 +3555,15 @@ static int create_umr_res(struct mlx5_ib_dev *dev)
error_4: error_4:
mlx5_ib_destroy_qp(qp); mlx5_ib_destroy_qp(qp);
dev->umrc.qp = NULL;
error_3: error_3:
ib_free_cq(cq); ib_free_cq(cq);
dev->umrc.cq = NULL;
error_2: error_2:
ib_dealloc_pd(pd); ib_dealloc_pd(pd);
dev->umrc.pd = NULL;
error_0: error_0:
kfree(attr); kfree(attr);
......
...@@ -739,6 +739,9 @@ int mlx5_mr_cache_cleanup(struct mlx5_ib_dev *dev) ...@@ -739,6 +739,9 @@ int mlx5_mr_cache_cleanup(struct mlx5_ib_dev *dev)
{ {
int i; int i;
if (!dev->cache.wq)
return 0;
dev->cache.stopped = 1; dev->cache.stopped = 1;
flush_workqueue(dev->cache.wq); flush_workqueue(dev->cache.wq);
......
...@@ -833,7 +833,8 @@ static struct qedr_dev *qedr_add(struct qed_dev *cdev, struct pci_dev *pdev, ...@@ -833,7 +833,8 @@ static struct qedr_dev *qedr_add(struct qed_dev *cdev, struct pci_dev *pdev,
dev->num_cnq = dev->ops->rdma_get_min_cnq_msix(cdev); dev->num_cnq = dev->ops->rdma_get_min_cnq_msix(cdev);
if (!dev->num_cnq) { if (!dev->num_cnq) {
DP_ERR(dev, "not enough CNQ resources.\n"); DP_ERR(dev, "Failed. At least one CNQ is required.\n");
rc = -ENOMEM;
goto init_err; goto init_err;
} }
......
...@@ -1841,14 +1841,15 @@ static void qedr_reset_qp_hwq_info(struct qedr_qp_hwq_info *qph) ...@@ -1841,14 +1841,15 @@ static void qedr_reset_qp_hwq_info(struct qedr_qp_hwq_info *qph)
static int qedr_update_qp_state(struct qedr_dev *dev, static int qedr_update_qp_state(struct qedr_dev *dev,
struct qedr_qp *qp, struct qedr_qp *qp,
enum qed_roce_qp_state cur_state,
enum qed_roce_qp_state new_state) enum qed_roce_qp_state new_state)
{ {
int status = 0; int status = 0;
if (new_state == qp->state) if (new_state == cur_state)
return 0; return 0;
switch (qp->state) { switch (cur_state) {
case QED_ROCE_QP_STATE_RESET: case QED_ROCE_QP_STATE_RESET:
switch (new_state) { switch (new_state) {
case QED_ROCE_QP_STATE_INIT: case QED_ROCE_QP_STATE_INIT:
...@@ -1955,6 +1956,7 @@ int qedr_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, ...@@ -1955,6 +1956,7 @@ int qedr_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
struct qedr_dev *dev = get_qedr_dev(&qp->dev->ibdev); struct qedr_dev *dev = get_qedr_dev(&qp->dev->ibdev);
const struct ib_global_route *grh = rdma_ah_read_grh(&attr->ah_attr); const struct ib_global_route *grh = rdma_ah_read_grh(&attr->ah_attr);
enum ib_qp_state old_qp_state, new_qp_state; enum ib_qp_state old_qp_state, new_qp_state;
enum qed_roce_qp_state cur_state;
int rc = 0; int rc = 0;
DP_DEBUG(dev, QEDR_MSG_QP, DP_DEBUG(dev, QEDR_MSG_QP,
...@@ -2086,18 +2088,23 @@ int qedr_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, ...@@ -2086,18 +2088,23 @@ int qedr_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
SET_FIELD(qp_params.modify_flags, SET_FIELD(qp_params.modify_flags,
QED_ROCE_MODIFY_QP_VALID_ACK_TIMEOUT, 1); QED_ROCE_MODIFY_QP_VALID_ACK_TIMEOUT, 1);
qp_params.ack_timeout = attr->timeout; /* The received timeout value is an exponent used like this:
if (attr->timeout) { * "12.7.34 LOCAL ACK TIMEOUT
u32 temp; * Value representing the transport (ACK) timeout for use by
* the remote, expressed as: 4.096 * 2^timeout [usec]"
temp = 4096 * (1UL << attr->timeout) / 1000 / 1000; * The FW expects timeout in msec so we need to divide the usec
/* FW requires [msec] */ * result by 1000. We'll approximate 1000~2^10, and 4.096 ~ 2^2,
qp_params.ack_timeout = temp; * so we get: 2^2 * 2^timeout / 2^10 = 2^(timeout - 8).
} else { * The value of zero means infinite so we use a 'max_t' to make
/* Infinite */ * sure that sub 1 msec values will be configured as 1 msec.
*/
if (attr->timeout)
qp_params.ack_timeout =
1 << max_t(int, attr->timeout - 8, 0);
else
qp_params.ack_timeout = 0; qp_params.ack_timeout = 0;
} }
}
if (attr_mask & IB_QP_RETRY_CNT) { if (attr_mask & IB_QP_RETRY_CNT) {
SET_FIELD(qp_params.modify_flags, SET_FIELD(qp_params.modify_flags,
QED_ROCE_MODIFY_QP_VALID_RETRY_CNT, 1); QED_ROCE_MODIFY_QP_VALID_RETRY_CNT, 1);
...@@ -2170,13 +2177,25 @@ int qedr_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, ...@@ -2170,13 +2177,25 @@ int qedr_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
qp->dest_qp_num = attr->dest_qp_num; qp->dest_qp_num = attr->dest_qp_num;
} }
cur_state = qp->state;
/* Update the QP state before the actual ramrod to prevent a race with
* fast path. Modifying the QP state to error will cause the device to
* flush the CQEs and while polling the flushed CQEs will considered as
* a potential issue if the QP isn't in error state.
*/
if ((attr_mask & IB_QP_STATE) && qp->qp_type != IB_QPT_GSI &&
!udata && qp_params.new_state == QED_ROCE_QP_STATE_ERR)
qp->state = QED_ROCE_QP_STATE_ERR;
if (qp->qp_type != IB_QPT_GSI) if (qp->qp_type != IB_QPT_GSI)
rc = dev->ops->rdma_modify_qp(dev->rdma_ctx, rc = dev->ops->rdma_modify_qp(dev->rdma_ctx,
qp->qed_qp, &qp_params); qp->qed_qp, &qp_params);
if (attr_mask & IB_QP_STATE) { if (attr_mask & IB_QP_STATE) {
if ((qp->qp_type != IB_QPT_GSI) && (!udata)) if ((qp->qp_type != IB_QPT_GSI) && (!udata))
rc = qedr_update_qp_state(dev, qp, qp_params.new_state); rc = qedr_update_qp_state(dev, qp, cur_state,
qp_params.new_state);
qp->state = qp_params.new_state; qp->state = qp_params.new_state;
} }
......
...@@ -130,6 +130,8 @@ void rdma_copy_addr(struct rdma_dev_addr *dev_addr, ...@@ -130,6 +130,8 @@ void rdma_copy_addr(struct rdma_dev_addr *dev_addr,
const unsigned char *dst_dev_addr); const unsigned char *dst_dev_addr);
int rdma_addr_size(struct sockaddr *addr); int rdma_addr_size(struct sockaddr *addr);
int rdma_addr_size_in6(struct sockaddr_in6 *addr);
int rdma_addr_size_kss(struct __kernel_sockaddr_storage *addr);
int rdma_addr_find_l2_eth_by_grh(const union ib_gid *sgid, int rdma_addr_find_l2_eth_by_grh(const union ib_gid *sgid,
const union ib_gid *dgid, const union ib_gid *dgid,
......
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