[PATCH 2/2] dmaengine: idxd: fix destroy of NULL or already destroyed workqueue

From: Jingyi Li

Date: Tue Oct 27 2026 - 20:38:09 EST


idxd_conf_device_release() unconditionally calls
destroy_workqueue(idxd->wq). This is wrong in two cases:

- If idxd_probe() fails before idxd_setup_internals() has created the
workqueue, for example when the device reports HALTED after reset,
idxd->wq is still NULL and the final put_device() in the probe error
path oopses:

BUG: kernel NULL pointer dereference, address: 00000000000000d0
RIP: 0010:destroy_workqueue+0xe/0x300
Call Trace:
<TASK>
idxd_conf_device_release+0x15/0x90 [idxd]
device_release+0x3c/0x90
kobject_put+0x7e/0x1e0
idxd_pci_probe_alloc+0x300/0x15e0 [idxd]
local_pci_probe+0x22/0x60
pci_device_probe+0xd4/0x260

- idxd_cleanup_internals() and the err_evl path of
idxd_setup_internals() destroy the workqueue but leave idxd->wq
pointing to it, so the release callback destroys it a second time.

Clear idxd->wq after the early destroys and skip the destroy in the
release callback when there is no workqueue.

We hit the NULL case in a kdump crash kernel, where the DSA device
fails to reset and the oops kills the crash kernel before the dump is
saved.

Fixes: 3d33de353b1f ("dmaengine: idxd: Fix not releasing workqueue on .release()")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Jingyi Li <jinli@xxxxxxxxxxxxxxx>
---
drivers/dma/idxd/init.c | 2 ++
drivers/dma/idxd/sysfs.c | 3 ++-
2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c
index 1577d22b299c..5962cacef060 100644
--- a/drivers/dma/idxd/init.c
+++ b/drivers/dma/idxd/init.c
@@ -389,6 +389,7 @@ static void idxd_cleanup_internals(struct idxd_device *idxd)
idxd_clean_engines(idxd);
idxd_clean_wqs(idxd);
destroy_workqueue(idxd->wq);
+ idxd->wq = NULL;
}

static int idxd_init_evl(struct idxd_device *idxd)
@@ -460,6 +461,7 @@ static int idxd_setup_internals(struct idxd_device *idxd)

err_evl:
destroy_workqueue(idxd->wq);
+ idxd->wq = NULL;
err_wkq_create:
idxd_clean_groups(idxd);
err_group:
diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c
index 6d251095c350..d5ffc641c856 100644
--- a/drivers/dma/idxd/sysfs.c
+++ b/drivers/dma/idxd/sysfs.c
@@ -1836,7 +1836,8 @@ static void idxd_conf_device_release(struct device *dev)
{
struct idxd_device *idxd = confdev_to_idxd(dev);

- destroy_workqueue(idxd->wq);
+ if (idxd->wq)
+ destroy_workqueue(idxd->wq);
kfree(idxd->groups);
bitmap_free(idxd->wq_enable_map);
kfree(idxd->wqs);
--
2.43.0