Re: [PATCH v2 09/64] dmaengine: ioat: convert cleanup tasklet to dma_chan BH

[email protected] Mon, 27 Jul 2026 21:02:13 +0000
Newsgroups org.kernel.vger.dmaengine
Message-ID <[email protected]>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

Pre-existing issues:
- [High] The teardown sequence in `ioat_stop()` cancels the timer using `timer_delete_sync()`, but it can be subsequently re-armed by the final cleanup sequence, leading to a use-after-free when channel resources are freed.
- [High] `ioat_shutdown()` does not flush inflight BH runs, which can lead to a use-after-free or crash on module unload.
--

--- Patch [9]: [PATCH v2 09/64] dmaengine: ioat: convert cleanup tasklet to dma_chan BH ---
commit 1d64b3893af8e57fe59c7d2f05e40d26e9aec652
Author: Allen Pais <[email protected]>

dmaengine: ioat: convert cleanup tasklet to dma_chan BH

Replace the per-channel tasklet with the shared dma_chan BH helper.
The handler continues to run in softirq context while dmaengine owns
the common scheduling and teardown mechanism.

> diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c
> index ee93b029f9e3d..827b46c6354ad 100644
> --- a/drivers/dma/ioat/dma.c
> +++ b/drivers/dma/ioat/dma.c

[ ... ]

> @@ -161,11 +161,11 @@ void ioat_stop(struct ioatdma_chan *ioat_chan)
>  	/* flush inflight timers */
>  	timer_delete_sync(&ioat_chan->timer);
>  
> -	/* flush inflight tasklet runs */
> -	tasklet_kill(&ioat_chan->cleanup_task);
> +	/* flush inflight BH runs */
> +	dma_chan_kill_bh(&ioat_chan->dma_chan);
>  
>  	/* final cleanup now that everything is quiesced and can't re-arm */
> -	ioat_cleanup_event(&ioat_chan->cleanup_task);
> +	ioat_cleanup_event(&ioat_chan->dma_chan);

[Severity: High]
This is a pre-existing issue, but does this sequence inadvertently re-arm
the timer during teardown?

After timer_delete_sync() is called, ioat_cleanup_event() triggers a call
chain that can re-arm the timer unconditionally:

ioat_stop()
   timer_delete_sync(&ioat_chan->timer);
   ioat_cleanup_event()
      ioat_cleanup()
         ioat_cleanup_preamble()
            mod_timer(&ioat_chan->timer, jiffies + COMPLETION_TIMEOUT);

If the timer is re-armed here, could the delayed timer callback execute
after ioat_free_chan_resources() frees the completion pool memory?

Would upgrading timer_delete_sync() to timer_shutdown_sync() properly
prevent the timer from being re-armed?

[Severity: High]
This is also a pre-existing issue, but does ioat_shutdown() in 
drivers/dma/ioat/init.c have a similar teardown problem with the BH?

In ioat_shutdown(), the driver calls timer_delete_sync() and disables 
interrupts, but it does not appear to flush inflight BH runs like it does 
here in ioat_stop(). 

Since the IOAT_RUN bit is not cleared in ioat_shutdown():

drivers/dma/ioat/init.c:ioat_shutdown() {
    ...
    timer_delete_sync(&ioat_chan->timer);
    ioat_reset_hw(ioat_chan);
    ...
    ioat_disable_interrupts(ioat_dma);
}

Could an interrupt firing just before ioat_disable_interrupts() successfully
schedule the BH via dma_chan_schedule_bh()?

If the module is then unloaded, could the scheduled BH execute after 
release_ioatdma() has freed the channel structures, resulting in a 
use-after-free?

>  }

-- 
Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=9