]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
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)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 1 Dec 2019 08:16:23 +0000 (09:16 +0100)
[ Upstream commit 5df950994934814a8b91f0cf9f653842d2ba082d ]

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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/infiniband/hw/bnxt_re/bnxt_re.h
drivers/infiniband/hw/bnxt_re/main.c

index 96f76896488da6c0414411fea440520e75bf2843..802942adea8e85d60356854cb49cda90d330134e 100644 (file)
@@ -120,6 +120,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 7ffad368c5fa1c1929e9b756459b1853a40a8c0b..589b0d4677d52dcefe03cebdc5eb60d9de145b8d 100644 (file)
@@ -864,10 +864,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);
@@ -876,6 +874,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);
 
@@ -891,9 +890,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;
 }
 
@@ -925,6 +928,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;
@@ -951,7 +955,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,
@@ -964,14 +968,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);
@@ -1206,8 +1213,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(&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);
@@ -1337,12 +1347,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)