lkml.org 
[lkml]   [2015]   [Sep]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    SubjectRe: [PATCH 2/2] usbnet: Fix a race between usbnet_stop() and the BH
    From
    Date
    On Fri, 2015-08-28 at 11:09 +0300, Eugene Shatokhin wrote:
    > > Exactly what problem will that result in? The tasklet_kill() will
    > wait
    > > for the processing of the single element done queue, and everything
    > will
    > > be fine. Or?
    >
    > Given enough time, what prevents defer_bh() from calling
    > tasklet_schedule(&dev->bh) *after* usbnet_stop() calls tasklet_kill()?
    >
    > Consider the following situation (assuming '&&' are changed to '||'
    > in
    > that while loop in usbnet_terminate_urbs() as they should be):
    >
    > CPU0 CPU1
    > usbnet_stop() defer_bh() with list == dev->rxq
    > usbnet_terminate_urbs()
    > __skb_unlink() removes the last
    > skb from dev->rxq.
    > dev->rxq, dev->txq and dev->done
    > are now empty.
    > while (!skb_queue_empty()...)
    > The loop ends because all 3
    > queues are now empty.
    >
    > usbnet_terminate_urbs() ends.
    >
    > usbnet_stop() continues:
    > usbnet_status_stop(dev);
    > ...
    > del_timer_sync (&dev->delay);
    > tasklet_kill (&dev->bh);
    > __skb_queue_tail(&dev->done, skb);
    > if (dev->done.qlen == 1)
    > tasklet_schedule(&dev->bh);
    >
    > The BH is scheduled at this point, which is not what was intended.
    > The
    > race window is small, but still.

    This looks possible. I cannot come up with a better fix, although
    it isn't nice. Thanks for finding this.

    Regards
    Oliver




    \
     
     \ /
      Last update: 2015-09-01 10:21    [W:3.038 / U:0.228 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site