Re: [PATCH v2 12/64] dmaengine: mv_xor: convert irq tasklet to dma_chan BH

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

Pre-existing issues:
- [High] The driver fails to explicitly cancel pending bottom-half work during module removal and initialization error paths, leading to a Use-After-Free.
- [High] Interrupts are requested and unmasked before the channel spinlock is initialized, creating a race condition that can lead to locking an uninitialized spinlock.
- [High] Recursive deadlock when submitting dependent operations from the completion handler.
--

--- Patch [12]: [PATCH v2 12/64] dmaengine: mv_xor: convert irq tasklet to dma_chan BH ---
commit a6fdd06d107411d5248196d2bc3b3e3a0282f10d
Author: Allen Pais <[email protected]>
Subject: dmaengine: mv_xor: convert irq tasklet to dma_chan BH

This patch replaces 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/mv_xor.c b/drivers/dma/mv_xor.c
> index 25ed61f1b0899..3a70d565e1ef0 100644
> --- a/drivers/dma/mv_xor.c
> +++ b/drivers/dma/mv_xor.c

[ ... ]

> @@ -336,9 +336,9 @@ static void mv_chan_slot_cleanup(struct mv_xor_chan *mv_chan)
>  		mv_chan->dmachan.completed_cookie = cookie;
>  }
>  
> -static void mv_xor_tasklet(struct tasklet_struct *t)
> +static void mv_xor_tasklet(struct dma_chan *c)
>  {
> -	struct mv_xor_chan *chan = from_tasklet(chan, t, irq_tasklet);
> +	struct mv_xor_chan *chan = to_mv_xor_chan(c);
>  
>  	spin_lock(&chan->lock);
>  	mv_chan_slot_cleanup(chan);
>  	spin_unlock(&chan->lock);
>  }

[Severity: High]
This is a pre-existing issue, but can this sequence lead to a recursive
deadlock? Looking at mv_xor_tasklet(), it holds the lock while running
cleanup:

mv_xor_tasklet()
    spin_lock(&chan->lock);
    mv_chan_slot_cleanup(chan);

If mv_chan_slot_cleanup() processes completed slots and invokes
dma_run_dependencies(), the dependent operations might be submitted to the
same channel:

mv_chan_slot_cleanup()
    mv_desc_run_tx_complete_actions()
        dma_run_dependencies()
            mv_xor_tx_submit()
                spin_lock_bh(&mv_chan->lock);

Would this recursive lock attempt cause a system hang, or is there something
preventing dependencies from being queued on the same channel?

[ ... ]

> @@ -1107,7 +1107,7 @@ mv_xor_channel_add(struct mv_xor_device *xordev,
>  
>  	mv_chan->mmr_base = xordev->xor_base;
>  	mv_chan->mmr_high_base = xordev->xor_high_base;
> -	tasklet_setup(&mv_chan->irq_tasklet, mv_xor_tasklet);
> +	dma_chan_init_bh(&mv_chan->dmachan, mv_xor_tasklet);
>  
>  	/* clear errors before enabling interrupts */
>  	mv_chan_clear_err_status(mv_chan);

[Severity: High]
This is a pre-existing issue, but does the initialization error path properly
cancel the bottom half work before the channel structure is freed?

If a failure occurs later in mv_xor_channel_add() (like self-tests failing),
the code jumps to err_free_irq:

err_free_irq:
    free_irq(mv_chan->irq, mv_chan);
err_free_dma:
    ...

Should dma_chan_kill_bh() be called here and in mv_xor_channel_remove() to
ensure scheduled work doesn't execute after mv_chan is freed?

[Severity: High]
This is also a pre-existing issue, but is it possible for an interrupt to
fire before the channel spinlock is initialized?

In mv_xor_channel_add(), request_irq() is called and interrupts are unmasked
before the lock is initialized:

mv_xor_channel_add()
    request_irq(..., mv_xor_interrupt_handler, ...);
    mv_chan_unmask_interrupts(mv_chan);
    ...
    spin_lock_init(&mv_chan->lock);

If a spurious interrupt fires immediately and schedules the BH work, could
mv_xor_tasklet() attempt to acquire an uninitialized lock?

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