dmaengine: idxd: Add missing cleanup for early error out in idxd_setup_internals

commit 61259fb96e023f7299c442c48b13e72c441fc0f2 upstream.

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: defe49f960 ("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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Shuai Xue
2025-04-04 20:02:12 +08:00
committed by Greg Kroah-Hartman
parent 6ab9526e32
commit 404aad9b0c

View File

@@ -145,6 +145,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;
@@ -235,6 +254,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;
@@ -286,6 +320,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;
@@ -400,7 +447,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);
@@ -431,14 +478,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;
}