[PATCH 2/4] dmaengine: dmatest: Suppress bogus failures when stopping a run

From: Nathan Lynch via B4 Relay

Date: Wed Jul 22 2026 - 11:52:47 EST


From: Nathan Lynch <nathan.lynch@xxxxxxx>

Writing 0 to the module 'run' attribute stops the test threads with
kthread_stop(), waking threads out of wait_event_freezable_timeout()
before the last transfer's completion callback has run. The stopping
thread samples the transfer status and then checks done->done at two
different instants, so the last transaction gets misreported two ways:

- "test timed out": the wait returns early with done->done still clear
even though the transfer is simply still finishing — not a real
timeout.

- "completion busy status": status is read as DMA_IN_PROGRESS a moment
before the transfer completes and latches done->done, so the stale
status is reported as a failure against a transfer that actually
succeeded.

This is not a recent regression: the threads have used an interruptible,
freezable timeout wait since long before the wait queue was moved into
thread context by commit 6f6a23a213be ("dmaengine: dmatest: move callback
wait queue to thread context"), so a stop has always been able to wake
the wait before the final callback runs.

When kthread_should_stop() returns true, use dma_sync_wait() to settle
the pending transaction. Real errors still yield DMA_ERROR.

Assisted-by: Claude:claude-opus-4-8 [Claude-Code]
Signed-off-by: Nathan Lynch <nathan.lynch@xxxxxxx>
---
drivers/dma/dmatest.c | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c
index 60bc448f42ee..3267c7e86f5d 100644
--- a/drivers/dma/dmatest.c
+++ b/drivers/dma/dmatest.c
@@ -702,6 +702,7 @@ static int dmatest_func(void *data)
struct dmaengine_unmap_data *um;
dma_addr_t *dsts;
unsigned int len;
+ bool stopping;

total_tests++;

@@ -839,6 +840,7 @@ static int dmatest_func(void *data)
status = dma_sync_wait(chan, cookie);
if (status == DMA_COMPLETE)
done->done = true;
+ stopping = kthread_should_stop();
} else {
dma_async_issue_pending(chan);

@@ -846,14 +848,19 @@ static int dmatest_func(void *data)
done->done,
msecs_to_jiffies(params->timeout));

- status = dma_async_is_tx_complete(chan, cookie, NULL,
- NULL);
+ stopping = kthread_should_stop();
+ status = stopping ?
+ dma_sync_wait(chan, cookie) :
+ dma_async_is_tx_complete(chan, cookie, NULL, NULL);
}

if (!done->done) {
- result("test timed out", total_tests, src->off, dst->off,
- len, 0);
- goto error_unmap_continue;
+ /* stopping: dma_sync_wait() let the transfer finish, not a timeout */
+ if (!stopping) {
+ result("test timed out", total_tests, src->off,
+ dst->off, len, 0);
+ goto error_unmap_continue;
+ }
} else if (status != DMA_COMPLETE &&
!(dma_has_cap(DMA_COMPLETION_NO_ORDER,
dev->cap_mask) &&

--
2.54.0