Merge tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 30 Mar 2018 05:23:24 +0000 (19:23 -1000)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 30 Mar 2018 05:23:24 +0000 (19:23 -1000)
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

drivers/infiniband/core/addr.c
drivers/infiniband/core/device.c
drivers/infiniband/core/ucma.c
drivers/infiniband/hw/hns/hns_roce_hw_v2.c
drivers/infiniband/hw/mlx5/main.c
drivers/infiniband/hw/mlx5/mr.c
drivers/infiniband/hw/qedr/main.c
drivers/infiniband/hw/qedr/verbs.c
include/rdma/ib_addr.h

index 9183d148d644484c11f4e26fc87ff332c4fbb4eb..cb1d2ab13c661ac77f0221efc8c520de20fa3312 100644 (file)
@@ -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);
index bb065c9449be46617bd82e2b26d7648aa00212a3..b7459cf524e454f946d683fbddcc2e9d070cb42d 100644 (file)
@@ -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);
 
index e5a1e7d813265fc3f0947d3a6aa643367745d9cc..d933336d7e01eb0cb4ca4451d440040dd8131af9 100644 (file)
@@ -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);
index db2ff352d75f665b075d512e73dce619fdf230c1..ec638778661ccd7aadecb857bfdb9b8e59929524 100644 (file)
@@ -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) {
index da091de4e69d81eda73de4e3ce758830aaa1413c..7f8bda3a20058753c7bc3109c985895b2fb46664 100644 (file)
@@ -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);
index c51c602f06d6ea6d9c4737abbf4a6ab6f09fa6eb..3e0b3f0238d69315a8bd16d2177a0e5a96f8746e 100644 (file)
@@ -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);
 
index db4bf97c0e156cdda65f09934bd48f7b0e4a5de4..0ffb9b93e22de4f81e0e192afb1fbc8b34f2e861 100644 (file)
@@ -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;
        }
 
index 875b17272d65289d2cfa826f3635683831e19886..419a158e8fca78a930bdf2ee03e1297a4a15f1ba 100644 (file)
@@ -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;
        }
 
index d656809f1217ae039abb54df1748ae3aead1dafa..415e0996001760312d82c475d97ebf8cfb426531 100644 (file)
@@ -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,