Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0cf4daee authored by Brandon Philips's avatar Brandon Philips Committed by Mauro Carvalho Chehab
Browse files

V4L/DVB (7562): videobuf: Require spinlocks for all videobuf users



A spinlock is necessary for queue_cancel to work with every driver in the tree.
Otherwise a race exists between IRQ handlers removing buffers from the queue
and queue_cancel invalidating the queue.

Signed-off-by: default avatarBrandon Philips <bphilips@suse.de>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent aa9479ed
Loading
Loading
Loading
Loading
+18 −28
Original line number Diff line number Diff line
@@ -123,6 +123,9 @@ void videobuf_queue_core_init(struct videobuf_queue *q,
	BUG_ON(!q->ops->buf_queue);
	BUG_ON(!q->ops->buf_release);

	/* Lock is mandatory for queue_cancel to work */
	BUG_ON(!irqlock);

	/* Having implementations for abstract methods are mandatory */
	BUG_ON(!q->int_ops);

@@ -180,7 +183,6 @@ void videobuf_queue_cancel(struct videobuf_queue *q)
	wake_up_interruptible_sync(&q->wait);

	/* remove queued buffers from list */
	if (q->irqlock)
	spin_lock_irqsave(q->irqlock, flags);
	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
		if (NULL == q->bufs[i])
@@ -191,7 +193,6 @@ void videobuf_queue_cancel(struct videobuf_queue *q)
			wake_up_all(&q->bufs[i]->done);
		}
	}
	if (q->irqlock)
	spin_unlock_irqrestore(q->irqlock, flags);

	/* free all buffers + clear queue */
@@ -548,10 +549,8 @@ int videobuf_qbuf(struct videobuf_queue *q,

	list_add_tail(&buf->stream, &q->stream);
	if (q->streaming) {
		if (q->irqlock)
		spin_lock_irqsave(q->irqlock, flags);
		q->ops->buf_queue(q, buf);
		if (q->irqlock)
		spin_unlock_irqrestore(q->irqlock, flags);
	}
	dprintk(1, "qbuf: succeded\n");
@@ -689,12 +688,10 @@ int videobuf_streamon(struct videobuf_queue *q)
	if (q->streaming)
		goto done;
	q->streaming = 1;
	if (q->irqlock)
	spin_lock_irqsave(q->irqlock, flags);
	list_for_each_entry(buf, &q->stream, stream)
		if (buf->state == VIDEOBUF_PREPARED)
			q->ops->buf_queue(q, buf);
	if (q->irqlock)
	spin_unlock_irqrestore(q->irqlock, flags);

	wake_up_interruptible_sync(&q->wait);
@@ -751,10 +748,8 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q,
		goto done;

	/* start capture & wait */
	if (q->irqlock)
	spin_lock_irqsave(q->irqlock, flags);
	q->ops->buf_queue(q, q->read_buf);
	if (q->irqlock)
	spin_unlock_irqrestore(q->irqlock, flags);
	retval = videobuf_waiton(q->read_buf, 0, 0);
	if (0 == retval) {
@@ -816,12 +811,11 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
			q->read_buf = NULL;
			goto done;
		}
		if (q->irqlock)
			spin_lock_irqsave(q->irqlock, flags);

		spin_lock_irqsave(q->irqlock, flags);
		q->ops->buf_queue(q, q->read_buf);
		if (q->irqlock)
		spin_unlock_irqrestore(q->irqlock, flags);

		q->read_off = 0;
	}

@@ -887,11 +881,9 @@ static int __videobuf_read_start(struct videobuf_queue *q)
			return err;
		list_add_tail(&q->bufs[i]->stream, &q->stream);
	}
	if (q->irqlock)
	spin_lock_irqsave(q->irqlock, flags);
	for (i = 0; i < count; i++)
		q->ops->buf_queue(q, q->bufs[i]);
	if (q->irqlock)
	spin_unlock_irqrestore(q->irqlock, flags);
	q->reading = 1;
	return 0;
@@ -1004,10 +996,8 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
		if (q->read_off == q->read_buf->size) {
			list_add_tail(&q->read_buf->stream,
				      &q->stream);
			if (q->irqlock)
			spin_lock_irqsave(q->irqlock, flags);
			q->ops->buf_queue(q, q->read_buf);
			if (q->irqlock)
			spin_unlock_irqrestore(q->irqlock, flags);
			q->read_buf = NULL;
		}