All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Allen Pais" <allen.lkml@gmail.com>
Cc: dmaengine@vger.kernel.org, vkoul@kernel.org, Frank.Li@kernel.org
Subject: Re: [PATCH v4 31/33] dmaengine: hidma: defer callbacks via channel BH
Date: Tue, 10 Nov 2026 19:51:08 +0000	[thread overview]
Message-ID: <sashiko-outbox-207685@kernel.org> (raw)
In-Reply-To: <1654bf0a77be77ccf3a2775a838d1accf604ac4e.1794315350.git.allen.lkml@gmail.com>

Thank you for your contribution! Sashiko AI review found 3 potential
issues to consider:
- [High] dmaengine: hidma: missing lldev tasklet kill before
  dmaengine_kill_bh()
- [High] dmaengine: hidma: race between hidma_chan_bh() and
  hidma_terminate_channel()
- [Medium] dmaengine: hidma: unconditional BH schedule in
  hidma_callback()
--

commit 2833f6ace610118cc0f61079464819e2cd18fc0f
Author: Allen Pais <allen.lkml@gmail.com>

dmaengine: hidma: defer callbacks via channel BH

This commit defers HIDMA descriptor completion processing from
hidma_callback() to per-channel BH work and drains the BH during channel
synchronization, resource freeing, and device removal.

> diff --git a/drivers/dma/qcom/hidma.c b/drivers/dma/qcom/hidma.c
> index 85844965f0d8c..2cde0cd08b1f5 100644
> --- a/drivers/dma/qcom/hidma.c
> +++ b/drivers/dma/qcom/hidma.c

[ ... ]

> @@ -181,7 +188,7 @@ static void hidma_callback(void *data)
>  	}
>  	spin_unlock_irqrestore(&mchan->lock, irqflags);
>  
> -	hidma_process_completed(mchan);
> +	dmaengine_schedule_bh(&mchan->chan);
>  
>  	if (queued) {
>  		pm_runtime_mark_last_busy(dmadev->ddev.dev);

[Severity: Medium]
Should dmaengine_schedule_bh(&mchan->chan) only be called when queued is
true?

During hidma_alloc_chan_resources(), hidma_ll_request() synchronously
invokes hidma_callback(mdesc) before mdesc->node is added to any list, so
mdesc->node.next is NULL and queued is false.  Scheduling the BH
unconditionally queues mchan->chan.bh_work during descriptor allocation; if
a later iteration in hidma_alloc_chan_resources() fails, the function
returns an error without calling dmaengine_kill_bh(), leaving
mchan->chan.bh_work pending after dma_chan_get() drops its device and
module references.

[ ... ]

> @@ -529,6 +537,11 @@ static int hidma_terminate_all(struct dma_chan *chan)
>  	return rc;
>  }
>  
> +static void hidma_synchronize(struct dma_chan *dmach)
> +{
> +	dmaengine_kill_bh(dmach);
> +}
> +
>  static void hidma_free_chan_resources(struct dma_chan *dmach)
>  {
>  	struct hidma_chan *mchan = to_hidma_chan(dmach);

[Severity: High]
Can dmadev->lldev->task schedule the channel BH after dmaengine_kill_bh()
returns in hidma_synchronize() and hidma_free_chan_resources()?

In hidma_remove(), tasklet_kill(&dmadev->lldev->task) is called before
dmaengine_kill_bh() because the low-level completion tasklet
(hidma_ll_tre_complete()) is what invokes hidma_callback() and schedules
the BH.  However, neither hidma_synchronize() nor
hidma_free_chan_resources() kills lldev->task first.  If an interrupt fires
just before hidma_ll_disable() masks hardware interrupts in
hidma_terminate_channel(), lldev->task can still be scheduled:

CPU0                                  CPU1 (<softirq>)
hidma_free_chan_resources()
  hidma_terminate_channel()
    hidma_ll_disable()
  dmaengine_kill_bh(dmach)
  spin_lock_irqsave(&mchan->lock)
  list_for_each_entry_safe(...) {
    hidma_ll_free(..., mdesc->tre_ch)
    list_del(&mdesc->node)
    kfree(mdesc)
  }
  spin_unlock_irqrestore(&mchan->lock)
                                      hidma_ll_tre_complete()
                                        tre->callback(tre->data)
                                          hidma_callback(mdesc)
                                            if (mdesc->node.next)
                                              list_move_tail(&mdesc->node,
                                                &mchan->completed)
                                                  <-- use-after-free
                                            dmaengine_schedule_bh()

Because list_del() sets mdesc->node.next to LIST_POISON1 (non-NULL),
hidma_callback() dereferences the freed mdesc, corrupts mchan->completed,
and schedules hidma_chan_bh() on the freed descriptor.  In the
dmaengine_terminate_sync() path, hidma_callback() moves mdesc from
mchan->free to mchan->completed and runs completion callbacks after
hidma_synchronize() has returned.

> @@ -540,6 +553,9 @@ static void hidma_free_chan_resources(struct dma_chan *dmach)
>  	/* terminate running transactions and free descriptors */
>  	hidma_terminate_channel(dmach);
>  
> +	/* drain completion work before the descriptors go away */
> +	dmaengine_kill_bh(dmach);
> +
>  	spin_lock_irqsave(&mchan->lock, irqflags);
>  
>  	/* Move data */

[Severity: High]
Can hidma_chan_bh() race with hidma_terminate_channel() and corrupt
mchan->free when dmaengine_kill_bh() is only called after
hidma_terminate_channel()?

Both dmaengine_terminate_sync() (which calls hidma_terminate_all() before
hidma_synchronize()) and hidma_free_chan_resources() enter
hidma_terminate_channel() while hidma_chan_bh() can still be running
hidma_process_completed():

CPU0 (kworker)                        CPU1
hidma_chan_bh()
  hidma_process_completed()
    spin_lock_irqsave(&mchan->lock)
    list_splice_tail_init(
      &mchan->completed, &list)
    spin_unlock_irqrestore(&mchan->lock)
                                      hidma_terminate_channel()
                                        ...
                                        list_for_each_entry_safe(...) {
                                          ...
                                          list_move(&mdesc->node,
                                                    &mchan->free)
    spin_lock_irqsave(&mchan->lock)
    list_move(&mdesc->node,
              &mchan->free)               <-- corrupts mchan->free
    spin_unlock_irqrestore(&mchan->lock)

hidma_terminate_channel() moves descriptors onto mchan->free without
holding mchan->lock:

drivers/dma/qcom/hidma.c:hidma_terminate_channel() {
    ...
	/* return all user requests */
	list_for_each_entry_safe(mdesc, tmp, &list, node) {
		struct dma_async_tx_descriptor *txd = &mdesc->desc;

		dma_descriptor_unmap(txd);
		dmaengine_desc_get_callback_invoke(txd, NULL);
		dma_run_dependencies(txd);

		/* move myself to free_list */
		list_move(&mdesc->node, &mchan->free);
	}
    ...
}

Previously hidma_process_completed() ran synchronously inside the tasklet,
Whereas now hidma_chan_bh() runs concurrently on the BH workqueue and can
also call hidma_process_completed() in parallel with the direct
hidma_process_completed() call at the top of hidma_terminate_channel() and
overwrite mchan->last_success after hidma_terminate_channel() resets it to
0.  Killing lldev->task and draining the channel BH inside
hidma_terminate_channel() after hidma_ll_disable() masks interrupts (and
before draining lists and moving descriptors to mchan->free) would avoid
these races.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1794315350.git.allen.lkml@gmail.com?part=31

  reply	other threads:[~2026-11-10 19:51 UTC|newest]

Thread overview: 44+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-10 13:13 [PATCH v4 00/33] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
2026-11-10 13:13 ` [PATCH v4 01/33] dmaengine: add tasklet-backed channel BH helpers Allen Pais
2026-11-10 13:13   ` Allen Pais
2026-11-10 13:13 ` [PATCH v4 02/33] dmaengine: back channel BH helpers with WQ_BH Allen Pais
2026-11-10 14:15   ` sashiko-bot
2026-11-10 13:13 ` [PATCH v4 03/33] dmaengine: apple-admac: use dmaengine BH callback Allen Pais
2026-11-10 13:13 ` [PATCH v4 04/33] dmaengine: at_xdmac: move irq bottom half to dmaengine BH Allen Pais
2026-11-10 13:13 ` [PATCH v4 05/33] dmaengine: ep93xx: hook callbacks via " Allen Pais
2026-11-10 13:13 ` [PATCH v4 06/33] dmaengine: fsldma: migrate tasklet to " Allen Pais
2026-11-10 13:13 ` [PATCH v4 07/33] dmaengine: fsl_raid: run completions via " Allen Pais
2026-11-10 13:13 ` [PATCH v4 08/33] dmaengine: imx-dma: flip per-chan tasklet to " Allen Pais
2026-11-10 13:13 ` [PATCH v4 09/33] dmaengine: ioat: convert cleanup " Allen Pais
2026-11-10 13:13 ` [PATCH v4 10/33] dmaengine: mmp_pdma: replace per-chan tasklet with " Allen Pais
2026-11-10 13:13 ` [PATCH v4 11/33] dmaengine: mmp_tdma: hook completions to " Allen Pais
2026-11-10 13:13 ` [PATCH v4 12/33] dmaengine: mv_xor: convert irq tasklet " Allen Pais
2026-11-10 13:13 ` [PATCH v4 13/33] dmaengine: mxs-dma: use dmaengine BH scheduling Allen Pais
2026-11-10 13:13 ` [PATCH v4 14/33] dmaengine: nbpfaxi: switch callbacks to dmaengine BH Allen Pais
2026-11-10 13:13 ` [PATCH v4 15/33] dmaengine: pch_dma: convert tasklet " Allen Pais
2026-11-10 13:13 ` [PATCH v4 16/33] dmaengine: ppc4xx: replace irq tasklet with " Allen Pais
2026-11-10 13:13 ` [PATCH v4 17/33] dmaengine: ste_dma40: convert per-channel tasklet to " Allen Pais
2026-11-10 17:08   ` sashiko-bot
2026-11-10 13:13 ` [PATCH v4 18/33] dmaengine: xgene-dma: wire descriptor cleanup " Allen Pais
2026-11-10 13:13 ` [PATCH v4 19/33] dmaengine: xilinx-dma: use dmaengine BH instead of tasklets Allen Pais
2026-11-10 17:35   ` sashiko-bot
2026-11-10 13:13 ` [PATCH v4 20/33] dmaengine: xilinx-dpdma: kill vchan BH on remove Allen Pais
2026-11-10 13:13 ` [PATCH v4 21/33] dmaengine: zynqmp-dma: switch completion tasklet to dmaengine BH Allen Pais
2026-11-10 13:13 ` [PATCH v4 22/33] dmaengine: tegra20-apb: use channel BH helpers Allen Pais
2026-11-10 13:13 ` [PATCH v4 23/33] dmaengine: timb_dma: route callbacks via channel BH Allen Pais
2026-11-10 18:04   ` sashiko-bot
2026-11-10 13:13 ` [PATCH v4 24/33] dmaengine: txx9dmac: " Allen Pais
2026-11-10 13:13 ` [PATCH v4 25/33] dmaengine: mv_xor_v2: use channel BH helpers Allen Pais
2026-11-10 13:13 ` [PATCH v4 26/33] dmaengine: mpc512x: route callbacks via channel BH Allen Pais
2026-11-10 18:44   ` sashiko-bot
2026-11-10 13:13 ` [PATCH v4 27/33] dmaengine: plx_dma: use channel BH helpers Allen Pais
2026-11-10 13:13 ` [PATCH v4 28/33] dmaengine: sf-pdma: route error callbacks through channel BH Allen Pais
2026-11-10 13:13   ` Allen Pais
2026-11-10 19:08   ` sashiko-bot
2026-11-10 13:13 ` [PATCH v4 29/33] dmaengine: pl330: route callbacks via " Allen Pais
2026-11-10 13:13 ` [PATCH v4 30/33] dmaengine: altera-msgdma: use channel BH helpers Allen Pais
2026-11-11  2:39   ` NG, ADRIAN HO YIN
2026-11-10 13:13 ` [PATCH v4 31/33] dmaengine: hidma: defer callbacks via channel BH Allen Pais
2026-11-10 19:51   ` sashiko-bot [this message]
2026-11-10 13:13 ` [PATCH v4 32/33] dmaengine: qcom-gpi: defer callbacks via vchan Allen Pais
2026-11-10 13:13 ` [PATCH v4 33/33] dmaengine: switchtec: use channel BH helpers Allen Pais

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=sashiko-outbox-207685@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=Frank.Li@kernel.org \
    --cc=allen.lkml@gmail.com \
    --cc=dmaengine@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=vkoul@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.