diff --git a/videobuf.c b/videobuf.c index dd5298a..7d63b0d 100644 --- a/videobuf.c +++ b/videobuf.c @@ -70,8 +70,9 @@ static int vcam_start_streaming(struct vb2_queue *q, unsigned int count) /* Try to start kernel thread */ dev->sub_thr_id = kthread_create(submitter_thread, dev, "vcam_submitter"); - if (!dev->sub_thr_id) { + if (IS_ERR(dev->sub_thr_id)) { pr_err("Failed to create kernel thread\n"); + dev->sub_thr_id = NULL; return -ECANCELED; } @@ -85,22 +86,25 @@ static void vcam_stop_streaming(struct vb2_queue *vb2_q) struct vcam_device *dev = vb2_q->drv_priv; struct vcam_out_queue *q = &dev->vcam_out_vidq; unsigned long flags = 0; + LIST_HEAD(tmp_list); - /* Stop running threads */ if (dev->sub_thr_id) kthread_stop(dev->sub_thr_id); - dev->sub_thr_id = NULL; - /* Empty buffer queue */ + + /* Collect buffers under spinlock, return them to vb2 outside it. + * vb2_buffer_done() must not be called while holding a spinlock. */ spin_lock_irqsave(&dev->out_q_slock, flags); - while (!list_empty(&q->active)) { + list_splice_init(&q->active, &tmp_list); + spin_unlock_irqrestore(&dev->out_q_slock, flags); + + while (!list_empty(&tmp_list)) { struct vcam_out_buffer *buf = - list_entry(q->active.next, struct vcam_out_buffer, list); + list_entry(tmp_list.next, struct vcam_out_buffer, list); list_del(&buf->list); vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); pr_debug("Throwing out buffer\n"); } - spin_unlock_irqrestore(&dev->out_q_slock, flags); } static void vcam_outbuf_lock(struct vb2_queue *vq)