diff options
author | Brandon Philips <bphilips@suse.de> | 2008-03-28 13:18:33 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-04-24 13:09:16 -0400 |
commit | 0cf4daee31d88086cf3508d1d8d1f4e451c27906 (patch) | |
tree | 522c7f2fa9bbac4682dd00776b606278c485bad5 /drivers/media/video | |
parent | aa9479ed508d78dcd06479dc6274c9b02d1398df (diff) |
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: Brandon Philips <bphilips@suse.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video')
-rw-r--r-- | drivers/media/video/videobuf-core.c | 46 |
1 files changed, 18 insertions, 28 deletions
diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index 45a8cbdf417d..848a2d0e1233 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c | |||
@@ -123,6 +123,9 @@ void videobuf_queue_core_init(struct videobuf_queue *q, | |||
123 | BUG_ON(!q->ops->buf_queue); | 123 | BUG_ON(!q->ops->buf_queue); |
124 | BUG_ON(!q->ops->buf_release); | 124 | BUG_ON(!q->ops->buf_release); |
125 | 125 | ||
126 | /* Lock is mandatory for queue_cancel to work */ | ||
127 | BUG_ON(!irqlock); | ||
128 | |||
126 | /* Having implementations for abstract methods are mandatory */ | 129 | /* Having implementations for abstract methods are mandatory */ |
127 | BUG_ON(!q->int_ops); | 130 | BUG_ON(!q->int_ops); |
128 | 131 | ||
@@ -180,8 +183,7 @@ void videobuf_queue_cancel(struct videobuf_queue *q) | |||
180 | wake_up_interruptible_sync(&q->wait); | 183 | wake_up_interruptible_sync(&q->wait); |
181 | 184 | ||
182 | /* remove queued buffers from list */ | 185 | /* remove queued buffers from list */ |
183 | if (q->irqlock) | 186 | spin_lock_irqsave(q->irqlock, flags); |
184 | spin_lock_irqsave(q->irqlock, flags); | ||
185 | for (i = 0; i < VIDEO_MAX_FRAME; i++) { | 187 | for (i = 0; i < VIDEO_MAX_FRAME; i++) { |
186 | if (NULL == q->bufs[i]) | 188 | if (NULL == q->bufs[i]) |
187 | continue; | 189 | continue; |
@@ -191,8 +193,7 @@ void videobuf_queue_cancel(struct videobuf_queue *q) | |||
191 | wake_up_all(&q->bufs[i]->done); | 193 | wake_up_all(&q->bufs[i]->done); |
192 | } | 194 | } |
193 | } | 195 | } |
194 | if (q->irqlock) | 196 | spin_unlock_irqrestore(q->irqlock, flags); |
195 | spin_unlock_irqrestore(q->irqlock, flags); | ||
196 | 197 | ||
197 | /* free all buffers + clear queue */ | 198 | /* free all buffers + clear queue */ |
198 | for (i = 0; i < VIDEO_MAX_FRAME; i++) { | 199 | for (i = 0; i < VIDEO_MAX_FRAME; i++) { |
@@ -548,11 +549,9 @@ int videobuf_qbuf(struct videobuf_queue *q, | |||
548 | 549 | ||
549 | list_add_tail(&buf->stream, &q->stream); | 550 | list_add_tail(&buf->stream, &q->stream); |
550 | if (q->streaming) { | 551 | if (q->streaming) { |
551 | if (q->irqlock) | 552 | spin_lock_irqsave(q->irqlock, flags); |
552 | spin_lock_irqsave(q->irqlock, flags); | ||
553 | q->ops->buf_queue(q, buf); | 553 | q->ops->buf_queue(q, buf); |
554 | if (q->irqlock) | 554 | spin_unlock_irqrestore(q->irqlock, flags); |
555 | spin_unlock_irqrestore(q->irqlock, flags); | ||
556 | } | 555 | } |
557 | dprintk(1, "qbuf: succeded\n"); | 556 | dprintk(1, "qbuf: succeded\n"); |
558 | retval = 0; | 557 | retval = 0; |
@@ -689,13 +688,11 @@ int videobuf_streamon(struct videobuf_queue *q) | |||
689 | if (q->streaming) | 688 | if (q->streaming) |
690 | goto done; | 689 | goto done; |
691 | q->streaming = 1; | 690 | q->streaming = 1; |
692 | if (q->irqlock) | 691 | spin_lock_irqsave(q->irqlock, flags); |
693 | spin_lock_irqsave(q->irqlock, flags); | ||
694 | list_for_each_entry(buf, &q->stream, stream) | 692 | list_for_each_entry(buf, &q->stream, stream) |
695 | if (buf->state == VIDEOBUF_PREPARED) | 693 | if (buf->state == VIDEOBUF_PREPARED) |
696 | q->ops->buf_queue(q, buf); | 694 | q->ops->buf_queue(q, buf); |
697 | if (q->irqlock) | 695 | spin_unlock_irqrestore(q->irqlock, flags); |
698 | spin_unlock_irqrestore(q->irqlock, flags); | ||
699 | 696 | ||
700 | wake_up_interruptible_sync(&q->wait); | 697 | wake_up_interruptible_sync(&q->wait); |
701 | done: | 698 | done: |
@@ -751,11 +748,9 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q, | |||
751 | goto done; | 748 | goto done; |
752 | 749 | ||
753 | /* start capture & wait */ | 750 | /* start capture & wait */ |
754 | if (q->irqlock) | 751 | spin_lock_irqsave(q->irqlock, flags); |
755 | spin_lock_irqsave(q->irqlock, flags); | ||
756 | q->ops->buf_queue(q, q->read_buf); | 752 | q->ops->buf_queue(q, q->read_buf); |
757 | if (q->irqlock) | 753 | spin_unlock_irqrestore(q->irqlock, flags); |
758 | spin_unlock_irqrestore(q->irqlock, flags); | ||
759 | retval = videobuf_waiton(q->read_buf, 0, 0); | 754 | retval = videobuf_waiton(q->read_buf, 0, 0); |
760 | if (0 == retval) { | 755 | if (0 == retval) { |
761 | CALL(q, sync, q, q->read_buf); | 756 | CALL(q, sync, q, q->read_buf); |
@@ -816,12 +811,11 @@ ssize_t videobuf_read_one(struct videobuf_queue *q, | |||
816 | q->read_buf = NULL; | 811 | q->read_buf = NULL; |
817 | goto done; | 812 | goto done; |
818 | } | 813 | } |
819 | if (q->irqlock) | ||
820 | spin_lock_irqsave(q->irqlock, flags); | ||
821 | 814 | ||
815 | spin_lock_irqsave(q->irqlock, flags); | ||
822 | q->ops->buf_queue(q, q->read_buf); | 816 | q->ops->buf_queue(q, q->read_buf); |
823 | if (q->irqlock) | 817 | spin_unlock_irqrestore(q->irqlock, flags); |
824 | spin_unlock_irqrestore(q->irqlock, flags); | 818 | |
825 | q->read_off = 0; | 819 | q->read_off = 0; |
826 | } | 820 | } |
827 | 821 | ||
@@ -887,12 +881,10 @@ static int __videobuf_read_start(struct videobuf_queue *q) | |||
887 | return err; | 881 | return err; |
888 | list_add_tail(&q->bufs[i]->stream, &q->stream); | 882 | list_add_tail(&q->bufs[i]->stream, &q->stream); |
889 | } | 883 | } |
890 | if (q->irqlock) | 884 | spin_lock_irqsave(q->irqlock, flags); |
891 | spin_lock_irqsave(q->irqlock, flags); | ||
892 | for (i = 0; i < count; i++) | 885 | for (i = 0; i < count; i++) |
893 | q->ops->buf_queue(q, q->bufs[i]); | 886 | q->ops->buf_queue(q, q->bufs[i]); |
894 | if (q->irqlock) | 887 | spin_unlock_irqrestore(q->irqlock, flags); |
895 | spin_unlock_irqrestore(q->irqlock, flags); | ||
896 | q->reading = 1; | 888 | q->reading = 1; |
897 | return 0; | 889 | return 0; |
898 | } | 890 | } |
@@ -1004,11 +996,9 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q, | |||
1004 | if (q->read_off == q->read_buf->size) { | 996 | if (q->read_off == q->read_buf->size) { |
1005 | list_add_tail(&q->read_buf->stream, | 997 | list_add_tail(&q->read_buf->stream, |
1006 | &q->stream); | 998 | &q->stream); |
1007 | if (q->irqlock) | 999 | spin_lock_irqsave(q->irqlock, flags); |
1008 | spin_lock_irqsave(q->irqlock, flags); | ||
1009 | q->ops->buf_queue(q, q->read_buf); | 1000 | q->ops->buf_queue(q, q->read_buf); |
1010 | if (q->irqlock) | 1001 | spin_unlock_irqrestore(q->irqlock, flags); |
1011 | spin_unlock_irqrestore(q->irqlock, flags); | ||
1012 | q->read_buf = NULL; | 1002 | q->read_buf = NULL; |
1013 | } | 1003 | } |
1014 | if (retval < 0) | 1004 | if (retval < 0) |