[PATCH v5 4/4] dmaengine: wait for RCU readers before releasing dma_device
From: Shivank Garg
Date: Sat Aug 22 2026 - 15:24:21 EST
dma_issue_pending_all() walks the dma_device_list with
list_for_each_entry_rcu() under rcu_read_lock(). dma_device_release()
unlinks the device with list_del_rcu() and then calls
device->device_release() (which in many drivers, such as plx_dma.c,
directly calls kfree()).
Because there is no grace period between unlinking the device and
freeing it, concurrent RCU readers in dma_issue_pending_all() can
access the device after it has been freed.
The lockless walk originally relied on clients holding a dmaengine
reference to pin the provider module, and therefore the device, for as
long as they might traverse the list. Commit 8ad342a86359 ("dmaengine:
Add reference counting to dma_device struct") decoupled the dma_device
lifetime from the module reference, so the device can now be released
while a reader is still walking the list.
Add synchronize_rcu() before the device is freed, so RCU readers are
guaranteed to have finished. Keep it unconditional: providers that do
not implement device_release() free the device themselves once
dma_async_device_unregister() returns. This call will delay for a grace
period with dma_list_mutex held, which is safe and only teardown path is
delayed.
Fixes: 2ba05622b8b1 ("dmaengine: provide a common 'issue_pending_all' implementation")
Suggested-by: Sashiko <sashiko-bot@xxxxxxxxxx>
Link: https://sashiko.dev/#/patchset/20260526-dmaengine-kref-fix-v2-0-3df60afac01d@xxxxxxx
Reviewed-by: Frank Li <Frank.Li@xxxxxxx>
Reviewed-by: Logan Gunthorpe <logang@xxxxxxxxxxxx>
Signed-off-by: Shivank Garg <shivankg@xxxxxxx>
---
drivers/dma/dmaengine.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 9214b9272a55..f9bc3e69fe58 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -428,6 +428,7 @@ static void dma_device_release(struct kref *ref)
list_del_rcu(&device->global_node);
dma_channel_rebalance();
+ synchronize_rcu();
if (device->device_release)
device->device_release(device);
--
2.43.0