Re: [PATCH v3 3/3] dmaengine: wait for RCU readers before releasing dma_device
From: Frank Li
Date: Mon Aug 17 2026 - 10:37:18 EST
On Sun, Aug 16, 2026 at 03:49:27PM +0000, Shivank Garg wrote:
> [You don't often get email from shivankg@xxxxxxx. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
>
> 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, so they need the same grace
> period.
>
> 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
> Signed-off-by: Shivank Garg <shivankg@xxxxxxx>
> ---
Reviewed-by: Frank Li <Frank.Li@xxxxxxx>
> drivers/dma/dmaengine.c | 6 ++++++
> 1 file changed, 6 insertions(+)
>
> diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
> index bf491eb10596..29b128aa0bea 100644
> --- a/drivers/dma/dmaengine.c
> +++ b/drivers/dma/dmaengine.c
> @@ -429,6 +429,12 @@ static void dma_device_release(struct kref *ref)
> list_del_rcu(&device->global_node);
> dma_channel_rebalance();
>
> + /*
> + * Wait for RCU readers (e.g. dma_issue_pending_all()) that may still
> + * be traversing dma_device_list before the device is freed.
> + */
> + synchronize_rcu();
> +
> if (device->device_release)
> device->device_release(device);
> }
>
> --
> 2.43.0
>