Commit 5063452e authored by Kosuke Tatsukawa's avatar Kosuke Tatsukawa Committed by Mauro Carvalho Chehab

[media] media: fix waitqueue_active without memory barrier in cpia2 driver

cpia2_usb_disconnect() seems to be missing a memory barrier which might
cause the waker to not notice the waiter and miss sending a wake_up as
in the following figure.

	cpia2_usb_disconnect			sync
------------------------------------------------------------------------
					mutex_unlock(&cam->v4l2_lock);
if (waitqueue_active(&cam->wq_stream))
/* The CPU might reorder the test for
   the waitqueue up here, before
   prior writes complete */
					/* wait_event_interruptible */
					 /* __wait_event_interruptible */
					  /* ___wait_event */
					  long __int = prepare_to_wait_event(
					    &wq, &__wait, state);
					  if (!cam->streaming ||
					    frame->status == FRAME_READY)
cam->curbuff->status = FRAME_READY;
cam->curbuff->length = 0;
					  schedule()
------------------------------------------------------------------------

The attached patch removes the call to waitqueue_active() leaving just
wake_up() behind.  This fixes the problem because the call to
spin_lock_irqsave() in wake_up() will be an ACQUIRE operation.

I found this issue when I was looking through the linux source code
for places calling waitqueue_active() before wake_up*(), but without
preceding memory barriers, after sending a patch to fix a similar
issue in drivers/tty/n_tty.c  (Details about the original issue can be
found here: https://lkml.org/lkml/2015/9/28/849).
Signed-off-by: default avatarKosuke Tatsukawa <tatsu@ab.jp.nec.com>
Signed-off-by: default avatarHans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@osg.samsung.com>
parent dcc7fdbe
...@@ -890,8 +890,7 @@ static void cpia2_usb_disconnect(struct usb_interface *intf) ...@@ -890,8 +890,7 @@ static void cpia2_usb_disconnect(struct usb_interface *intf)
DBG("Wakeup waiting processes\n"); DBG("Wakeup waiting processes\n");
cam->curbuff->status = FRAME_READY; cam->curbuff->status = FRAME_READY;
cam->curbuff->length = 0; cam->curbuff->length = 0;
if (waitqueue_active(&cam->wq_stream)) wake_up_interruptible(&cam->wq_stream);
wake_up_interruptible(&cam->wq_stream);
} }
DBG("Releasing interface\n"); DBG("Releasing interface\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment