RDMA/core: Add resource tracking for create and destroy QPs
[linux] / drivers / infiniband / core / verbs.c
index a1bcdac..5324cf4 100644 (file)
@@ -882,7 +882,7 @@ struct ib_qp *ib_create_qp(struct ib_pd *pd,
        if (qp_init_attr->cap.max_rdma_ctxs)
                rdma_rw_init_qp(device, qp_init_attr);
 
-       qp = device->create_qp(pd, qp_init_attr, NULL);
+       qp = _ib_create_qp(device, pd, qp_init_attr, NULL);
        if (IS_ERR(qp))
                return qp;
 
@@ -892,7 +892,6 @@ struct ib_qp *ib_create_qp(struct ib_pd *pd,
                return ERR_PTR(ret);
        }
 
-       qp->device     = device;
        qp->real_qp    = qp;
        qp->uobject    = NULL;
        qp->qp_type    = qp_init_attr->qp_type;
@@ -922,7 +921,6 @@ struct ib_qp *ib_create_qp(struct ib_pd *pd,
                        atomic_inc(&qp_init_attr->srq->usecnt);
        }
 
-       qp->pd      = pd;
        qp->send_cq = qp_init_attr->send_cq;
        qp->xrcd    = NULL;
 
@@ -1301,9 +1299,6 @@ static int ib_resolve_eth_dmac(struct ib_device *device,
        if (!rdma_is_port_valid(device, rdma_ah_get_port_num(ah_attr)))
                return -EINVAL;
 
-       if (ah_attr->type != RDMA_AH_ATTR_TYPE_ROCE)
-               return 0;
-
        grh = rdma_ah_retrieve_grh(ah_attr);
 
        if (rdma_is_multicast_addr((struct in6_addr *)ah_attr->grh.dgid.raw)) {
@@ -1323,28 +1318,14 @@ static int ib_resolve_eth_dmac(struct ib_device *device,
 }
 
 /**
- * ib_modify_qp_with_udata - Modifies the attributes for the specified QP.
- * @qp: The QP to modify.
- * @attr: On input, specifies the QP attributes to modify.  On output,
- *   the current values of selected QP attributes are returned.
- * @attr_mask: A bit-mask used to specify which attributes of the QP
- *   are being modified.
- * @udata: pointer to user's input output buffer information
- *   are being modified.
- * It returns 0 on success and returns appropriate error code on error.
+ * IB core internal function to perform QP attributes modification.
  */
-int ib_modify_qp_with_udata(struct ib_qp *qp, struct ib_qp_attr *attr,
-                           int attr_mask, struct ib_udata *udata)
+static int _ib_modify_qp(struct ib_qp *qp, struct ib_qp_attr *attr,
+                        int attr_mask, struct ib_udata *udata)
 {
        u8 port = attr_mask & IB_QP_PORT ? attr->port_num : qp->port;
        int ret;
 
-       if (attr_mask & IB_QP_AV) {
-               ret = ib_resolve_eth_dmac(qp->device, &attr->ah_attr);
-               if (ret)
-                       return ret;
-       }
-
        if (rdma_ib_or_roce(qp->device, port)) {
                if (attr_mask & IB_QP_RQ_PSN && attr->rq_psn & ~0xffffff) {
                        pr_warn("%s: %s rq_psn overflow, masking to 24 bits\n",
@@ -1365,6 +1346,41 @@ int ib_modify_qp_with_udata(struct ib_qp *qp, struct ib_qp_attr *attr,
 
        return ret;
 }
+
+static bool is_qp_type_connected(const struct ib_qp *qp)
+{
+       return (qp->qp_type == IB_QPT_UC ||
+               qp->qp_type == IB_QPT_RC ||
+               qp->qp_type == IB_QPT_XRC_INI ||
+               qp->qp_type == IB_QPT_XRC_TGT);
+}
+
+/**
+ * ib_modify_qp_with_udata - Modifies the attributes for the specified QP.
+ * @ib_qp: The QP to modify.
+ * @attr: On input, specifies the QP attributes to modify.  On output,
+ *   the current values of selected QP attributes are returned.
+ * @attr_mask: A bit-mask used to specify which attributes of the QP
+ *   are being modified.
+ * @udata: pointer to user's input output buffer information
+ *   are being modified.
+ * It returns 0 on success and returns appropriate error code on error.
+ */
+int ib_modify_qp_with_udata(struct ib_qp *ib_qp, struct ib_qp_attr *attr,
+                           int attr_mask, struct ib_udata *udata)
+{
+       struct ib_qp *qp = ib_qp->real_qp;
+       int ret;
+
+       if (attr_mask & IB_QP_AV &&
+           attr->ah_attr.type == RDMA_AH_ATTR_TYPE_ROCE &&
+           is_qp_type_connected(qp)) {
+               ret = ib_resolve_eth_dmac(qp->device, &attr->ah_attr);
+               if (ret)
+                       return ret;
+       }
+       return _ib_modify_qp(qp, attr, attr_mask, udata);
+}
 EXPORT_SYMBOL(ib_modify_qp_with_udata);
 
 int ib_get_eth_speed(struct ib_device *dev, u8 port_num, u8 *speed, u8 *width)
@@ -1426,7 +1442,7 @@ int ib_modify_qp(struct ib_qp *qp,
                 struct ib_qp_attr *qp_attr,
                 int qp_attr_mask)
 {
-       return ib_modify_qp_with_udata(qp, qp_attr, qp_attr_mask, NULL);
+       return _ib_modify_qp(qp->real_qp, qp_attr, qp_attr_mask, NULL);
 }
 EXPORT_SYMBOL(ib_modify_qp);
 
@@ -1520,6 +1536,7 @@ int ib_destroy_qp(struct ib_qp *qp)
        if (!qp->uobject)
                rdma_rw_cleanup_mrs(qp);
 
+       rdma_restrack_del(&qp->res);
        ret = qp->device->destroy_qp(qp);
        if (!ret) {
                if (pd)
@@ -1764,7 +1781,7 @@ int ib_detach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid)
 }
 EXPORT_SYMBOL(ib_detach_mcast);
 
-struct ib_xrcd *ib_alloc_xrcd(struct ib_device *device)
+struct ib_xrcd *__ib_alloc_xrcd(struct ib_device *device, const char *caller)
 {
        struct ib_xrcd *xrcd;
 
@@ -1782,7 +1799,7 @@ struct ib_xrcd *ib_alloc_xrcd(struct ib_device *device)
 
        return xrcd;
 }
-EXPORT_SYMBOL(ib_alloc_xrcd);
+EXPORT_SYMBOL(__ib_alloc_xrcd);
 
 int ib_dealloc_xrcd(struct ib_xrcd *xrcd)
 {
@@ -1807,11 +1824,11 @@ EXPORT_SYMBOL(ib_dealloc_xrcd);
  * ib_create_wq - Creates a WQ associated with the specified protection
  * domain.
  * @pd: The protection domain associated with the WQ.
- * @wq_init_attr: A list of initial attributes required to create the
+ * @wq_attr: A list of initial attributes required to create the
  * WQ. If WQ creation succeeds, then the attributes are updated to
  * the actual capabilities of the created WQ.
  *
- * wq_init_attr->max_wr and wq_init_attr->max_sge determine
+ * wq_attr->max_wr and wq_attr->max_sge determine
  * the requested size of the WQ, and set to the actual values allocated
  * on return.
  * If ib_create_wq() succeeds, then max_wr and max_sge will always be
@@ -2173,16 +2190,16 @@ static void __ib_drain_sq(struct ib_qp *qp)
        struct ib_send_wr swr = {}, *bad_swr;
        int ret;
 
-       swr.wr_cqe = &sdrain.cqe;
-       sdrain.cqe.done = ib_drain_qp_done;
-       init_completion(&sdrain.done);
-
        ret = ib_modify_qp(qp, &attr, IB_QP_STATE);
        if (ret) {
                WARN_ONCE(ret, "failed to drain send queue: %d\n", ret);
                return;
        }
 
+       swr.wr_cqe = &sdrain.cqe;
+       sdrain.cqe.done = ib_drain_qp_done;
+       init_completion(&sdrain.done);
+
        ret = ib_post_send(qp, &swr, &bad_swr);
        if (ret) {
                WARN_ONCE(ret, "failed to drain send queue: %d\n", ret);
@@ -2207,16 +2224,16 @@ static void __ib_drain_rq(struct ib_qp *qp)
        struct ib_recv_wr rwr = {}, *bad_rwr;
        int ret;
 
-       rwr.wr_cqe = &rdrain.cqe;
-       rdrain.cqe.done = ib_drain_qp_done;
-       init_completion(&rdrain.done);
-
        ret = ib_modify_qp(qp, &attr, IB_QP_STATE);
        if (ret) {
                WARN_ONCE(ret, "failed to drain recv queue: %d\n", ret);
                return;
        }
 
+       rwr.wr_cqe = &rdrain.cqe;
+       rdrain.cqe.done = ib_drain_qp_done;
+       init_completion(&rdrain.done);
+
        ret = ib_post_recv(qp, &rwr, &bad_rwr);
        if (ret) {
                WARN_ONCE(ret, "failed to drain recv queue: %d\n", ret);