FAILED: patch "[PATCH] dmaengine: at_hdmac: Fix concurrency over the active list" failed to apply to 5.4-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 5.4-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
Possible dependencies:
03ed9ba357cc ("dmaengine: at_hdmac: Fix concurrency over the active list") 6ba826cbb57d ("dmaengine: at_hdmac: Free the memset buf without holding the chan lock") 06988949df8c ("dmaengine: at_hdmac: Fix concurrency over descriptor") c6babed879fb ("dmaengine: at_hdmac: Fix concurrency problems by removing atc_complete_all()") 078a6506141a ("dmaengine: at_hdmac: Fix deadlocks")
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 03ed9ba357cc78116164b90b87f45eacab60b561 Mon Sep 17 00:00:00 2001
From: Tudor Ambarus <[email protected]>
Date: Tue, 25 Oct 2022 12:02:44 +0300
Subject: [PATCH] dmaengine: at_hdmac: Fix concurrency over the active list
The tasklet (atc_advance_work()) did not held the channel lock when retrieving the first active descriptor, causing concurrency problems if issue_pending() was called in between. If issue_pending() was called exactly after the lock was released in the tasklet (atc_advance_work()), atc_chain_complete() could complete a descriptor for which the controller has not yet raised an interrupt.
drivers/dma/at_hdmac.c +6 -4
@@ -462,8 +462,6 @@ atc_chain_complete(struct at_dma_chan *atchan, struct at_desc *desc)if (!atc_chan_is_cyclic (atchan))dma_cookie_complete (txd); -/* Remove transfer node from the active list. */ -list_del_init (&desc->desc_node);spin_unlock_irqrestore (&atchan->lock, flags);dma_descriptor_unmap (txd);
@@ -495,6 +493,7 @@ atc_chain_complete(struct at_dma_chan *atchan, struct at_desc *desc)*/ static void atc_advance_work (struct at_dma_chan *atchan) { +struct at_desc *desc;unsigned long flags;dev_vdbg (chan2dev (&atchan->chan_common),"advance_work\n" );
@@ -502,9 +501,12 @@ static void atc_advance_work(struct at_dma_chan *atchan)spin_lock_irqsave (&atchan->lock, flags);if (atc_chan_is_enabled (atchan) ||list_empty (&atchan->active_list))return spin_unlock_irqrestore (&atchan->lock, flags); -spin_unlock_irqrestore (&atchan->lock, flags); -atc_chain_complete (atchan,atc_first_active (atchan)); + desc =atc_first_active (atchan); +/* Remove the transfer node from the active list. */ +list_del_init (&desc->desc_node); +spin_unlock_irqrestore (&atchan->lock, flags); +atc_chain_complete (atchan, desc);/* advance work */ spin_lock_irqsave (&atchan->lock, flags);