dmaengine: idxd: Add missing cleanup for early error out in idxd_setup_internals
authorShuai Xue <xueshuai@linux.alibaba.com>
Fri, 4 Apr 2025 12:02:12 +0000 (20:02 +0800)
committerVinod Koul <vkoul@kernel.org>
Wed, 14 May 2025 13:40:39 +0000 (14:40 +0100)
The idxd_setup_internals() is missing some cleanup when things fail in
the middle.

Add the appropriate cleanup routines:

- cleanup groups
- cleanup enginces
- cleanup wqs

to make sure it exits gracefully.

Fixes: defe49f96012 ("dmaengine: idxd: fix group conf_dev lifetime")
Cc: stable@vger.kernel.org
Suggested-by: Fenghua Yu <fenghuay@nvidia.com>
Signed-off-by: Shuai Xue <xueshuai@linux.alibaba.com>
Reviewed-by: Fenghua Yu <fenghuay@nvidia.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Link: https://lore.kernel.org/r/20250404120217.48772-5-xueshuai@linux.alibaba.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
drivers/dma/idxd/init.c

index 7f0a26e2e0a5ced0a272f93fbc620d5607df50e1..a40fb2fd500618bdfbb330e2b0f7edc5a7781865 100644 (file)
@@ -155,6 +155,25 @@ static void idxd_cleanup_interrupts(struct idxd_device *idxd)
        pci_free_irq_vectors(pdev);
 }
 
+static void idxd_clean_wqs(struct idxd_device *idxd)
+{
+       struct idxd_wq *wq;
+       struct device *conf_dev;
+       int i;
+
+       for (i = 0; i < idxd->max_wqs; i++) {
+               wq = idxd->wqs[i];
+               if (idxd->hw.wq_cap.op_config)
+                       bitmap_free(wq->opcap_bmap);
+               kfree(wq->wqcfg);
+               conf_dev = wq_confdev(wq);
+               put_device(conf_dev);
+               kfree(wq);
+       }
+       bitmap_free(idxd->wq_enable_map);
+       kfree(idxd->wqs);
+}
+
 static int idxd_setup_wqs(struct idxd_device *idxd)
 {
        struct device *dev = &idxd->pdev->dev;
@@ -245,6 +264,21 @@ err_bitmap:
        return rc;
 }
 
+static void idxd_clean_engines(struct idxd_device *idxd)
+{
+       struct idxd_engine *engine;
+       struct device *conf_dev;
+       int i;
+
+       for (i = 0; i < idxd->max_engines; i++) {
+               engine = idxd->engines[i];
+               conf_dev = engine_confdev(engine);
+               put_device(conf_dev);
+               kfree(engine);
+       }
+       kfree(idxd->engines);
+}
+
 static int idxd_setup_engines(struct idxd_device *idxd)
 {
        struct idxd_engine *engine;
@@ -296,6 +330,19 @@ static int idxd_setup_engines(struct idxd_device *idxd)
        return rc;
 }
 
+static void idxd_clean_groups(struct idxd_device *idxd)
+{
+       struct idxd_group *group;
+       int i;
+
+       for (i = 0; i < idxd->max_groups; i++) {
+               group = idxd->groups[i];
+               put_device(group_confdev(group));
+               kfree(group);
+       }
+       kfree(idxd->groups);
+}
+
 static int idxd_setup_groups(struct idxd_device *idxd)
 {
        struct device *dev = &idxd->pdev->dev;
@@ -410,7 +457,7 @@ static int idxd_init_evl(struct idxd_device *idxd)
 static int idxd_setup_internals(struct idxd_device *idxd)
 {
        struct device *dev = &idxd->pdev->dev;
-       int rc, i;
+       int rc;
 
        init_waitqueue_head(&idxd->cmd_waitq);
 
@@ -441,14 +488,11 @@ static int idxd_setup_internals(struct idxd_device *idxd)
  err_evl:
        destroy_workqueue(idxd->wq);
  err_wkq_create:
-       for (i = 0; i < idxd->max_groups; i++)
-               put_device(group_confdev(idxd->groups[i]));
+       idxd_clean_groups(idxd);
  err_group:
-       for (i = 0; i < idxd->max_engines; i++)
-               put_device(engine_confdev(idxd->engines[i]));
+       idxd_clean_engines(idxd);
  err_engine:
-       for (i = 0; i < idxd->max_wqs; i++)
-               put_device(wq_confdev(idxd->wqs[i]));
+       idxd_clean_wqs(idxd);
  err_wqs:
        return rc;
 }