48f7141efb61f5f43a1616a6d950b0137a2ba46f
[librecmc/librecmc.git] /
1 From 6c730080e663b1d629f8aa89348291fbcdc46cd9 Mon Sep 17 00:00:00 2001
2 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= <bjorn@mork.no>
3 Date: Sun, 6 Dec 2015 21:25:50 +0100
4 Subject: [PATCH] net: qmi_wwan: should hold RTNL while changing netdev type
5 MIME-Version: 1.0
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
8
9 The notifier calls were thrown in as a last-minute fix for an
10 imagined "this device could be part of a bridge" problem. That
11 revealed a certain lack of locking.  Not to mention testing...
12
13 Avoid this splat:
14
15 RTNL: assertion failed at net/core/dev.c (1639)
16 CPU: 0 PID: 4293 Comm: bash Not tainted 4.4.0-rc3+ #358
17 Hardware name: LENOVO 2776LEG/2776LEG, BIOS 6EET55WW (3.15 ) 12/19/2011
18  0000000000000000 ffff8800ad253d60 ffffffff8122f7cf ffff8800ad253d98
19  ffff8800ad253d88 ffffffff813833ab 0000000000000002 ffff880230f48560
20  ffff880230a12900 ffff8800ad253da0 ffffffff813833da 0000000000000002
21 Call Trace:
22  [<ffffffff8122f7cf>] dump_stack+0x4b/0x63
23  [<ffffffff813833ab>] call_netdevice_notifiers_info+0x3d/0x59
24  [<ffffffff813833da>] call_netdevice_notifiers+0x13/0x15
25  [<ffffffffa09be227>] raw_ip_store+0x81/0x193 [qmi_wwan]
26  [<ffffffff8131e149>] dev_attr_store+0x20/0x22
27  [<ffffffff811d858b>] sysfs_kf_write+0x49/0x50
28  [<ffffffff811d8027>] kernfs_fop_write+0x10a/0x151
29  [<ffffffff8117249a>] __vfs_write+0x26/0xa5
30  [<ffffffff81085ed4>] ? percpu_down_read+0x53/0x7f
31  [<ffffffff81174c9e>] ? __sb_start_write+0x5f/0xb0
32  [<ffffffff81174c9e>] ? __sb_start_write+0x5f/0xb0
33  [<ffffffff81172c37>] vfs_write+0xa3/0xe7
34  [<ffffffff811734ad>] SyS_write+0x50/0x7e
35  [<ffffffff8145c517>] entry_SYSCALL_64_fastpath+0x12/0x6f
36
37 Fixes: 32f7adf633b9 ("net: qmi_wwan: support "raw IP" mode")
38 Signed-off-by: Bjørn Mork <bjorn@mork.no>
39 Signed-off-by: David S. Miller <davem@davemloft.net>
40 ---
41  drivers/net/usb/qmi_wwan.c | 22 +++++++++++++++-------
42  1 file changed, 15 insertions(+), 7 deletions(-)
43
44 diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
45 index 98add3bf8821..babc84a3946c 100644
46 --- a/drivers/net/usb/qmi_wwan.c
47 +++ b/drivers/net/usb/qmi_wwan.c
48 @@ -16,6 +16,7 @@
49  #include <linux/etherdevice.h>
50  #include <linux/if_arp.h>
51  #include <linux/mii.h>
52 +#include <linux/rtnetlink.h>
53  #include <linux/usb.h>
54  #include <linux/usb/cdc.h>
55  #include <linux/usb/usbnet.h>
56 @@ -92,7 +93,7 @@ static ssize_t raw_ip_store(struct device *d,  struct device_attribute *attr, co
57         struct usbnet *dev = netdev_priv(to_net_dev(d));
58         struct qmi_wwan_state *info = (void *)&dev->data;
59         bool enable;
60 -       int err;
61 +       int ret;
62  
63         if (strtobool(buf, &enable))
64                 return -EINVAL;
65 @@ -101,18 +102,22 @@ static ssize_t raw_ip_store(struct device *d,  struct device_attribute *attr, co
66         if (enable == (info->flags & QMI_WWAN_FLAG_RAWIP))
67                 return len;
68  
69 +       if (!rtnl_trylock())
70 +               return restart_syscall();
71 +
72         /* we don't want to modify a running netdev */
73         if (netif_running(dev->net)) {
74                 netdev_err(dev->net, "Cannot change a running device\n");
75 -               return -EBUSY;
76 +               ret = -EBUSY;
77 +               goto err;
78         }
79  
80         /* let other drivers deny the change */
81 -       err = call_netdevice_notifiers(NETDEV_PRE_TYPE_CHANGE, dev->net);
82 -       err = notifier_to_errno(err);
83 -       if (err) {
84 +       ret = call_netdevice_notifiers(NETDEV_PRE_TYPE_CHANGE, dev->net);
85 +       ret = notifier_to_errno(ret);
86 +       if (ret) {
87                 netdev_err(dev->net, "Type change was refused\n");
88 -               return err;
89 +               goto err;
90         }
91  
92         if (enable)
93 @@ -121,7 +126,10 @@ static ssize_t raw_ip_store(struct device *d,  struct device_attribute *attr, co
94                 info->flags &= ~QMI_WWAN_FLAG_RAWIP;
95         qmi_wwan_netdev_setup(dev->net);
96         call_netdevice_notifiers(NETDEV_POST_TYPE_CHANGE, dev->net);
97 -       return len;
98 +       ret = len;
99 +err:
100 +       rtnl_unlock();
101 +       return ret;
102  }
103  
104  static DEVICE_ATTR_RW(raw_ip);
105 -- 
106 2.7.4
107