[PATCH 3/6] dmaengine: idxd: Fix potential double free on probe error path

From: Vinicius Costa Gomes

Date: Mon Oct 12 2026 - 17:43:30 EST


On the probe error path the device is released via put_device() ->
idxd_conf_device_release(), which frees idxd->wq and the idxd->wqs,
idxd->engines, idxd->groups and idxd->wq_enable_map arrays. The
idxd_clean_*() helpers and the idxd_setup_*() error unwind paths free
the same objects, so they get freed twice.

With commit ec2d428b2e32 ("dmaengine: idxd: fix double free of wq,
engine, and group structs") we made use of the kobject lifetime to
keep track of device memory allocations. These deallocations were left
behind. Remove them as idxd_conf_device_release() is already taking
care of that.

Fixes: 3d33de353b1f ("dmaengine: idxd: Fix not releasing workqueue on .release()")
Link: https://lore.kernel.org/all/20260615103932.61828-1-bogdan.codres@xxxxxxxxxxxxx/
Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@xxxxxxxxx>
---
drivers/dma/idxd/init.c | 11 -----------
1 file changed, 11 deletions(-)

diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c
index 4adb3f3bcd01..8cf478c5b26d 100644
--- a/drivers/dma/idxd/init.c
+++ b/drivers/dma/idxd/init.c
@@ -166,8 +166,6 @@ static void idxd_clean_wqs(struct idxd_device *idxd)
conf_dev = wq_confdev(idxd->wqs[i]);
put_device(conf_dev);
}
- bitmap_free(idxd->wq_enable_map);
- kfree(idxd->wqs);
}

static int idxd_setup_wqs(struct idxd_device *idxd)
@@ -245,11 +243,8 @@ static int idxd_setup_wqs(struct idxd_device *idxd)
conf_dev = wq_confdev(idxd->wqs[i]);
put_device(conf_dev);
}
- bitmap_free(idxd->wq_enable_map);

err_free_wqs:
- kfree(idxd->wqs);
-
return rc;
}

@@ -262,7 +257,6 @@ static void idxd_clean_engines(struct idxd_device *idxd)
conf_dev = engine_confdev(idxd->engines[i]);
put_device(conf_dev);
}
- kfree(idxd->engines);
}

static int idxd_setup_engines(struct idxd_device *idxd)
@@ -308,7 +302,6 @@ static int idxd_setup_engines(struct idxd_device *idxd)
conf_dev = engine_confdev(idxd->engines[i]);
put_device(conf_dev);
}
- kfree(idxd->engines);

return rc;
}
@@ -320,7 +313,6 @@ static void idxd_clean_groups(struct idxd_device *idxd)
for (i = 0; i < idxd->max_groups; i++) {
put_device(group_confdev(idxd->groups[i]));
}
- kfree(idxd->groups);
}

static int idxd_setup_groups(struct idxd_device *idxd)
@@ -378,7 +370,6 @@ static int idxd_setup_groups(struct idxd_device *idxd)
group = idxd->groups[i];
put_device(group_confdev(group));
}
- kfree(idxd->groups);

return rc;
}
@@ -388,7 +379,6 @@ static void idxd_cleanup_internals(struct idxd_device *idxd)
idxd_clean_groups(idxd);
idxd_clean_engines(idxd);
idxd_clean_wqs(idxd);
- destroy_workqueue(idxd->wq);
}

static int idxd_init_evl(struct idxd_device *idxd)
@@ -459,7 +449,6 @@ static int idxd_setup_internals(struct idxd_device *idxd)
return 0;

err_evl:
- destroy_workqueue(idxd->wq);
err_wkq_create:
idxd_clean_groups(idxd);
err_group:

--
2.56.0