On Wed Jun 24 00:32:08 2026 +0000, Fan Wu wrote:
> mxc_jpeg_device_run() returns early through a shared "end" label on several
> error paths (no free slot, mxc_jpeg_alloc_slot_data() failure, or missing
> buffers or queue data), and none of them calls v4l2_m2m_job_finish().
> Since the delayed work is queued only after the hardware is started, those
> paths neither finish the job directly nor queue timeout work that could
> finish it later. The job is left with TRANS_RUNNING set, so the
> wait_event() in v4l2_m2m_cancel_job() (reached from v4l2_m2m_ctx_release()
> at close) waits indefinitely and the close hangs.
> 
> mxc_jpeg_alloc_slot_data() uses dma_alloc_coherent(), so the failure path
> is reachable under memory pressure.
> 
> Return the src/dst buffers with VB2_BUF_STATE_ERROR and call
> v4l2_m2m_job_finish() on those paths: paths that have buffers use a
> "buf_finish" label; the no-buffer path uses "job_finish" directly. This
> mirrors the existing jpeg_parse_error path.
> 
> This bug was found by static analysis.
> 
> Fixes: 2db16c6ed72c ("media: imx-jpeg: Add V4L2 driver for i.MX8 JPEG 
> Encoder/Decoder")
> Cc: [email protected]
> Signed-off-by: Fan Wu <[email protected]>
> Reviewed-by: Ming Qian <[email protected]>
> Signed-off-by: Frank Li <[email protected]>
> Signed-off-by: Hans Verkuil <[email protected]>

Patch committed.

Thanks,
Hans Verkuil

 drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c | 21 +++++++++++++++------
 1 file changed, 15 insertions(+), 6 deletions(-)

---

diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c 
b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
index ea2fad5dd646..e17085935435 100644
--- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
+++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
@@ -1590,15 +1590,15 @@ static void mxc_jpeg_device_run(void *priv)
        dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
        if (!src_buf || !dst_buf) {
                dev_err(dev, "Null src or dst buf\n");
-               goto end;
+               goto job_finish;
        }
 
        q_data_cap = mxc_jpeg_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
        if (!q_data_cap)
-               goto end;
+               goto buf_finish;
        q_data_out = mxc_jpeg_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
        if (!q_data_out)
-               goto end;
+               goto buf_finish;
        src_buf->sequence = q_data_out->sequence++;
        dst_buf->sequence = q_data_cap->sequence++;
 
@@ -1636,11 +1636,11 @@ static void mxc_jpeg_device_run(void *priv)
        ctx->slot = mxc_get_free_slot(&jpeg->slot_data);
        if (ctx->slot < 0) {
                dev_err(dev, "No more free slots\n");
-               goto end;
+               goto buf_finish;
        }
        if (!mxc_jpeg_alloc_slot_data(jpeg)) {
                dev_err(dev, "Cannot allocate slot data\n");
-               goto end;
+               goto buf_finish;
        }
 
        mxc_jpeg_enable_slot(reg, ctx->slot);
@@ -1660,8 +1660,17 @@ static void mxc_jpeg_device_run(void *priv)
                mxc_jpeg_dec_mode_go(dev, reg);
        }
        schedule_delayed_work(&ctx->task_timer, msecs_to_jiffies(hw_timeout));
-end:
+
        spin_unlock_irqrestore(&ctx->mxc_jpeg->hw_lock, flags);
+       return;
+buf_finish:
+       v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+       v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+       v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
+       v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);
+job_finish:
+       spin_unlock_irqrestore(&ctx->mxc_jpeg->hw_lock, flags);
+       v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
 }
 
 static int mxc_jpeg_decoder_cmd(struct file *file, void *priv,
_______________________________________________
linuxtv-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to