aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/gspca
diff options
context:
space:
mode:
authorJean-François Moine <moinejf@free.fr>2010-07-06 04:16:40 -0300
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-08-02 16:42:47 -0300
commit02bbcb9d863df10b5a4b91ba5b4c76eaf1340883 (patch)
tree1e19c0d8d0a50e1a34d4b6fa5f5027ee713b9612 /drivers/media/video/gspca
parent9059cd44403608f6554b37c3b3d5598ded7a3a92 (diff)
downloadkernel_samsung_aries-02bbcb9d863df10b5a4b91ba5b4c76eaf1340883.zip
kernel_samsung_aries-02bbcb9d863df10b5a4b91ba5b4c76eaf1340883.tar.gz
kernel_samsung_aries-02bbcb9d863df10b5a4b91ba5b4c76eaf1340883.tar.bz2
V4L/DVB: gspca - main: Possible race condition in queue management
The problem may occur with SMP: - a frame is completed at interrupt level (in gspca_frame_add with packet_type == LAST_PACKET, - just after clearing the bit V4L2_BUF_FLAG_QUEUED and before setting the bit V4L2_BUF_FLAG_DONE, on the other processor, the application tries to requeue the same frame buffer, - then, the qbuf function succeeds because ALL_FLAGS are not set. The fix sets and resets the two flags in one instruction. Reported-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Jean-François Moine <moinejf@free.fr> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/gspca')
-rw-r--r--drivers/media/video/gspca/gspca.c5
1 files changed, 3 insertions, 2 deletions
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c
index 8e822ed..2dc7270 100644
--- a/drivers/media/video/gspca/gspca.c
+++ b/drivers/media/video/gspca/gspca.c
@@ -466,8 +466,9 @@ void gspca_frame_add(struct gspca_dev *gspca_dev,
j = gspca_dev->fr_queue[i];
frame = &gspca_dev->frame[j];
frame->v4l2_buf.bytesused = gspca_dev->image_len;
- frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_QUEUED;
- frame->v4l2_buf.flags |= V4L2_BUF_FLAG_DONE;
+ frame->v4l2_buf.flags = (frame->v4l2_buf.flags
+ | V4L2_BUF_FLAG_DONE)
+ & ~V4L2_BUF_FLAG_QUEUED;
wake_up_interruptible(&gspca_dev->wq); /* event = new frame */
i = (i + 1) % gspca_dev->nframes;
gspca_dev->fr_i = i;