[PATCH v7 05/19] media: meson: vdec: Fix race condition and synchronize esparser IRQ

From: Anand Moon

Date: Mon Jul 13 2026 - 08:13:13 EST


During session teardown sequences in vdec_stop_streaming() and
vdec_close(), the 'esparser' hardware interrupt handler can still be
actively triggered or executing on another CPU core. This creates a
transient race condition where the ISR attempts to handle stream data and
allocate internal tracking state structures after session contexts have
been modified or freed.

Update esparser_isr() to read the current session context utilizing an
smp_load_acquire() barrier snapshot. If the pointer resolves to NULL,
terminate processing early with IRQ_HANDLED to protect against
concurrent dismantling.

Suggested-by: Doruk Tan Ozturk <doruk@xxxxxxx>
Reported-by: Sashiko <sashiko-bot@xxxxxxxxxx>
Closes: https://lore.kernel.org/all/20260521090944.F35401F00A3D@xxxxxxxxxxxxxxx/
Signed-off-by: Anand Moon <linux.amoon@xxxxxxxxx>
---
drivers/staging/media/meson/vdec/esparser.c | 8 ++++++++
drivers/staging/media/meson/vdec/vdec.c | 4 ++++
drivers/staging/media/meson/vdec/vdec.h | 2 ++
3 files changed, 14 insertions(+)

diff --git a/drivers/staging/media/meson/vdec/esparser.c b/drivers/staging/media/meson/vdec/esparser.c
index 4632346f04a9e..37749ede308c6 100644
--- a/drivers/staging/media/meson/vdec/esparser.c
+++ b/drivers/staging/media/meson/vdec/esparser.c
@@ -60,6 +60,12 @@ static irqreturn_t esparser_isr(int irq, void *dev)
{
int int_status;
struct amvdec_core *core = dev;
+ struct amvdec_session *sess;
+
+ /* Secure an atomic snapshot to protect against concurrent teardown */
+ sess = smp_load_acquire(&core->cur_sess);
+ if (!sess)
+ return IRQ_HANDLED;

int_status = amvdec_read_parser(core, PARSER_INT_STATUS);
amvdec_write_parser(core, PARSER_INT_STATUS, int_status);
@@ -439,6 +445,8 @@ int esparser_init(struct platform_device *pdev, struct amvdec_core *core)
if (irq < 0)
return irq;

+ core->esparser_irq = irq;
+
ret = devm_request_irq(dev, irq, esparser_isr, IRQF_SHARED,
"esparserirq", core);
if (ret) {
diff --git a/drivers/staging/media/meson/vdec/vdec.c b/drivers/staging/media/meson/vdec/vdec.c
index 7ae3d5a9dd6ab..7689ffdb2e500 100644
--- a/drivers/staging/media/meson/vdec/vdec.c
+++ b/drivers/staging/media/meson/vdec/vdec.c
@@ -486,6 +486,8 @@ static void vdec_stop_streaming(struct vb2_queue *q)

/* Synchronize and flush pending hardware interrupt service routines */
synchronize_irq(core->vdec_irq);
+ /* Ensure esparser ISR finishes executing */
+ synchronize_irq(core->esparser_irq);

vdec_poweroff(sess);
vdec_free_canvas(sess);
@@ -994,6 +996,8 @@ static int vdec_close(struct file *file)

/* Synchronize and flush pending hardware interrupt service routines */
synchronize_irq(core->vdec_irq);
+ /* Ensure esparser ISR finishes executing */
+ synchronize_irq(core->esparser_irq);

if (!IS_ERR_OR_NULL(sess->recycle_thread)) {
kthread_stop(sess->recycle_thread);
diff --git a/drivers/staging/media/meson/vdec/vdec.h b/drivers/staging/media/meson/vdec/vdec.h
index d165c343fd022..c4639cf33e73e 100644
--- a/drivers/staging/media/meson/vdec/vdec.h
+++ b/drivers/staging/media/meson/vdec/vdec.h
@@ -68,6 +68,7 @@ struct amvdec_session;
* @cur_sess: current decoding session
* @lock: video device lock
* @vdec_irq: irq for video decoding
+ * @esparser_irq: irq for elementary stream parsing
*/
struct amvdec_core {
void __iomem *dos_base;
@@ -95,6 +96,7 @@ struct amvdec_core {
struct amvdec_session *cur_sess;
struct mutex lock;
int vdec_irq;
+ int esparser_irq;
};

/**
--
2.50.1