Skip to content

Commit 6c73008

Browse files
bmorkdavem330
authored andcommitted
net: qmi_wwan: should hold RTNL while changing netdev type
The notifier calls were thrown in as a last-minute fix for an imagined "this device could be part of a bridge" problem. That revealed a certain lack of locking. Not to mention testing... Avoid this splat: RTNL: assertion failed at net/core/dev.c (1639) CPU: 0 PID: 4293 Comm: bash Not tainted 4.4.0-rc3+ #358 Hardware name: LENOVO 2776LEG/2776LEG, BIOS 6EET55WW (3.15 ) 12/19/2011 0000000000000000 ffff8800ad253d60 ffffffff8122f7cf ffff8800ad253d98 ffff8800ad253d88 ffffffff813833ab 0000000000000002 ffff880230f48560 ffff880230a12900 ffff8800ad253da0 ffffffff813833da 0000000000000002 Call Trace: [<ffffffff8122f7cf>] dump_stack+0x4b/0x63 [<ffffffff813833ab>] call_netdevice_notifiers_info+0x3d/0x59 [<ffffffff813833da>] call_netdevice_notifiers+0x13/0x15 [<ffffffffa09be227>] raw_ip_store+0x81/0x193 [qmi_wwan] [<ffffffff8131e149>] dev_attr_store+0x20/0x22 [<ffffffff811d858b>] sysfs_kf_write+0x49/0x50 [<ffffffff811d8027>] kernfs_fop_write+0x10a/0x151 [<ffffffff8117249a>] __vfs_write+0x26/0xa5 [<ffffffff81085ed4>] ? percpu_down_read+0x53/0x7f [<ffffffff81174c9e>] ? __sb_start_write+0x5f/0xb0 [<ffffffff81174c9e>] ? __sb_start_write+0x5f/0xb0 [<ffffffff81172c37>] vfs_write+0xa3/0xe7 [<ffffffff811734ad>] SyS_write+0x50/0x7e [<ffffffff8145c517>] entry_SYSCALL_64_fastpath+0x12/0x6f Fixes: 32f7adf ("net: qmi_wwan: support "raw IP" mode") Signed-off-by: Bjørn Mork <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 6633d38 commit 6c73008

File tree

1 file changed

+15
-7
lines changed

1 file changed

+15
-7
lines changed

drivers/net/usb/qmi_wwan.c

+15-7
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <linux/etherdevice.h>
1717
#include <linux/if_arp.h>
1818
#include <linux/mii.h>
19+
#include <linux/rtnetlink.h>
1920
#include <linux/usb.h>
2021
#include <linux/usb/cdc.h>
2122
#include <linux/usb/usbnet.h>
@@ -92,7 +93,7 @@ static ssize_t raw_ip_store(struct device *d, struct device_attribute *attr, co
9293
struct usbnet *dev = netdev_priv(to_net_dev(d));
9394
struct qmi_wwan_state *info = (void *)&dev->data;
9495
bool enable;
95-
int err;
96+
int ret;
9697

9798
if (strtobool(buf, &enable))
9899
return -EINVAL;
@@ -101,18 +102,22 @@ static ssize_t raw_ip_store(struct device *d, struct device_attribute *attr, co
101102
if (enable == (info->flags & QMI_WWAN_FLAG_RAWIP))
102103
return len;
103104

105+
if (!rtnl_trylock())
106+
return restart_syscall();
107+
104108
/* we don't want to modify a running netdev */
105109
if (netif_running(dev->net)) {
106110
netdev_err(dev->net, "Cannot change a running device\n");
107-
return -EBUSY;
111+
ret = -EBUSY;
112+
goto err;
108113
}
109114

110115
/* let other drivers deny the change */
111-
err = call_netdevice_notifiers(NETDEV_PRE_TYPE_CHANGE, dev->net);
112-
err = notifier_to_errno(err);
113-
if (err) {
116+
ret = call_netdevice_notifiers(NETDEV_PRE_TYPE_CHANGE, dev->net);
117+
ret = notifier_to_errno(ret);
118+
if (ret) {
114119
netdev_err(dev->net, "Type change was refused\n");
115-
return err;
120+
goto err;
116121
}
117122

118123
if (enable)
@@ -121,7 +126,10 @@ static ssize_t raw_ip_store(struct device *d, struct device_attribute *attr, co
121126
info->flags &= ~QMI_WWAN_FLAG_RAWIP;
122127
qmi_wwan_netdev_setup(dev->net);
123128
call_netdevice_notifiers(NETDEV_POST_TYPE_CHANGE, dev->net);
124-
return len;
129+
ret = len;
130+
err:
131+
rtnl_unlock();
132+
return ret;
125133
}
126134

127135
static DEVICE_ATTR_RW(raw_ip);

0 commit comments

Comments
 (0)