From: Oliver Neukum <oneukum@suse.de>
To: Julius Werner <jwerner@chromium.org>
Cc: Grant Grundler <grundler@google.com>,
netdev <netdev@vger.kernel.org>, Freddy Xin <freddy@asix.com.tw>,
"linux-usb@vger.kernel.org" <linux-usb@vger.kernel.org>,
Allan Chou <allan@asix.com.tw>
Subject: Re: usbnet: driver_info->stop required to stop USB interrupts?
Date: Tue, 11 Mar 2014 10:14:23 +0100 [thread overview]
Message-ID: <1394529263.16128.6.camel@linux-fkkt.site> (raw)
In-Reply-To: <CAODwPW_t9COeg0LWfkiqXC_yTbSNhUHX-8T95KRZHfOTSiZK1Q@mail.gmail.com>
On Mon, 2014-03-10 at 19:53 -0700, Julius Werner wrote:
> I think the best solution would be to just make dev->wait a directly
> embedded structure inside struct usbnet instead of a pointer to
> something stack-allocated. usbnet_bh() could just call wake_up()
> unconditionally (if empty it will be a noop), and then one other check
> for !dev->wait could be replaced with a call to waitqueue_active().
> Then the waitqueue-internal locks should be enough to protect all
> accesses.
What do you think?
Regards
Oliver
>From 5ea2cb8a2893953fc7067aeae093ab20239d5108 Mon Sep 17 00:00:00 2001
From: Oliver Neukum <oneukum@suse.de>
Date: Tue, 11 Mar 2014 09:59:48 +0100
Subject: [PATCH] usbnet: include wait queue head in device structure
This fixes a race which happens by freeing an object on the stack.
Quoting Julius:
> The issue is
> that it calls usbnet_terminate_urbs() before that, which temporarily
> installs a waitqueue in dev->wait in order to be able to wait on the
> tasklet to run and finish up some queues. The waiting itself looks
> okay, but the access to 'dev->wait' is totally unprotected and can
> race arbitrarily. I think in this case usbnet_bh() managed to succeed
> it's dev->wait check just before usbnet_terminate_urbs() sets it back
> to NULL. The latter then finishes and the waitqueue_t structure on its
> stack gets overwritten by other functions halfway through the
> wake_up() call in usbnet_bh().
The fix is to just not allocate the data structure on the stack.
As dev->wait is abused as a flag it also takes a runtime PM change
to fix this bug.
Signed-off-by: Oliver Neukum <oneukum@suse.de>
---
drivers/net/usb/usbnet.c | 27 ++++++++++++++-------------
include/linux/usb/usbnet.h | 2 +-
2 files changed, 15 insertions(+), 14 deletions(-)
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index dd10d58..b5bcb48 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -752,14 +752,12 @@ EXPORT_SYMBOL_GPL(usbnet_unlink_rx_urbs);
// precondition: never called in_interrupt
static void usbnet_terminate_urbs(struct usbnet *dev)
{
- DECLARE_WAIT_QUEUE_HEAD_ONSTACK(unlink_wakeup);
DECLARE_WAITQUEUE(wait, current);
int temp;
/* ensure there are no more active urbs */
- add_wait_queue(&unlink_wakeup, &wait);
+ add_wait_queue(&dev->wait, &wait);
set_current_state(TASK_UNINTERRUPTIBLE);
- dev->wait = &unlink_wakeup;
temp = unlink_urbs(dev, &dev->txq) +
unlink_urbs(dev, &dev->rxq);
@@ -773,15 +771,14 @@ static void usbnet_terminate_urbs(struct usbnet *dev)
"waited for %d urb completions\n", temp);
}
set_current_state(TASK_RUNNING);
- dev->wait = NULL;
- remove_wait_queue(&unlink_wakeup, &wait);
+ remove_wait_queue(&dev->wait, &wait);
}
int usbnet_stop (struct net_device *net)
{
struct usbnet *dev = netdev_priv(net);
struct driver_info *info = dev->driver_info;
- int retval;
+ int retval, pm;
clear_bit(EVENT_DEV_OPEN, &dev->flags);
netif_stop_queue (net);
@@ -791,6 +788,8 @@ int usbnet_stop (struct net_device *net)
net->stats.rx_packets, net->stats.tx_packets,
net->stats.rx_errors, net->stats.tx_errors);
+ /* to not race resume */
+ pm = usb_autopm_get_interface(dev->intf);
/* allow minidriver to stop correctly (wireless devices to turn off
* radio etc) */
if (info->stop) {
@@ -817,6 +816,9 @@ int usbnet_stop (struct net_device *net)
dev->flags = 0;
del_timer_sync (&dev->delay);
tasklet_kill (&dev->bh);
+ if (!pm)
+ usb_autopm_put_interface(dev->intf);
+
if (info->manage_power &&
!test_and_clear_bit(EVENT_NO_RUNTIME_PM, &dev->flags))
info->manage_power(dev, 0);
@@ -1438,10 +1440,8 @@ static void usbnet_bh (unsigned long param)
clear_bit(EVENT_RX_KILL, &dev->flags);
// waiting for all pending urbs to complete?
- if (dev->wait) {
- if ((dev->txq.qlen + dev->rxq.qlen + dev->done.qlen) == 0) {
- wake_up (dev->wait);
- }
+ if ((dev->txq.qlen + dev->rxq.qlen + dev->done.qlen) == 0) {
+ wake_up (&dev->wait);
// or are we maybe short a few urbs?
} else if (netif_running (dev->net) &&
@@ -1791,9 +1791,10 @@ int usbnet_resume (struct usb_interface *intf)
spin_unlock_irq(&dev->txq.lock);
if (test_bit(EVENT_DEV_OPEN, &dev->flags)) {
- /* handle remote wakeup ASAP */
- if (!dev->wait &&
- netif_device_present(dev->net) &&
+ /* handle remote wakeup ASAP
+ * we cannot race against stop
+ */
+ if (netif_device_present(dev->net) &&
!timer_pending(&dev->delay) &&
!test_bit(EVENT_RX_HALT, &dev->flags))
rx_alloc_submit(dev, GFP_NOIO);
diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h
index e303eef..0662e98 100644
--- a/include/linux/usb/usbnet.h
+++ b/include/linux/usb/usbnet.h
@@ -30,7 +30,7 @@ struct usbnet {
struct driver_info *driver_info;
const char *driver_name;
void *driver_priv;
- wait_queue_head_t *wait;
+ wait_queue_head_t wait;
struct mutex phy_mutex;
unsigned char suspend_count;
unsigned char pkt_cnt, pkt_err;
--
1.8.4.5
next prev parent reply other threads:[~2014-03-11 9:14 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-03-10 18:33 usbnet: driver_info->stop required to stop USB interrupts? Grant Grundler
2014-03-10 22:58 ` Grant Grundler
2014-03-11 2:53 ` Julius Werner
2014-03-11 9:10 ` Oliver Neukum
2014-03-11 9:14 ` Oliver Neukum [this message]
[not found] ` <1394529263.16128.6.camel-B2T3B9s34ElbnMAlSieJcQ@public.gmane.org>
2014-03-11 17:27 ` Julius Werner
2014-03-17 21:53 ` Julius Werner
2014-03-17 21:55 ` Oliver Neukum
2014-03-17 22:02 ` Grant Grundler
2014-03-18 20:51 ` Grant Grundler
[not found] ` <CANEJEGuaVPNZKFiXY9CywFuqghgiQqV_sii7TE3STCNvXLQ3pQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-03-18 20:52 ` Grant Grundler
2014-03-19 1:09 ` Julius Werner
[not found] ` <CAODwPW-E-3HcXCGEmp9JpW6hU-Xt-FHwBtqeSSTDGaRPqO49Sw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-03-19 1:40 ` Grant Grundler
[not found] ` <CANEJEGscbVF3gRLNtTAcRSpHGVm1iDDKEeBscXcwj2-YdkiDXA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-03-20 0:58 ` Grant Grundler
2014-03-20 7:15 ` Oliver Neukum
2014-03-20 16:35 ` Grant Grundler
2014-03-20 21:19 ` Grant Grundler
[not found] ` <CANEJEGues6qVUEpWR5ggejg7dmS1PqzOHvZeWdxGJSnJh6c8Tw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-03-20 23:53 ` Julius Werner
[not found] ` <CAODwPW8vJf_AWDiea5jcunMu8HjqsDnRMfy25BkGDPHuVuRRHA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-03-21 8:32 ` Oliver Neukum
2014-03-21 8:33 ` Oliver Neukum
2014-03-21 16:18 ` Grant Grundler
2014-03-24 19:27 ` Grant Grundler
2014-03-11 17:31 ` Grant Grundler
2014-03-11 17:37 ` Grant Grundler
[not found] ` <CANEJEGv77PnbLZsyOdTevXjij-_wLSq4uGCnSjnAwN9OK8m3Yg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-03-11 17:52 ` Grant Grundler
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1394529263.16128.6.camel@linux-fkkt.site \
--to=oneukum@suse.de \
--cc=allan@asix.com.tw \
--cc=freddy@asix.com.tw \
--cc=grundler@google.com \
--cc=jwerner@chromium.org \
--cc=linux-usb@vger.kernel.org \
--cc=netdev@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).