099-0003-net-qmi_wwan-should-hold-RTNL-while-changing-netdev-.patch 3.4 KB

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