Re: [PATCH v2 01/64] dmaengine: add tasklet-backed channel BH helpers

Vinod Koul <[email protected]> Wed, 29 Jul 2026 18:16:23 +0530
Newsgroups org.kernel.vger.dmaengine,dev.linux.lists.sashiko-reviews
Message-ID <amn2H5thhxTdGUKO@vaman>
On 27-07-26, 20:56, [email protected] wrote:
> Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
> 
> New issues:
> - [Low] API breakage leading to widespread build failures in downstream DMA drivers due to the removal of the `task` field from `struct virt_dma_chan` without updating its consumers.
> 
> Pre-existing issues:
> - [Critical] Race condition causing a Use-After-Free of a cyclic descriptor's `tx_result` pointer when a channel is concurrently terminated.
> --
> 
> --- Patch [1]: [PATCH v2 01/64] dmaengine: add tasklet-backed channel BH helpers ---
> commit 9141d715bfba5e26881326cc343ca063eaf8458a
> Author: Allen Pais <[email protected]>
> 
> dmaengine: add tasklet-backed channel BH helpers
> 
> This patch introduces helpers to initialize, schedule, and kill a channel
> bottom half. It converts virt-dma to use the new API, replacing its private
> tasklet while preserving the execution context.
> 
> > diff --git a/drivers/dma/virt-dma.c b/drivers/dma/virt-dma.c
> > index 7961172a780dd..89fcd51ddcabe 100644
> > --- a/drivers/dma/virt-dma.c
> > +++ b/drivers/dma/virt-dma.c
> [ ... ]
> > @@ -98,7 +98,7 @@ static void vchan_complete(struct tasklet_struct *t)
> >  	}
> >  	spin_unlock_irq(&vc->lock);
> >  
> > -	dmaengine_desc_callback_invoke(&cb, &vd->tx_result);
> > +	dmaengine_desc_callback_invoke(&cb, vd ? &vd->tx_result : NULL);
> 
> [Severity: Critical]
> This is a pre-existing issue, but does dropping vc->lock just before
> referencing vd->tx_result open a race window for a use-after-free?
> 
> If a concurrent dmaengine_terminate_sync() calls the driver's terminate_all
> callback (like bcm2835_dma_terminate_all()), the driver could acquire the
> lock and free vd via vchan_dma_desc_free_list():
> 
> CPU1
> vchan_complete()
>     spin_unlock_irq(&vc->lock);
> 
> CPU2
> dmaengine_terminate_sync()
>     bcm2835_dma_terminate_all()
>         spin_lock_irqsave(&vc->lock, flags);
>         vchan_dma_desc_free_list() // frees vd
>         spin_unlock_irqrestore(&vc->lock, flags);
> 
> CPU1
>     dmaengine_desc_callback_invoke(&cb, vd ? &vd->tx_result : NULL);
> 
> Could evaluating vd->tx_result here pass a dangling pointer to the client
> callback if the descriptor was freed by the concurrent termination?
> 
> >  	list_for_each_entry_safe(vd, _vd, &head, node) {
> >  		dmaengine_desc_get_callback(&vd->tx, &cb);
> [ ... ]
> > diff --git a/drivers/dma/virt-dma.h b/drivers/dma/virt-dma.h
> > index 59d9eabc8b674..abe2a44757442 100644
> > --- a/drivers/dma/virt-dma.h
> > +++ b/drivers/dma/virt-dma.h
> > @@ -21,7 +21,6 @@ struct virt_dma_desc {
> >  
> >  struct virt_dma_chan {
> >  	struct dma_chan	chan;
> > -	struct tasklet_struct task;
> 
> [Severity: Low]
> Does removing the task field here cause build failures in downstream drivers?
> 
> Several DMA drivers like bcm2835-dma, hisi_dma, idma64, and tegra210-adma
> directly access chan->vc.task during driver removal or error paths to kill
> the tasklet. Without updating those consumers, they will fail to compile.

This one seems valid.
We need to replace the callsites with dma_chan_kill_bh() here

-- 
~Vinod