• Kosuke Tatsukawa's avatar
    [media] media: fix waitqueue_active without memory barrier in cpia2 driver · 5063452e
    Kosuke Tatsukawa authored
    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>
    5063452e
cpia2_usb.c 26 KB