camera(videobuf-core): fix deadlock in videobuf core, because dqueue ioctl havn't...
authorddl <ddl@rock-chips.com>
Tue, 29 Nov 2011 12:08:07 +0000 (20:08 +0800)
committerddl <ddl@rock-chips.com>
Tue, 29 Nov 2011 12:09:14 +0000 (20:09 +0800)
drivers/media/video/videobuf-core.c

index 57978bf6defe47fd5fec8ee80bebc11c384e20b5..5badba86d0352eb617a9577e9cc5fe0053d5ebc6 100644 (file)
@@ -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);