Fifth pull request for 4.16-rc
Bug fixes: - qedr driver bugfixes causing application hangs, wrong uapi errnos, and a race condition - 3 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 -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAABCgAGBQJavTPwAAoJEDht9xV+IJsaMtIP/04hM1pWJAxCPtxlXFqlfLnQ llGvDlzyGUrFlSbDITmXXS3nVFtk36SM6Eqqa48yi7oZF+2+4JjlaqIUiYXmAOOR ocvpDB4QKXgnjAc9mIyJ8SOILhmSDOwwbueaKBClnyPIj5wGvrKlnAdeGDgPeuSU Jcmect5penbU4U44m4JtbqSNIRWuoUvrbQ6ioftHV32RnXBRyrP1KxXtM3tVvav8 TlBgCt6zWhab1u6MGEebJgx97eFwhgc1Bd1mIJv9TPPEplC8kqaNRFrsctsyDUxu h674VNE5YyzoLBrUGI4IzvL5f3p8OEa18wslJB5ZyL6qiorj5y4vf+lSiQT8qOSF NW+jmsVEA0l0trVkl5r0qhzIV+EVTgSoR4C5wKbxEwMx51PmG/utPqFV+N511In7 GPqmRL3KuJPBZ0TIepwoH57FwrXdfc/UiF95duLizHojJgMpbnn18pQUBj2Fofch Gs9IjipO8AxpYybRoGvBC7fMTrzs5IV3yNj2qxu2mCq0tRQMu1cbOh6y//YZKqjL wQFtUSX2rO/rcvABAgpEP7a/9aLEj5m+vsFpEtigteRQRggOH6dAxXYzK8qKFqPK 4C9+5ybpAJqjjMuFxjd9n6BIYJG8gEhSGIyOaeP6cK016AQj4FN8ZgLwR9nTokQS p9DdyVZWFpqAuCWV5ML1 =0JcN -----END PGP SIGNATURE----- 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
This commit is contained in:
Коммит
d89b9f5029
|
@ -207,6 +207,22 @@ int rdma_addr_size(struct sockaddr *addr)
|
|||
}
|
||||
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;
|
||||
|
||||
void rdma_addr_register_client(struct rdma_addr_client *client)
|
||||
|
@ -586,6 +602,15 @@ static void process_one_req(struct work_struct *_work)
|
|||
list_del(&req->list);
|
||||
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->addr, req->context);
|
||||
put_client(req->client);
|
||||
|
|
|
@ -290,6 +290,7 @@ void ib_dealloc_device(struct ib_device *device)
|
|||
{
|
||||
WARN_ON(device->reg_state != IB_DEV_UNREGISTERED &&
|
||||
device->reg_state != IB_DEV_UNINITIALIZED);
|
||||
rdma_restrack_clean(&device->res);
|
||||
put_device(&device->dev);
|
||||
}
|
||||
EXPORT_SYMBOL(ib_dealloc_device);
|
||||
|
@ -600,8 +601,6 @@ void ib_unregister_device(struct ib_device *device)
|
|||
}
|
||||
up_read(&lists_rwsem);
|
||||
|
||||
rdma_restrack_clean(&device->res);
|
||||
|
||||
ib_device_unregister_rdmacg(device);
|
||||
ib_device_unregister_sysfs(device);
|
||||
|
||||
|
|
|
@ -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)))
|
||||
return -EFAULT;
|
||||
|
||||
if (!rdma_addr_size_in6(&cmd.addr))
|
||||
return -EINVAL;
|
||||
|
||||
ctx = ucma_get_ctx(file, cmd.id);
|
||||
if (IS_ERR(ctx))
|
||||
return PTR_ERR(ctx);
|
||||
|
@ -645,22 +648,21 @@ static ssize_t ucma_bind(struct ucma_file *file, const char __user *inbuf,
|
|||
int in_len, int out_len)
|
||||
{
|
||||
struct rdma_ucm_bind cmd;
|
||||
struct sockaddr *addr;
|
||||
struct ucma_context *ctx;
|
||||
int ret;
|
||||
|
||||
if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
|
||||
return -EFAULT;
|
||||
|
||||
addr = (struct sockaddr *) &cmd.addr;
|
||||
if (cmd.reserved || !cmd.addr_size || (cmd.addr_size != rdma_addr_size(addr)))
|
||||
if (cmd.reserved || !cmd.addr_size ||
|
||||
cmd.addr_size != rdma_addr_size_kss(&cmd.addr))
|
||||
return -EINVAL;
|
||||
|
||||
ctx = ucma_get_ctx(file, cmd.id);
|
||||
if (IS_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);
|
||||
return ret;
|
||||
}
|
||||
|
@ -670,23 +672,22 @@ static ssize_t ucma_resolve_ip(struct ucma_file *file,
|
|||
int in_len, int out_len)
|
||||
{
|
||||
struct rdma_ucm_resolve_ip cmd;
|
||||
struct sockaddr *src, *dst;
|
||||
struct ucma_context *ctx;
|
||||
int ret;
|
||||
|
||||
if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
|
||||
return -EFAULT;
|
||||
|
||||
src = (struct sockaddr *) &cmd.src_addr;
|
||||
dst = (struct sockaddr *) &cmd.dst_addr;
|
||||
if (!rdma_addr_size(src) || !rdma_addr_size(dst))
|
||||
if (!rdma_addr_size_in6(&cmd.src_addr) ||
|
||||
!rdma_addr_size_in6(&cmd.dst_addr))
|
||||
return -EINVAL;
|
||||
|
||||
ctx = ucma_get_ctx(file, cmd.id);
|
||||
if (IS_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);
|
||||
return ret;
|
||||
}
|
||||
|
@ -696,24 +697,23 @@ static ssize_t ucma_resolve_addr(struct ucma_file *file,
|
|||
int in_len, int out_len)
|
||||
{
|
||||
struct rdma_ucm_resolve_addr cmd;
|
||||
struct sockaddr *src, *dst;
|
||||
struct ucma_context *ctx;
|
||||
int ret;
|
||||
|
||||
if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
|
||||
return -EFAULT;
|
||||
|
||||
src = (struct sockaddr *) &cmd.src_addr;
|
||||
dst = (struct sockaddr *) &cmd.dst_addr;
|
||||
if (cmd.reserved || (cmd.src_size && (cmd.src_size != rdma_addr_size(src))) ||
|
||||
!cmd.dst_size || (cmd.dst_size != rdma_addr_size(dst)))
|
||||
if (cmd.reserved ||
|
||||
(cmd.src_size && (cmd.src_size != rdma_addr_size_kss(&cmd.src_addr))) ||
|
||||
!cmd.dst_size || (cmd.dst_size != rdma_addr_size_kss(&cmd.dst_addr)))
|
||||
return -EINVAL;
|
||||
|
||||
ctx = ucma_get_ctx(file, cmd.id);
|
||||
if (IS_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);
|
||||
return ret;
|
||||
}
|
||||
|
@ -1166,6 +1166,11 @@ static ssize_t ucma_init_qp_attr(struct ucma_file *file,
|
|||
if (IS_ERR(ctx))
|
||||
return PTR_ERR(ctx);
|
||||
|
||||
if (!ctx->cm_id->device) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
resp.qp_attr_mask = 0;
|
||||
memset(&qp_attr, 0, sizeof qp_attr);
|
||||
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,
|
|||
if (IS_ERR(ctx))
|
||||
return PTR_ERR(ctx);
|
||||
|
||||
if (unlikely(cmd.optval > KMALLOC_MAX_SIZE))
|
||||
if (unlikely(cmd.optlen > KMALLOC_MAX_SIZE))
|
||||
return -EINVAL;
|
||||
|
||||
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,
|
|||
{
|
||||
struct rdma_ucm_notify cmd;
|
||||
struct ucma_context *ctx;
|
||||
int ret;
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
|
||||
return -EFAULT;
|
||||
|
@ -1340,7 +1345,9 @@ static ssize_t ucma_notify(struct ucma_file *file, const char __user *inbuf,
|
|||
if (IS_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);
|
||||
return ret;
|
||||
}
|
||||
|
@ -1426,7 +1433,7 @@ static ssize_t ucma_join_ip_multicast(struct ucma_file *file,
|
|||
join_cmd.response = cmd.response;
|
||||
join_cmd.uid = cmd.uid;
|
||||
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)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -1445,7 +1452,7 @@ static ssize_t ucma_join_multicast(struct ucma_file *file,
|
|||
if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
|
||||
return -EFAULT;
|
||||
|
||||
if (!rdma_addr_size((struct sockaddr *)&cmd.addr))
|
||||
if (!rdma_addr_size_kss(&cmd.addr))
|
||||
return -EINVAL;
|
||||
|
||||
return ucma_process_join(file, &cmd, out_len);
|
||||
|
|
|
@ -4383,7 +4383,7 @@ err_dma_alloc_buf:
|
|||
eq->l0_dma = 0;
|
||||
|
||||
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],
|
||||
eq->buf_dma[i]);
|
||||
else if (mhop_num == 2) {
|
||||
|
|
|
@ -3448,9 +3448,12 @@ static void destroy_umrc_res(struct mlx5_ib_dev *dev)
|
|||
if (err)
|
||||
mlx5_ib_warn(dev, "mr cache cleanup failed\n");
|
||||
|
||||
mlx5_ib_destroy_qp(dev->umrc.qp);
|
||||
ib_free_cq(dev->umrc.cq);
|
||||
ib_dealloc_pd(dev->umrc.pd);
|
||||
if (dev->umrc.qp)
|
||||
mlx5_ib_destroy_qp(dev->umrc.qp);
|
||||
if (dev->umrc.cq)
|
||||
ib_free_cq(dev->umrc.cq);
|
||||
if (dev->umrc.pd)
|
||||
ib_dealloc_pd(dev->umrc.pd);
|
||||
}
|
||||
|
||||
enum {
|
||||
|
@ -3552,12 +3555,15 @@ static int create_umr_res(struct mlx5_ib_dev *dev)
|
|||
|
||||
error_4:
|
||||
mlx5_ib_destroy_qp(qp);
|
||||
dev->umrc.qp = NULL;
|
||||
|
||||
error_3:
|
||||
ib_free_cq(cq);
|
||||
dev->umrc.cq = NULL;
|
||||
|
||||
error_2:
|
||||
ib_dealloc_pd(pd);
|
||||
dev->umrc.pd = NULL;
|
||||
|
||||
error_0:
|
||||
kfree(attr);
|
||||
|
|
|
@ -739,6 +739,9 @@ int mlx5_mr_cache_cleanup(struct mlx5_ib_dev *dev)
|
|||
{
|
||||
int i;
|
||||
|
||||
if (!dev->cache.wq)
|
||||
return 0;
|
||||
|
||||
dev->cache.stopped = 1;
|
||||
flush_workqueue(dev->cache.wq);
|
||||
|
||||
|
|
|
@ -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);
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
struct qedr_qp *qp,
|
||||
enum qed_roce_qp_state cur_state,
|
||||
enum qed_roce_qp_state new_state)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
if (new_state == qp->state)
|
||||
if (new_state == cur_state)
|
||||
return 0;
|
||||
|
||||
switch (qp->state) {
|
||||
switch (cur_state) {
|
||||
case QED_ROCE_QP_STATE_RESET:
|
||||
switch (new_state) {
|
||||
case QED_ROCE_QP_STATE_INIT:
|
||||
|
@ -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);
|
||||
const struct ib_global_route *grh = rdma_ah_read_grh(&attr->ah_attr);
|
||||
enum ib_qp_state old_qp_state, new_qp_state;
|
||||
enum qed_roce_qp_state cur_state;
|
||||
int rc = 0;
|
||||
|
||||
DP_DEBUG(dev, QEDR_MSG_QP,
|
||||
|
@ -2086,18 +2088,23 @@ int qedr_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
|
|||
SET_FIELD(qp_params.modify_flags,
|
||||
QED_ROCE_MODIFY_QP_VALID_ACK_TIMEOUT, 1);
|
||||
|
||||
qp_params.ack_timeout = attr->timeout;
|
||||
if (attr->timeout) {
|
||||
u32 temp;
|
||||
|
||||
temp = 4096 * (1UL << attr->timeout) / 1000 / 1000;
|
||||
/* FW requires [msec] */
|
||||
qp_params.ack_timeout = temp;
|
||||
} else {
|
||||
/* Infinite */
|
||||
/* The received timeout value is an exponent used like this:
|
||||
* "12.7.34 LOCAL ACK TIMEOUT
|
||||
* Value representing the transport (ACK) timeout for use by
|
||||
* the remote, expressed as: 4.096 * 2^timeout [usec]"
|
||||
* The FW expects timeout in msec so we need to divide the usec
|
||||
* result by 1000. We'll approximate 1000~2^10, and 4.096 ~ 2^2,
|
||||
* so we get: 2^2 * 2^timeout / 2^10 = 2^(timeout - 8).
|
||||
* The value of zero means infinite so we use a 'max_t' to make
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
if (attr_mask & IB_QP_RETRY_CNT) {
|
||||
SET_FIELD(qp_params.modify_flags,
|
||||
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,
|
|||
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)
|
||||
rc = dev->ops->rdma_modify_qp(dev->rdma_ctx,
|
||||
qp->qed_qp, &qp_params);
|
||||
|
||||
if (attr_mask & IB_QP_STATE) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -130,6 +130,8 @@ void rdma_copy_addr(struct rdma_dev_addr *dev_addr,
|
|||
const unsigned char *dst_dev_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,
|
||||
const union ib_gid *dgid,
|
||||
|
|
Загрузка…
Ссылка в новой задаче