From: Anand Moon <linux.amoon@gmail.com>
To: Neil Armstrong <neil.armstrong@linaro.org>,
Maarten Lankhorst <maarten.lankhorst@linux.intel.com>,
Maxime Ripard <mripard@kernel.org>,
Thomas Zimmermann <tzimmermann@suse.de>,
David Airlie <airlied@gmail.com>, Simona Vetter <simona@ffwll.ch>,
Kevin Hilman <khilman@baylibre.com>,
Jerome Brunet <jbrunet@baylibre.com>,
Martin Blumenstingl <martin.blumenstingl@googlemail.com>,
Mauro Carvalho Chehab <mchehab@kernel.org>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
dri-devel@lists.freedesktop.org (open list:DRM DRIVERS FOR
AMLOGIC SOCS),
linux-amlogic@lists.infradead.org (open list:DRM DRIVERS FOR
AMLOGIC SOCS),
linux-arm-kernel@lists.infradead.org (moderated list:ARM/Amlogic
Meson SoC support), linux-kernel@vger.kernel.org (open list),
linux-media@vger.kernel.org (open list:MESON VIDEO DECODER
DRIVER FOR AMLOGIC SOCS),
linux-staging@lists.linux.dev (open list:STAGING SUBSYSTEM)
Cc: Anand Moon <linux.amoon@gmail.com>,
Doruk Tan Ozturk <doruk@0sec.ai>,
Nicolas Dufresne <nicolas@ndufresne.ca>
Subject: [PATCH v7 08/19] media: meson: vdec: Fix concurrent execution races and unsafe teardown
Date: Mon, 13 Jul 2026 17:37:03 +0530 [thread overview]
Message-ID: <20260713120840.17427-9-linux.amoon@gmail.com> (raw)
In-Reply-To: <20260713120840.17427-1-linux.amoon@gmail.com>
Address data races involving 'should_stop' and prevent multi-session
hardware clobbering by enforcing atomic tracking and strict owner
validation during device teardown.
The esparser work queue reads 'sess->should_stop' outside of critical
regions without serialization primitives, risking data races or visibility
delays. Furthermore, vdec_close() and vdec_stop_streaming() blindly
shut down hardware components (via poweroff and canvas frees) and nullify
'core->cur_sess' without confirming that the executing session actually
owns the active hardware context. In multi-session scenarios, this allows
a closing inactive session to inadvertently break a running session.
To fix these synchronization and lifecycle issues with the following
changes use thread-safe flagging: Wrap reads and writes of
'sess->should_stop' in READ_ONCE() and WRITE_ONCE() to prevent compiler
optimizations from caching the condition variables across scheduling
boundaries and optimizations across workqueue execution threads.
Also safe context releasing: transition 'core->cur_sess' pointer
clearings to use smp_store_release(). This ensures all prior internal
memory structures are entirely flushed and visible to other execution
cores.
Cc: Nicolas Dufresne <nicolas@ndufresne.ca>
Signed-off-by: Anand Moon <linux.amoon@gmail.com>
---
drivers/staging/media/meson/vdec/esparser.c | 2 +-
drivers/staging/media/meson/vdec/vdec.c | 88 ++++++++++++++-------
2 files changed, 59 insertions(+), 31 deletions(-)
diff --git a/drivers/staging/media/meson/vdec/esparser.c b/drivers/staging/media/meson/vdec/esparser.c
index e5d3d817b9b2b..959673742e699 100644
--- a/drivers/staging/media/meson/vdec/esparser.c
+++ b/drivers/staging/media/meson/vdec/esparser.c
@@ -379,7 +379,7 @@ void esparser_queue_all_src(struct work_struct *work)
scoped_guard(mutex, &sess->lock) {
/* Safe atomic tracking check: exit loop if session is shutting down */
- if (sess->should_stop)
+ if (READ_ONCE(sess->should_stop))
return;
/* Queue completely empty: exit work loop cleanly */
diff --git a/drivers/staging/media/meson/vdec/vdec.c b/drivers/staging/media/meson/vdec/vdec.c
index 6fe9722577179..83a9b1238972a 100644
--- a/drivers/staging/media/meson/vdec/vdec.c
+++ b/drivers/staging/media/meson/vdec/vdec.c
@@ -287,9 +287,13 @@ static int vdec_start_streaming(struct vb2_queue *q, unsigned int count)
struct amvdec_session *sess = vb2_get_drv_priv(q);
struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
struct amvdec_core *core = sess->core;
+ struct device *dev = core->dev_dec;
struct vb2_v4l2_buffer *buf;
int ret;
+ /* Reset workqueue loop shutdown signal to allow streaming */
+ WRITE_ONCE(sess->should_stop, 0);
+
if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
sess->streamon_out = 1;
else
@@ -336,7 +340,7 @@ static int vdec_start_streaming(struct vb2_queue *q, unsigned int count)
dma_alloc_coherent(sess->core->dev, sess->vififo_size,
&sess->vififo_paddr, GFP_KERNEL);
if (!sess->vififo_vaddr) {
- dev_err(sess->core->dev, "Failed to request VIFIFO buffer\n");
+ dev_err(dev, "Failed to request VIFIFO buffer\n");
ret = -ENOMEM;
goto err_cleanup_session;
}
@@ -388,10 +392,12 @@ static int vdec_start_streaming(struct vb2_queue *q, unsigned int count)
sess->streamon_cap = 0;
mutex_lock(&core->lock);
- if (core->cur_sess == sess)
- core->cur_sess = NULL;
- if (sess->status != STATUS_NEEDS_RESUME)
- sess->status = STATUS_STOPPED;
+ if (core->cur_sess == sess) {
+ /* Safely clear hardware ownership since we were confirmed as the owner */
+ smp_store_release(&core->cur_sess, NULL);
+ if (sess->status != STATUS_NEEDS_RESUME)
+ sess->status = STATUS_STOPPED;
+ }
mutex_unlock(&core->lock);
err_unlock_no_hw:
while ((buf = v4l2_m2m_src_buf_remove(sess->m2m_ctx)))
@@ -441,6 +447,9 @@ static void vdec_stop_streaming(struct vb2_queue *q)
enum amvdec_status old_status;
bool full_cleanup = false;
+ /* Signal workqueue loop to abort instantly */
+ WRITE_ONCE(sess->should_stop, 1);
+
/* flush buffers to kill background workqueue thread */
if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
while ((buf = v4l2_m2m_src_buf_remove(sess->m2m_ctx)))
@@ -493,26 +502,33 @@ static void vdec_stop_streaming(struct vb2_queue *q)
cancel_work_sync(&sess->esparser_queue_work);
mutex_lock(&core->lock);
- vdec_poweroff(sess);
- vdec_free_canvas(sess);
+ if (core->cur_sess == sess) {
+ vdec_poweroff(sess);
+ vdec_free_canvas(sess);
+
+ if (sess->vififo_vaddr) {
+ dma_free_coherent(sess->core->dev,
+ sess->vififo_size,
+ sess->vififo_vaddr,
+ sess->vififo_paddr);
+ sess->vififo_vaddr = NULL;
+ sess->vififo_paddr = 0;
+ }
- if (sess->vififo_vaddr) {
- dma_free_coherent(sess->core->dev, sess->vififo_size,
- sess->vififo_vaddr, sess->vififo_paddr);
- sess->vififo_vaddr = NULL;
- sess->vififo_paddr = 0;
- }
+ vdec_reset_timestamps(sess);
+ vdec_reset_bufs_recycle(sess);
- vdec_reset_timestamps(sess);
- vdec_reset_bufs_recycle(sess);
- core->cur_sess = NULL;
+ kfree(sess->priv);
+ sess->priv = NULL;
- kfree(sess->priv);
- sess->priv = NULL;
+ /* Safely clear hardware ownership since we were confirmed as the owner */
+ smp_store_release(&core->cur_sess, NULL);
+ }
} else {
if (sess->status == STATUS_NEEDS_RESUME)
sess->changed_format = 0;
}
+
mutex_unlock(&core->lock);
}
@@ -802,7 +818,7 @@ vdec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd)
if (cmd->cmd == V4L2_DEC_CMD_START) {
v4l2_m2m_clear_state(sess->m2m_ctx);
- sess->should_stop = 0;
+ WRITE_ONCE(sess->should_stop, 0);
return 0;
}
@@ -812,7 +828,7 @@ vdec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd)
dev_dbg(dev, "Received V4L2_DEC_CMD_STOP\n");
- sess->should_stop = 1;
+ WRITE_ONCE(sess->should_stop, 1);
v4l2_m2m_mark_stopped(sess->m2m_ctx);
@@ -998,6 +1014,9 @@ static int vdec_close(struct file *file)
struct amvdec_session *sess = file_to_amvdec_session(file);
struct amvdec_core *core = sess->core;
+ /* Signal workqueue loop to abort instantly */
+ WRITE_ONCE(sess->should_stop, 1);
+
/* Synchronize and flush pending hardware interrupt service routines */
synchronize_irq(core->vdec_irq);
/* Ensure esparser ISR finishes executing */
@@ -1012,21 +1031,30 @@ static int vdec_close(struct file *file)
mutex_lock(&core->lock);
- vdec_poweroff(sess);
- vdec_free_canvas(sess);
- core->cur_sess = NULL;
+ if (core->cur_sess == sess) {
+ vdec_poweroff(sess);
+ vdec_free_canvas(sess);
- if (sess->vififo_vaddr) {
- dma_free_coherent(core->dev, sess->vififo_size,
- sess->vififo_vaddr, sess->vififo_paddr);
- sess->vififo_vaddr = NULL;
- sess->vififo_paddr = 0;
+ if (sess->vififo_vaddr) {
+ dma_free_coherent(core->dev,
+ sess->vififo_size,
+ sess->vififo_vaddr,
+ sess->vififo_paddr);
+ sess->vififo_vaddr = NULL;
+ sess->vififo_paddr = 0;
+ }
+ vdec_reset_timestamps(sess);
+ vdec_reset_bufs_recycle(sess);
}
- vdec_reset_timestamps(sess);
- vdec_reset_bufs_recycle(sess);
+
kfree(sess->priv);
sess->priv = NULL;
+ /* Unconditionally set our local status to stopped */
+ sess->status = STATUS_STOPPED;
+ /* Safely clear hardware ownership since we were confirmed as the owner */
+ smp_store_release(&core->cur_sess, NULL);
+
mutex_unlock(&core->lock);
v4l2_m2m_ctx_release(sess->m2m_ctx);
--
2.50.1
WARNING: multiple messages have this Message-ID (diff)
From: Anand Moon <linux.amoon@gmail.com>
To: Neil Armstrong <neil.armstrong@linaro.org>,
Maarten Lankhorst <maarten.lankhorst@linux.intel.com>,
Maxime Ripard <mripard@kernel.org>,
Thomas Zimmermann <tzimmermann@suse.de>,
David Airlie <airlied@gmail.com>, Simona Vetter <simona@ffwll.ch>,
Kevin Hilman <khilman@baylibre.com>,
Jerome Brunet <jbrunet@baylibre.com>,
Martin Blumenstingl <martin.blumenstingl@googlemail.com>,
Mauro Carvalho Chehab <mchehab@kernel.org>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
dri-devel@lists.freedesktop.org (open list:DRM DRIVERS FOR
AMLOGIC SOCS),
linux-amlogic@lists.infradead.org (open list:DRM DRIVERS FOR
AMLOGIC SOCS),
linux-arm-kernel@lists.infradead.org (moderated list:ARM/Amlogic
Meson SoC support), linux-kernel@vger.kernel.org (open list),
linux-media@vger.kernel.org (open list:MESON VIDEO DECODER
DRIVER FOR AMLOGIC SOCS),
linux-staging@lists.linux.dev (open list:STAGING SUBSYSTEM)
Cc: Doruk Tan Ozturk <doruk@0sec.ai>,
Nicolas Dufresne <nicolas@ndufresne.ca>
Subject: [PATCH v7 08/19] media: meson: vdec: Fix concurrent execution races and unsafe teardown
Date: Mon, 13 Jul 2026 17:37:03 +0530 [thread overview]
Message-ID: <20260713120840.17427-9-linux.amoon@gmail.com> (raw)
In-Reply-To: <20260713120840.17427-1-linux.amoon@gmail.com>
Address data races involving 'should_stop' and prevent multi-session
hardware clobbering by enforcing atomic tracking and strict owner
validation during device teardown.
The esparser work queue reads 'sess->should_stop' outside of critical
regions without serialization primitives, risking data races or visibility
delays. Furthermore, vdec_close() and vdec_stop_streaming() blindly
shut down hardware components (via poweroff and canvas frees) and nullify
'core->cur_sess' without confirming that the executing session actually
owns the active hardware context. In multi-session scenarios, this allows
a closing inactive session to inadvertently break a running session.
To fix these synchronization and lifecycle issues with the following
changes use thread-safe flagging: Wrap reads and writes of
'sess->should_stop' in READ_ONCE() and WRITE_ONCE() to prevent compiler
optimizations from caching the condition variables across scheduling
boundaries and optimizations across workqueue execution threads.
Also safe context releasing: transition 'core->cur_sess' pointer
clearings to use smp_store_release(). This ensures all prior internal
memory structures are entirely flushed and visible to other execution
cores.
Cc: Nicolas Dufresne <nicolas@ndufresne.ca>
Signed-off-by: Anand Moon <linux.amoon@gmail.com>
---
drivers/staging/media/meson/vdec/esparser.c | 2 +-
drivers/staging/media/meson/vdec/vdec.c | 88 ++++++++++++++-------
2 files changed, 59 insertions(+), 31 deletions(-)
diff --git a/drivers/staging/media/meson/vdec/esparser.c b/drivers/staging/media/meson/vdec/esparser.c
index e5d3d817b9b2b..959673742e699 100644
--- a/drivers/staging/media/meson/vdec/esparser.c
+++ b/drivers/staging/media/meson/vdec/esparser.c
@@ -379,7 +379,7 @@ void esparser_queue_all_src(struct work_struct *work)
scoped_guard(mutex, &sess->lock) {
/* Safe atomic tracking check: exit loop if session is shutting down */
- if (sess->should_stop)
+ if (READ_ONCE(sess->should_stop))
return;
/* Queue completely empty: exit work loop cleanly */
diff --git a/drivers/staging/media/meson/vdec/vdec.c b/drivers/staging/media/meson/vdec/vdec.c
index 6fe9722577179..83a9b1238972a 100644
--- a/drivers/staging/media/meson/vdec/vdec.c
+++ b/drivers/staging/media/meson/vdec/vdec.c
@@ -287,9 +287,13 @@ static int vdec_start_streaming(struct vb2_queue *q, unsigned int count)
struct amvdec_session *sess = vb2_get_drv_priv(q);
struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
struct amvdec_core *core = sess->core;
+ struct device *dev = core->dev_dec;
struct vb2_v4l2_buffer *buf;
int ret;
+ /* Reset workqueue loop shutdown signal to allow streaming */
+ WRITE_ONCE(sess->should_stop, 0);
+
if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
sess->streamon_out = 1;
else
@@ -336,7 +340,7 @@ static int vdec_start_streaming(struct vb2_queue *q, unsigned int count)
dma_alloc_coherent(sess->core->dev, sess->vififo_size,
&sess->vififo_paddr, GFP_KERNEL);
if (!sess->vififo_vaddr) {
- dev_err(sess->core->dev, "Failed to request VIFIFO buffer\n");
+ dev_err(dev, "Failed to request VIFIFO buffer\n");
ret = -ENOMEM;
goto err_cleanup_session;
}
@@ -388,10 +392,12 @@ static int vdec_start_streaming(struct vb2_queue *q, unsigned int count)
sess->streamon_cap = 0;
mutex_lock(&core->lock);
- if (core->cur_sess == sess)
- core->cur_sess = NULL;
- if (sess->status != STATUS_NEEDS_RESUME)
- sess->status = STATUS_STOPPED;
+ if (core->cur_sess == sess) {
+ /* Safely clear hardware ownership since we were confirmed as the owner */
+ smp_store_release(&core->cur_sess, NULL);
+ if (sess->status != STATUS_NEEDS_RESUME)
+ sess->status = STATUS_STOPPED;
+ }
mutex_unlock(&core->lock);
err_unlock_no_hw:
while ((buf = v4l2_m2m_src_buf_remove(sess->m2m_ctx)))
@@ -441,6 +447,9 @@ static void vdec_stop_streaming(struct vb2_queue *q)
enum amvdec_status old_status;
bool full_cleanup = false;
+ /* Signal workqueue loop to abort instantly */
+ WRITE_ONCE(sess->should_stop, 1);
+
/* flush buffers to kill background workqueue thread */
if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
while ((buf = v4l2_m2m_src_buf_remove(sess->m2m_ctx)))
@@ -493,26 +502,33 @@ static void vdec_stop_streaming(struct vb2_queue *q)
cancel_work_sync(&sess->esparser_queue_work);
mutex_lock(&core->lock);
- vdec_poweroff(sess);
- vdec_free_canvas(sess);
+ if (core->cur_sess == sess) {
+ vdec_poweroff(sess);
+ vdec_free_canvas(sess);
+
+ if (sess->vififo_vaddr) {
+ dma_free_coherent(sess->core->dev,
+ sess->vififo_size,
+ sess->vififo_vaddr,
+ sess->vififo_paddr);
+ sess->vififo_vaddr = NULL;
+ sess->vififo_paddr = 0;
+ }
- if (sess->vififo_vaddr) {
- dma_free_coherent(sess->core->dev, sess->vififo_size,
- sess->vififo_vaddr, sess->vififo_paddr);
- sess->vififo_vaddr = NULL;
- sess->vififo_paddr = 0;
- }
+ vdec_reset_timestamps(sess);
+ vdec_reset_bufs_recycle(sess);
- vdec_reset_timestamps(sess);
- vdec_reset_bufs_recycle(sess);
- core->cur_sess = NULL;
+ kfree(sess->priv);
+ sess->priv = NULL;
- kfree(sess->priv);
- sess->priv = NULL;
+ /* Safely clear hardware ownership since we were confirmed as the owner */
+ smp_store_release(&core->cur_sess, NULL);
+ }
} else {
if (sess->status == STATUS_NEEDS_RESUME)
sess->changed_format = 0;
}
+
mutex_unlock(&core->lock);
}
@@ -802,7 +818,7 @@ vdec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd)
if (cmd->cmd == V4L2_DEC_CMD_START) {
v4l2_m2m_clear_state(sess->m2m_ctx);
- sess->should_stop = 0;
+ WRITE_ONCE(sess->should_stop, 0);
return 0;
}
@@ -812,7 +828,7 @@ vdec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd)
dev_dbg(dev, "Received V4L2_DEC_CMD_STOP\n");
- sess->should_stop = 1;
+ WRITE_ONCE(sess->should_stop, 1);
v4l2_m2m_mark_stopped(sess->m2m_ctx);
@@ -998,6 +1014,9 @@ static int vdec_close(struct file *file)
struct amvdec_session *sess = file_to_amvdec_session(file);
struct amvdec_core *core = sess->core;
+ /* Signal workqueue loop to abort instantly */
+ WRITE_ONCE(sess->should_stop, 1);
+
/* Synchronize and flush pending hardware interrupt service routines */
synchronize_irq(core->vdec_irq);
/* Ensure esparser ISR finishes executing */
@@ -1012,21 +1031,30 @@ static int vdec_close(struct file *file)
mutex_lock(&core->lock);
- vdec_poweroff(sess);
- vdec_free_canvas(sess);
- core->cur_sess = NULL;
+ if (core->cur_sess == sess) {
+ vdec_poweroff(sess);
+ vdec_free_canvas(sess);
- if (sess->vififo_vaddr) {
- dma_free_coherent(core->dev, sess->vififo_size,
- sess->vififo_vaddr, sess->vififo_paddr);
- sess->vififo_vaddr = NULL;
- sess->vififo_paddr = 0;
+ if (sess->vififo_vaddr) {
+ dma_free_coherent(core->dev,
+ sess->vififo_size,
+ sess->vififo_vaddr,
+ sess->vififo_paddr);
+ sess->vififo_vaddr = NULL;
+ sess->vififo_paddr = 0;
+ }
+ vdec_reset_timestamps(sess);
+ vdec_reset_bufs_recycle(sess);
}
- vdec_reset_timestamps(sess);
- vdec_reset_bufs_recycle(sess);
+
kfree(sess->priv);
sess->priv = NULL;
+ /* Unconditionally set our local status to stopped */
+ sess->status = STATUS_STOPPED;
+ /* Safely clear hardware ownership since we were confirmed as the owner */
+ smp_store_release(&core->cur_sess, NULL);
+
mutex_unlock(&core->lock);
v4l2_m2m_ctx_release(sess->m2m_ctx);
--
2.50.1
WARNING: multiple messages have this Message-ID (diff)
From: Anand Moon <linux.amoon@gmail.com>
To: Neil Armstrong <neil.armstrong@linaro.org>,
Maarten Lankhorst <maarten.lankhorst@linux.intel.com>,
Maxime Ripard <mripard@kernel.org>,
Thomas Zimmermann <tzimmermann@suse.de>,
David Airlie <airlied@gmail.com>, Simona Vetter <simona@ffwll.ch>,
Kevin Hilman <khilman@baylibre.com>,
Jerome Brunet <jbrunet@baylibre.com>,
Martin Blumenstingl <martin.blumenstingl@googlemail.com>,
Mauro Carvalho Chehab <mchehab@kernel.org>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
dri-devel@lists.freedesktop.org (open list:DRM DRIVERS FOR
AMLOGIC SOCS),
linux-amlogic@lists.infradead.org (open list:DRM DRIVERS FOR
AMLOGIC SOCS),
linux-arm-kernel@lists.infradead.org (moderated list:ARM/Amlogic
Meson SoC support), linux-kernel@vger.kernel.org (open list),
linux-media@vger.kernel.org (open list:MESON VIDEO DECODER
DRIVER FOR AMLOGIC SOCS),
linux-staging@lists.linux.dev (open list:STAGING SUBSYSTEM)
Cc: Doruk Tan Ozturk <doruk@0sec.ai>,
Nicolas Dufresne <nicolas@ndufresne.ca>
Subject: [PATCH v7 08/19] media: meson: vdec: Fix concurrent execution races and unsafe teardown
Date: Mon, 13 Jul 2026 17:37:03 +0530 [thread overview]
Message-ID: <20260713120840.17427-9-linux.amoon@gmail.com> (raw)
In-Reply-To: <20260713120840.17427-1-linux.amoon@gmail.com>
Address data races involving 'should_stop' and prevent multi-session
hardware clobbering by enforcing atomic tracking and strict owner
validation during device teardown.
The esparser work queue reads 'sess->should_stop' outside of critical
regions without serialization primitives, risking data races or visibility
delays. Furthermore, vdec_close() and vdec_stop_streaming() blindly
shut down hardware components (via poweroff and canvas frees) and nullify
'core->cur_sess' without confirming that the executing session actually
owns the active hardware context. In multi-session scenarios, this allows
a closing inactive session to inadvertently break a running session.
To fix these synchronization and lifecycle issues with the following
changes use thread-safe flagging: Wrap reads and writes of
'sess->should_stop' in READ_ONCE() and WRITE_ONCE() to prevent compiler
optimizations from caching the condition variables across scheduling
boundaries and optimizations across workqueue execution threads.
Also safe context releasing: transition 'core->cur_sess' pointer
clearings to use smp_store_release(). This ensures all prior internal
memory structures are entirely flushed and visible to other execution
cores.
Cc: Nicolas Dufresne <nicolas@ndufresne.ca>
Signed-off-by: Anand Moon <linux.amoon@gmail.com>
---
drivers/staging/media/meson/vdec/esparser.c | 2 +-
drivers/staging/media/meson/vdec/vdec.c | 88 ++++++++++++++-------
2 files changed, 59 insertions(+), 31 deletions(-)
diff --git a/drivers/staging/media/meson/vdec/esparser.c b/drivers/staging/media/meson/vdec/esparser.c
index e5d3d817b9b2b..959673742e699 100644
--- a/drivers/staging/media/meson/vdec/esparser.c
+++ b/drivers/staging/media/meson/vdec/esparser.c
@@ -379,7 +379,7 @@ void esparser_queue_all_src(struct work_struct *work)
scoped_guard(mutex, &sess->lock) {
/* Safe atomic tracking check: exit loop if session is shutting down */
- if (sess->should_stop)
+ if (READ_ONCE(sess->should_stop))
return;
/* Queue completely empty: exit work loop cleanly */
diff --git a/drivers/staging/media/meson/vdec/vdec.c b/drivers/staging/media/meson/vdec/vdec.c
index 6fe9722577179..83a9b1238972a 100644
--- a/drivers/staging/media/meson/vdec/vdec.c
+++ b/drivers/staging/media/meson/vdec/vdec.c
@@ -287,9 +287,13 @@ static int vdec_start_streaming(struct vb2_queue *q, unsigned int count)
struct amvdec_session *sess = vb2_get_drv_priv(q);
struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
struct amvdec_core *core = sess->core;
+ struct device *dev = core->dev_dec;
struct vb2_v4l2_buffer *buf;
int ret;
+ /* Reset workqueue loop shutdown signal to allow streaming */
+ WRITE_ONCE(sess->should_stop, 0);
+
if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
sess->streamon_out = 1;
else
@@ -336,7 +340,7 @@ static int vdec_start_streaming(struct vb2_queue *q, unsigned int count)
dma_alloc_coherent(sess->core->dev, sess->vififo_size,
&sess->vififo_paddr, GFP_KERNEL);
if (!sess->vififo_vaddr) {
- dev_err(sess->core->dev, "Failed to request VIFIFO buffer\n");
+ dev_err(dev, "Failed to request VIFIFO buffer\n");
ret = -ENOMEM;
goto err_cleanup_session;
}
@@ -388,10 +392,12 @@ static int vdec_start_streaming(struct vb2_queue *q, unsigned int count)
sess->streamon_cap = 0;
mutex_lock(&core->lock);
- if (core->cur_sess == sess)
- core->cur_sess = NULL;
- if (sess->status != STATUS_NEEDS_RESUME)
- sess->status = STATUS_STOPPED;
+ if (core->cur_sess == sess) {
+ /* Safely clear hardware ownership since we were confirmed as the owner */
+ smp_store_release(&core->cur_sess, NULL);
+ if (sess->status != STATUS_NEEDS_RESUME)
+ sess->status = STATUS_STOPPED;
+ }
mutex_unlock(&core->lock);
err_unlock_no_hw:
while ((buf = v4l2_m2m_src_buf_remove(sess->m2m_ctx)))
@@ -441,6 +447,9 @@ static void vdec_stop_streaming(struct vb2_queue *q)
enum amvdec_status old_status;
bool full_cleanup = false;
+ /* Signal workqueue loop to abort instantly */
+ WRITE_ONCE(sess->should_stop, 1);
+
/* flush buffers to kill background workqueue thread */
if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
while ((buf = v4l2_m2m_src_buf_remove(sess->m2m_ctx)))
@@ -493,26 +502,33 @@ static void vdec_stop_streaming(struct vb2_queue *q)
cancel_work_sync(&sess->esparser_queue_work);
mutex_lock(&core->lock);
- vdec_poweroff(sess);
- vdec_free_canvas(sess);
+ if (core->cur_sess == sess) {
+ vdec_poweroff(sess);
+ vdec_free_canvas(sess);
+
+ if (sess->vififo_vaddr) {
+ dma_free_coherent(sess->core->dev,
+ sess->vififo_size,
+ sess->vififo_vaddr,
+ sess->vififo_paddr);
+ sess->vififo_vaddr = NULL;
+ sess->vififo_paddr = 0;
+ }
- if (sess->vififo_vaddr) {
- dma_free_coherent(sess->core->dev, sess->vififo_size,
- sess->vififo_vaddr, sess->vififo_paddr);
- sess->vififo_vaddr = NULL;
- sess->vififo_paddr = 0;
- }
+ vdec_reset_timestamps(sess);
+ vdec_reset_bufs_recycle(sess);
- vdec_reset_timestamps(sess);
- vdec_reset_bufs_recycle(sess);
- core->cur_sess = NULL;
+ kfree(sess->priv);
+ sess->priv = NULL;
- kfree(sess->priv);
- sess->priv = NULL;
+ /* Safely clear hardware ownership since we were confirmed as the owner */
+ smp_store_release(&core->cur_sess, NULL);
+ }
} else {
if (sess->status == STATUS_NEEDS_RESUME)
sess->changed_format = 0;
}
+
mutex_unlock(&core->lock);
}
@@ -802,7 +818,7 @@ vdec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd)
if (cmd->cmd == V4L2_DEC_CMD_START) {
v4l2_m2m_clear_state(sess->m2m_ctx);
- sess->should_stop = 0;
+ WRITE_ONCE(sess->should_stop, 0);
return 0;
}
@@ -812,7 +828,7 @@ vdec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd)
dev_dbg(dev, "Received V4L2_DEC_CMD_STOP\n");
- sess->should_stop = 1;
+ WRITE_ONCE(sess->should_stop, 1);
v4l2_m2m_mark_stopped(sess->m2m_ctx);
@@ -998,6 +1014,9 @@ static int vdec_close(struct file *file)
struct amvdec_session *sess = file_to_amvdec_session(file);
struct amvdec_core *core = sess->core;
+ /* Signal workqueue loop to abort instantly */
+ WRITE_ONCE(sess->should_stop, 1);
+
/* Synchronize and flush pending hardware interrupt service routines */
synchronize_irq(core->vdec_irq);
/* Ensure esparser ISR finishes executing */
@@ -1012,21 +1031,30 @@ static int vdec_close(struct file *file)
mutex_lock(&core->lock);
- vdec_poweroff(sess);
- vdec_free_canvas(sess);
- core->cur_sess = NULL;
+ if (core->cur_sess == sess) {
+ vdec_poweroff(sess);
+ vdec_free_canvas(sess);
- if (sess->vififo_vaddr) {
- dma_free_coherent(core->dev, sess->vififo_size,
- sess->vififo_vaddr, sess->vififo_paddr);
- sess->vififo_vaddr = NULL;
- sess->vififo_paddr = 0;
+ if (sess->vififo_vaddr) {
+ dma_free_coherent(core->dev,
+ sess->vififo_size,
+ sess->vififo_vaddr,
+ sess->vififo_paddr);
+ sess->vififo_vaddr = NULL;
+ sess->vififo_paddr = 0;
+ }
+ vdec_reset_timestamps(sess);
+ vdec_reset_bufs_recycle(sess);
}
- vdec_reset_timestamps(sess);
- vdec_reset_bufs_recycle(sess);
+
kfree(sess->priv);
sess->priv = NULL;
+ /* Unconditionally set our local status to stopped */
+ sess->status = STATUS_STOPPED;
+ /* Safely clear hardware ownership since we were confirmed as the owner */
+ smp_store_release(&core->cur_sess, NULL);
+
mutex_unlock(&core->lock);
v4l2_m2m_ctx_release(sess->m2m_ctx);
--
2.50.1
_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic
next prev parent reply other threads:[~2026-07-13 12:10 UTC|newest]
Thread overview: 102+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-13 12:06 [PATCH v7 00/19] media: meson: vdec: Fix lifecycles, race conditions, and stability bugs Anand Moon
2026-07-13 12:06 ` Anand Moon
2026-07-13 12:06 ` Anand Moon
2026-07-13 12:06 ` [PATCH v7 01/19] media: meson: vdec: Fix m2m device lifetime and cleanup path Anand Moon
2026-07-13 12:06 ` Anand Moon
2026-07-13 12:06 ` Anand Moon
2026-07-13 12:35 ` sashiko-bot
2026-07-13 12:35 ` sashiko-bot
2026-07-13 12:06 ` [PATCH v7 02/19] media: meson: vdec: Fix STREAMON / STREAMOFF race conditions and session teardown Anand Moon
2026-07-13 12:06 ` Anand Moon
2026-07-13 12:06 ` Anand Moon
2026-07-13 12:38 ` sashiko-bot
2026-07-13 12:38 ` sashiko-bot
2026-07-13 12:06 ` [PATCH v7 03/19] media: meson: vdec: Fix lifecycle leaks and race conditions in recycle_thread Anand Moon
2026-07-13 12:06 ` Anand Moon
2026-07-13 12:06 ` Anand Moon
2026-07-13 12:32 ` sashiko-bot
2026-07-13 12:32 ` sashiko-bot
2026-07-13 12:06 ` [PATCH v7 04/19] media: meson: vdec: Fix use-after-free race between teardown and ISR routines Anand Moon
2026-07-13 12:06 ` Anand Moon
2026-07-13 12:06 ` Anand Moon
2026-07-13 12:23 ` sashiko-bot
2026-07-13 12:23 ` sashiko-bot
2026-07-13 12:07 ` [PATCH v7 05/19] media: meson: vdec: Fix race condition and synchronize esparser IRQ Anand Moon
2026-07-13 12:07 ` Anand Moon
2026-07-13 12:07 ` Anand Moon
2026-07-13 12:28 ` sashiko-bot
2026-07-13 12:28 ` sashiko-bot
2026-07-13 12:07 ` [PATCH v7 06/19] media: meson: vdec: Fix race condition by canceling work sync Anand Moon
2026-07-13 12:07 ` Anand Moon
2026-07-13 12:07 ` Anand Moon
2026-07-13 12:33 ` sashiko-bot
2026-07-13 12:33 ` sashiko-bot
2026-07-13 12:07 ` [PATCH v7 07/19] media: meson: vdec: Refactor esparser work queue and fix teardown race Anand Moon
2026-07-13 12:07 ` Anand Moon
2026-07-13 12:07 ` Anand Moon
2026-07-13 12:27 ` sashiko-bot
2026-07-13 12:27 ` sashiko-bot
2026-07-13 12:07 ` Anand Moon [this message]
2026-07-13 12:07 ` [PATCH v7 08/19] media: meson: vdec: Fix concurrent execution races and unsafe teardown Anand Moon
2026-07-13 12:07 ` Anand Moon
2026-07-13 12:42 ` sashiko-bot
2026-07-13 12:42 ` sashiko-bot
2026-07-13 12:07 ` [PATCH v7 09/19] media: meson: vdec: Fix vp9 header update failure on invalid payloads Anand Moon
2026-07-13 12:07 ` Anand Moon
2026-07-13 12:07 ` Anand Moon
2026-07-13 12:42 ` sashiko-bot
2026-07-13 12:42 ` sashiko-bot
2026-07-13 12:07 ` [PATCH v7 10/19] media: meson: vdec: Fix race conditions and leaks in esparser pipeline Anand Moon
2026-07-13 12:07 ` Anand Moon
2026-07-13 12:07 ` Anand Moon
2026-07-13 12:46 ` sashiko-bot
2026-07-13 12:46 ` sashiko-bot
2026-07-13 12:07 ` [PATCH v7 11/19] media: meson: vdec: Update core m2m stream state during transitions Anand Moon
2026-07-13 12:07 ` Anand Moon
2026-07-13 12:07 ` Anand Moon
2026-07-13 12:48 ` sashiko-bot
2026-07-13 12:48 ` sashiko-bot
2026-07-13 12:07 ` [PATCH v7 12/19] media: meson: vdec: Coordinate m2m task execution inside async loop Anand Moon
2026-07-13 12:07 ` Anand Moon
2026-07-13 12:07 ` Anand Moon
2026-07-13 12:54 ` sashiko-bot
2026-07-13 12:54 ` sashiko-bot
2026-07-13 12:07 ` [PATCH v7 13/19] media: meson: vdec: Fix race conditions in job abort sequence Anand Moon
2026-07-13 12:07 ` Anand Moon
2026-07-13 12:07 ` Anand Moon
2026-07-13 12:55 ` sashiko-bot
2026-07-13 12:55 ` sashiko-bot
2026-07-13 12:07 ` [PATCH v7 14/19] media: meson: vdec: Correct atomic counter placement in dst_buf_done Anand Moon
2026-07-13 12:07 ` Anand Moon
2026-07-13 12:07 ` Anand Moon
2026-07-13 12:48 ` sashiko-bot
2026-07-13 12:48 ` sashiko-bot
2026-07-13 12:07 ` [PATCH v7 15/19] media: meson: vdec: Fix concurrent firmware loading race and hardware timeout Anand Moon
2026-07-13 12:07 ` Anand Moon
2026-07-13 12:07 ` Anand Moon
2026-07-13 12:56 ` sashiko-bot
2026-07-13 12:56 ` sashiko-bot
2026-07-13 12:07 ` [PATCH v7 16/19] media: meson: vdec: Configure DMA mask and segment size in probe Anand Moon
2026-07-13 12:07 ` Anand Moon
2026-07-13 12:07 ` Anand Moon
2026-07-13 12:55 ` sashiko-bot
2026-07-13 12:55 ` sashiko-bot
2026-07-13 12:07 ` [PATCH v7 17/19] media: meson: canvas: Fix Use-After-Free by linking canvas provider device Anand Moon
2026-07-13 12:07 ` Anand Moon
2026-07-13 12:07 ` Anand Moon
2026-07-13 12:58 ` sashiko-bot
2026-07-13 12:58 ` sashiko-bot
2026-07-13 12:07 ` [PATCH v7 18/19] media: meson: vdec: Increase VIFIFO buffer size to 32 MiB Anand Moon
2026-07-13 12:07 ` Anand Moon
2026-07-13 12:07 ` Anand Moon
2026-07-13 13:06 ` sashiko-bot
2026-07-13 13:06 ` sashiko-bot
2026-07-13 12:07 ` [PATCH v7 19/19] gpu: drm: meson: Fix DMA segment size limits and maximize allocation boundaries Anand Moon
2026-07-13 12:07 ` Anand Moon
2026-07-13 12:07 ` Anand Moon
2026-07-13 12:57 ` sashiko-bot
2026-07-13 12:57 ` sashiko-bot
2026-07-13 14:04 ` Nicolas Dufresne
2026-07-13 14:04 ` Nicolas Dufresne
2026-07-14 7:23 ` [PATCH v7 00/19] media: meson: vdec: Fix lifecycles, race conditions, and stability bugs Anand Moon
2026-07-14 7:23 ` Anand Moon
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=20260713120840.17427-9-linux.amoon@gmail.com \
--to=linux.amoon@gmail.com \
--cc=airlied@gmail.com \
--cc=doruk@0sec.ai \
--cc=dri-devel@lists.freedesktop.org \
--cc=gregkh@linuxfoundation.org \
--cc=jbrunet@baylibre.com \
--cc=khilman@baylibre.com \
--cc=linux-amlogic@lists.infradead.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-media@vger.kernel.org \
--cc=linux-staging@lists.linux.dev \
--cc=maarten.lankhorst@linux.intel.com \
--cc=martin.blumenstingl@googlemail.com \
--cc=mchehab@kernel.org \
--cc=mripard@kernel.org \
--cc=neil.armstrong@linaro.org \
--cc=nicolas@ndufresne.ca \
--cc=simona@ffwll.ch \
--cc=tzimmermann@suse.de \
/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.