OSDN Git Service

RDMA/bnxt_re: Avoid resource leak in case the NQ registration fails
authorSelvin Xavier <selvin.xavier@broadcom.com>
Mon, 8 Oct 2018 10:28:04 +0000 (03:28 -0700)
committerJason Gunthorpe <jgg@mellanox.com>
Tue, 16 Oct 2018 06:03:51 +0000 (00:03 -0600)
In case the NQ alloc/enable fails, free up the already allocated/enabled
NQ before reporting failure. Also, track the alloc/enable using proper
state checking.

Signed-off-by: Selvin Xavier <selvin.xavier@broadcom.com>
Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
drivers/infiniband/hw/bnxt_re/bnxt_re.h
drivers/infiniband/hw/bnxt_re/main.c

index f34ef05..31baa89 100644 (file)
@@ -119,6 +119,8 @@ struct bnxt_re_dev {
 #define BNXT_RE_FLAG_HAVE_L2_REF               3
 #define BNXT_RE_FLAG_RCFW_CHANNEL_EN           4
 #define BNXT_RE_FLAG_QOS_WORK_REG              5
+#define BNXT_RE_FLAG_RESOURCES_ALLOCATED       7
+#define BNXT_RE_FLAG_RESOURCES_INITIALIZED     8
 #define BNXT_RE_FLAG_ISSUE_ROCE_STATS          29
        struct net_device               *netdev;
        unsigned int                    version, major, minor;
index 75a54c5..e5d4b12 100644 (file)
@@ -863,10 +863,8 @@ static void bnxt_re_cleanup_res(struct bnxt_re_dev *rdev)
 {
        int i;
 
-       if (rdev->nq[0].hwq.max_elements) {
-               for (i = 1; i < rdev->num_msix; i++)
-                       bnxt_qplib_disable_nq(&rdev->nq[i - 1]);
-       }
+       for (i = 1; i < rdev->num_msix; i++)
+               bnxt_qplib_disable_nq(&rdev->nq[i - 1]);
 
        if (rdev->qplib_res.rcfw)
                bnxt_qplib_cleanup_res(&rdev->qplib_res);
@@ -875,6 +873,7 @@ static void bnxt_re_cleanup_res(struct bnxt_re_dev *rdev)
 static int bnxt_re_init_res(struct bnxt_re_dev *rdev)
 {
        int rc = 0, i;
+       int num_vec_enabled = 0;
 
        bnxt_qplib_init_res(&rdev->qplib_res);
 
@@ -890,9 +889,13 @@ static int bnxt_re_init_res(struct bnxt_re_dev *rdev)
                                "Failed to enable NQ with rc = 0x%x", rc);
                        goto fail;
                }
+               num_vec_enabled++;
        }
        return 0;
 fail:
+       for (i = num_vec_enabled; i >= 0; i--)
+               bnxt_qplib_disable_nq(&rdev->nq[i]);
+
        return rc;
 }
 
@@ -924,6 +927,7 @@ static void bnxt_re_free_res(struct bnxt_re_dev *rdev)
 static int bnxt_re_alloc_res(struct bnxt_re_dev *rdev)
 {
        int rc = 0, i;
+       int num_vec_created = 0;
 
        /* Configure and allocate resources for qplib */
        rdev->qplib_res.rcfw = &rdev->rcfw;
@@ -950,7 +954,7 @@ static int bnxt_re_alloc_res(struct bnxt_re_dev *rdev)
                if (rc) {
                        dev_err(rdev_to_dev(rdev), "Alloc Failed NQ%d rc:%#x",
                                i, rc);
-                       goto dealloc_dpi;
+                       goto free_nq;
                }
                rc = bnxt_re_net_ring_alloc
                        (rdev, rdev->nq[i].hwq.pbl[PBL_LVL_0].pg_map_arr,
@@ -963,14 +967,17 @@ static int bnxt_re_alloc_res(struct bnxt_re_dev *rdev)
                        dev_err(rdev_to_dev(rdev),
                                "Failed to allocate NQ fw id with rc = 0x%x",
                                rc);
+                       bnxt_qplib_free_nq(&rdev->nq[i]);
                        goto free_nq;
                }
+               num_vec_created++;
        }
        return 0;
 free_nq:
-       for (i = 0; i < rdev->num_msix - 1; i++)
+       for (i = num_vec_created; i >= 0; i--) {
+               bnxt_re_net_ring_free(rdev, rdev->nq[i].ring_id);
                bnxt_qplib_free_nq(&rdev->nq[i]);
-dealloc_dpi:
+       }
        bnxt_qplib_dealloc_dpi(&rdev->qplib_res,
                               &rdev->qplib_res.dpi_tbl,
                               &rdev->dpi_privileged);
@@ -1205,8 +1212,11 @@ static void bnxt_re_ib_unreg(struct bnxt_re_dev *rdev)
        if (test_and_clear_bit(BNXT_RE_FLAG_QOS_WORK_REG, &rdev->flags))
                cancel_delayed_work_sync(&rdev->worker);
 
-       bnxt_re_cleanup_res(rdev);
-       bnxt_re_free_res(rdev);
+       if (test_and_clear_bit(BNXT_RE_FLAG_RESOURCES_INITIALIZED,
+                              &rdev->flags))
+               bnxt_re_cleanup_res(rdev);
+       if (test_and_clear_bit(BNXT_RE_FLAG_RESOURCES_ALLOCATED, &rdev->flags))
+               bnxt_re_free_res(rdev);
 
        if (test_and_clear_bit(BNXT_RE_FLAG_RCFW_CHANNEL_EN, &rdev->flags)) {
                rc = bnxt_qplib_deinit_rcfw(&rdev->rcfw);
@@ -1335,12 +1345,15 @@ static int bnxt_re_ib_reg(struct bnxt_re_dev *rdev)
                pr_err("Failed to allocate resources: %#x\n", rc);
                goto fail;
        }
+       set_bit(BNXT_RE_FLAG_RESOURCES_ALLOCATED, &rdev->flags);
        rc = bnxt_re_init_res(rdev);
        if (rc) {
                pr_err("Failed to initialize resources: %#x\n", rc);
                goto fail;
        }
 
+       set_bit(BNXT_RE_FLAG_RESOURCES_INITIALIZED, &rdev->flags);
+
        if (!rdev->is_virtfn) {
                rc = bnxt_re_setup_qos(rdev);
                if (rc)