From 4b0965a601730ad6a65b588a6f731ef3dd0f6ac3 Mon Sep 17 00:00:00 2001 From: ddl Date: Tue, 29 Nov 2011 20:08:07 +0800 Subject: [PATCH] camera(videobuf-core): fix deadlock in videobuf core, because dqueue ioctl havn't unlock vdev lock when stream is empty --- drivers/media/video/videobuf-core.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index 57978bf6defe..5badba86d035 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -107,11 +107,11 @@ int videobuf_waiton(struct videobuf_queue *q, struct videobuf_buffer *vb, if (intr) ret = wait_event_interruptible(vb->done, is_state_active_or_queued(q, vb)); else - wait_event(vb->done, is_state_active_or_queued(q, vb)); + wait_event(vb->done, is_state_active_or_queued(q, vb)); /* Relock */ if (is_ext_locked) - mutex_lock(q->ext_lock); - + mutex_lock(q->ext_lock); + return ret; } EXPORT_SYMBOL_GPL(videobuf_waiton); @@ -642,6 +642,7 @@ EXPORT_SYMBOL_GPL(videobuf_qbuf); static int stream_next_buffer_check_queue(struct videobuf_queue *q, int noblock) { int retval; + bool is_ext_locked; checks: if (!q->streaming) { @@ -658,16 +659,28 @@ checks: } else { dprintk(2, "next_buffer: waiting on buffer\n"); - /* Drop lock to avoid deadlock with qbuf */ - videobuf_queue_unlock(q); - + /* Drop lock to avoid deadlock with qbuf */ + videobuf_queue_unlock(q); + /*ddl@rock-chips.com */ + is_ext_locked = q->ext_lock && mutex_is_locked(q->ext_lock); + + /* Release vdev lock to prevent this wait from blocking outside access to + the device. */ + if (is_ext_locked) + mutex_unlock(q->ext_lock); + + /* Checking list_empty and streaming is safe without * locks because we goto checks to validate while * holding locks before proceeding */ retval = wait_event_interruptible(q->wait, !list_empty(&q->stream) || !q->streaming); - videobuf_queue_lock(q); + videobuf_queue_lock(q); + /*ddl@rock-chips.com */ + if (is_ext_locked) + mutex_lock(q->ext_lock); + if (retval) goto done; @@ -710,7 +723,7 @@ int videobuf_dqbuf(struct videobuf_queue *q, MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - memset(b, 0, sizeof(*b)); + memset(b, 0, sizeof(*b)); videobuf_queue_lock(q); retval = stream_next_buffer(q, &buf, nonblocking); -- 2.34.1