spin_lock_irqsave(&dev->lock, flags);
        if (ctx->src_vbs[2]) {
                v4l2_m2m_buf_done(ctx->src_vbs[2], VB2_BUF_STATE_DONE);
-               v4l2_m2m_buf_done(ctx->src_vbs[1], VB2_BUF_STATE_DONE);
+               if (ctx->src_vbs[1] && (ctx->src_vbs[1] != ctx->src_vbs[2]))
+                       v4l2_m2m_buf_done(ctx->src_vbs[1], VB2_BUF_STATE_DONE);
+               ctx->src_vbs[2] = NULL;
+               ctx->src_vbs[1] = NULL;
        }
        spin_unlock_irqrestore(&dev->lock, flags);
 }
                ctx->src_vbs[1] = ctx->src_vbs[0];
        }
 
+       /*
+        * Since the vb2_buf_done has already been called fir therse
+        * buffer we can now NULL them out so that we won't try
+        * to clean out stray pointer later on.
+       */
+       ctx->src_vbs[0] = NULL;
+       ctx->dst_vb = NULL;
+
        ctx->bufs_completed++;
        if (ctx->bufs_completed < ctx->bufs_per_job && job_ready(ctx)) {
                device_run(ctx);
 static void vpe_stop_streaming(struct vb2_queue *q)
 {
        struct vpe_ctx *ctx = vb2_get_drv_priv(q);
+       struct vb2_v4l2_buffer *vb;
+       unsigned long flags;
 
        vpe_dump_regs(ctx->dev);
        vpdma_dump_regs(ctx->dev->vpdma);
+
+       for (;;) {
+               if (V4L2_TYPE_IS_OUTPUT(q->type))
+                       vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+               else
+                       vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+               if (!vb)
+                       break;
+               spin_lock_irqsave(&ctx->dev->lock, flags);
+               v4l2_m2m_buf_done(vb, VB2_BUF_STATE_ERROR);
+               spin_unlock_irqrestore(&ctx->dev->lock, flags);
+       }
+
+       /*
+        * Cleanup the in-transit vb2 buffers that have been
+        * removed from their respective queue already but for
+        * which procecessing has not been completed yet.
+        */
+       if (V4L2_TYPE_IS_OUTPUT(q->type)) {
+               spin_lock_irqsave(&ctx->dev->lock, flags);
+
+               if (ctx->src_vbs[2])
+                       v4l2_m2m_buf_done(ctx->src_vbs[2], VB2_BUF_STATE_ERROR);
+
+               if (ctx->src_vbs[1] && (ctx->src_vbs[1] != ctx->src_vbs[2]))
+                       v4l2_m2m_buf_done(ctx->src_vbs[1], VB2_BUF_STATE_ERROR);
+
+               if (ctx->src_vbs[0] &&
+                   (ctx->src_vbs[0] != ctx->src_vbs[1]) &&
+                   (ctx->src_vbs[0] != ctx->src_vbs[2]))
+                       v4l2_m2m_buf_done(ctx->src_vbs[0], VB2_BUF_STATE_ERROR);
+
+               ctx->src_vbs[2] = NULL;
+               ctx->src_vbs[1] = NULL;
+               ctx->src_vbs[0] = NULL;
+
+               spin_unlock_irqrestore(&ctx->dev->lock, flags);
+       } else {
+               if (ctx->dst_vb) {
+                       spin_lock_irqsave(&ctx->dev->lock, flags);
+
+                       v4l2_m2m_buf_done(ctx->dst_vb, VB2_BUF_STATE_ERROR);
+                       ctx->dst_vb = NULL;
+                       spin_unlock_irqrestore(&ctx->dev->lock, flags);
+               }
+       }
 }
 
 static const struct vb2_ops vpe_qops = {
        vpe_dbg(dev, "releasing instance %p\n", ctx);
 
        mutex_lock(&dev->dev_mutex);
-       free_vbs(ctx);
        free_mv_buffers(ctx);
        vpdma_free_desc_list(&ctx->desc_list);
        vpdma_free_desc_buf(&ctx->mmr_adb);