diff options
| author | Mahesh Bandewar <maheshb@google.com> | 2014-12-03 16:46:24 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2014-12-09 13:36:57 -0500 |
| commit | 395eea6ccf2b253f81b4718ffbcae67d36fe2e69 (patch) | |
| tree | 57993c1e5262b56f693a3fcc11c111ec390f28c2 /net/core | |
| parent | 5f4d8d97f5d979c6a62dcc45619b06d34311937c (diff) | |
rtnetlink: delay RTM_DELLINK notification until after ndo_uninit()
The commit 56bfa7ee7c ("unregister_netdevice : move RTM_DELLINK to
until after ndo_uninit") tried to do this ealier but while doing so
it created a problem. Unfortunately the delayed rtmsg_ifinfo() also
delayed call to fill_info(). So this translated into asking driver
to remove private state and then query it's private state. This
could have catastropic consequences.
This change breaks the rtmsg_ifinfo() into two parts - one takes the
precise snapshot of the device by called fill_info() before calling
the ndo_uninit() and the second part sends the notification using
collected snapshot.
It was brought to notice when last link is deleted from an ipvlan device
when it has free-ed the port and the subsequent .fill_info() call is
trying to get the info from the port.
kernel: [ 255.139429] ------------[ cut here ]------------
kernel: [ 255.139439] WARNING: CPU: 12 PID: 11173 at net/core/rtnetlink.c:2238 rtmsg_ifinfo+0x100/0x110()
kernel: [ 255.139493] Modules linked in: ipvlan bonding w1_therm ds2482 wire cdc_acm ehci_pci ehci_hcd i2c_dev i2c_i801 i2c_core msr cpuid bnx2x ptp pps_core mdio libcrc32c
kernel: [ 255.139513] CPU: 12 PID: 11173 Comm: ip Not tainted 3.18.0-smp-DEV #167
kernel: [ 255.139514] Hardware name: Intel RML,PCH/Ibis_QC_18, BIOS 1.0.10 05/15/2012
kernel: [ 255.139515] 0000000000000009 ffff880851b6b828 ffffffff815d87f4 00000000000000e0
kernel: [ 255.139516] 0000000000000000 ffff880851b6b868 ffffffff8109c29c 0000000000000000
kernel: [ 255.139518] 00000000ffffffa6 00000000000000d0 ffffffff81aaf580 0000000000000011
kernel: [ 255.139520] Call Trace:
kernel: [ 255.139527] [<ffffffff815d87f4>] dump_stack+0x46/0x58
kernel: [ 255.139531] [<ffffffff8109c29c>] warn_slowpath_common+0x8c/0xc0
kernel: [ 255.139540] [<ffffffff8109c2ea>] warn_slowpath_null+0x1a/0x20
kernel: [ 255.139544] [<ffffffff8150d570>] rtmsg_ifinfo+0x100/0x110
kernel: [ 255.139547] [<ffffffff814f78b5>] rollback_registered_many+0x1d5/0x2d0
kernel: [ 255.139549] [<ffffffff814f79cf>] unregister_netdevice_many+0x1f/0xb0
kernel: [ 255.139551] [<ffffffff8150acab>] rtnl_dellink+0xbb/0x110
kernel: [ 255.139553] [<ffffffff8150da90>] rtnetlink_rcv_msg+0xa0/0x240
kernel: [ 255.139557] [<ffffffff81329283>] ? rhashtable_lookup_compare+0x43/0x80
kernel: [ 255.139558] [<ffffffff8150d9f0>] ? __rtnl_unlock+0x20/0x20
kernel: [ 255.139562] [<ffffffff8152cb11>] netlink_rcv_skb+0xb1/0xc0
kernel: [ 255.139563] [<ffffffff8150a495>] rtnetlink_rcv+0x25/0x40
kernel: [ 255.139565] [<ffffffff8152c398>] netlink_unicast+0x178/0x230
kernel: [ 255.139567] [<ffffffff8152c75f>] netlink_sendmsg+0x30f/0x420
kernel: [ 255.139571] [<ffffffff814e0b0c>] sock_sendmsg+0x9c/0xd0
kernel: [ 255.139575] [<ffffffff811d1d7f>] ? rw_copy_check_uvector+0x6f/0x130
kernel: [ 255.139577] [<ffffffff814e11c9>] ? copy_msghdr_from_user+0x139/0x1b0
kernel: [ 255.139578] [<ffffffff814e1774>] ___sys_sendmsg+0x304/0x310
kernel: [ 255.139581] [<ffffffff81198723>] ? handle_mm_fault+0xca3/0xde0
kernel: [ 255.139585] [<ffffffff811ebc4c>] ? destroy_inode+0x3c/0x70
kernel: [ 255.139589] [<ffffffff8108e6ec>] ? __do_page_fault+0x20c/0x500
kernel: [ 255.139597] [<ffffffff811e8336>] ? dput+0xb6/0x190
kernel: [ 255.139606] [<ffffffff811f05f6>] ? mntput+0x26/0x40
kernel: [ 255.139611] [<ffffffff811d2b94>] ? __fput+0x174/0x1e0
kernel: [ 255.139613] [<ffffffff814e2129>] __sys_sendmsg+0x49/0x90
kernel: [ 255.139615] [<ffffffff814e2182>] SyS_sendmsg+0x12/0x20
kernel: [ 255.139617] [<ffffffff815df092>] system_call_fastpath+0x12/0x17
kernel: [ 255.139619] ---[ end trace 5e6703e87d984f6b ]---
Signed-off-by: Mahesh Bandewar <maheshb@google.com>
Reported-by: Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp>
Cc: Eric Dumazet <edumazet@google.com>
Cc: Roopa Prabhu <roopa@cumulusnetworks.com>
Cc: David S. Miller <davem@davemloft.net>
Acked-by: Eric Dumazet <edumazet@google.com>
Acked-by: Thomas Graf <tgraf@suug.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core')
| -rw-r--r-- | net/core/dev.c | 12 | ||||
| -rw-r--r-- | net/core/rtnetlink.c | 25 |
2 files changed, 30 insertions, 7 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index 0814a560e5f3..dd3bf582e6f0 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
| @@ -5925,6 +5925,8 @@ static void rollback_registered_many(struct list_head *head) | |||
| 5925 | synchronize_net(); | 5925 | synchronize_net(); |
| 5926 | 5926 | ||
| 5927 | list_for_each_entry(dev, head, unreg_list) { | 5927 | list_for_each_entry(dev, head, unreg_list) { |
| 5928 | struct sk_buff *skb = NULL; | ||
| 5929 | |||
| 5928 | /* Shutdown queueing discipline. */ | 5930 | /* Shutdown queueing discipline. */ |
| 5929 | dev_shutdown(dev); | 5931 | dev_shutdown(dev); |
| 5930 | 5932 | ||
| @@ -5934,6 +5936,11 @@ static void rollback_registered_many(struct list_head *head) | |||
| 5934 | */ | 5936 | */ |
| 5935 | call_netdevice_notifiers(NETDEV_UNREGISTER, dev); | 5937 | call_netdevice_notifiers(NETDEV_UNREGISTER, dev); |
| 5936 | 5938 | ||
| 5939 | if (!dev->rtnl_link_ops || | ||
| 5940 | dev->rtnl_link_state == RTNL_LINK_INITIALIZED) | ||
| 5941 | skb = rtmsg_ifinfo_build_skb(RTM_DELLINK, dev, ~0U, | ||
| 5942 | GFP_KERNEL); | ||
| 5943 | |||
| 5937 | /* | 5944 | /* |
| 5938 | * Flush the unicast and multicast chains | 5945 | * Flush the unicast and multicast chains |
| 5939 | */ | 5946 | */ |
| @@ -5943,9 +5950,8 @@ static void rollback_registered_many(struct list_head *head) | |||
| 5943 | if (dev->netdev_ops->ndo_uninit) | 5950 | if (dev->netdev_ops->ndo_uninit) |
| 5944 | dev->netdev_ops->ndo_uninit(dev); | 5951 | dev->netdev_ops->ndo_uninit(dev); |
| 5945 | 5952 | ||
| 5946 | if (!dev->rtnl_link_ops || | 5953 | if (skb) |
| 5947 | dev->rtnl_link_state == RTNL_LINK_INITIALIZED) | 5954 | rtmsg_ifinfo_send(skb, dev, GFP_KERNEL); |
| 5948 | rtmsg_ifinfo(RTM_DELLINK, dev, ~0U, GFP_KERNEL); | ||
| 5949 | 5955 | ||
| 5950 | /* Notifier chain MUST detach us all upper devices. */ | 5956 | /* Notifier chain MUST detach us all upper devices. */ |
| 5951 | WARN_ON(netdev_has_any_upper_dev(dev)); | 5957 | WARN_ON(netdev_has_any_upper_dev(dev)); |
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 61cb7e7cc3c7..a9be2c161702 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
| @@ -2245,8 +2245,8 @@ static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb) | |||
| 2245 | return skb->len; | 2245 | return skb->len; |
| 2246 | } | 2246 | } |
| 2247 | 2247 | ||
| 2248 | void rtmsg_ifinfo(int type, struct net_device *dev, unsigned int change, | 2248 | struct sk_buff *rtmsg_ifinfo_build_skb(int type, struct net_device *dev, |
| 2249 | gfp_t flags) | 2249 | unsigned int change, gfp_t flags) |
| 2250 | { | 2250 | { |
| 2251 | struct net *net = dev_net(dev); | 2251 | struct net *net = dev_net(dev); |
| 2252 | struct sk_buff *skb; | 2252 | struct sk_buff *skb; |
| @@ -2264,11 +2264,28 @@ void rtmsg_ifinfo(int type, struct net_device *dev, unsigned int change, | |||
| 2264 | kfree_skb(skb); | 2264 | kfree_skb(skb); |
| 2265 | goto errout; | 2265 | goto errout; |
| 2266 | } | 2266 | } |
| 2267 | rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, flags); | 2267 | return skb; |
| 2268 | return; | ||
| 2269 | errout: | 2268 | errout: |
| 2270 | if (err < 0) | 2269 | if (err < 0) |
| 2271 | rtnl_set_sk_err(net, RTNLGRP_LINK, err); | 2270 | rtnl_set_sk_err(net, RTNLGRP_LINK, err); |
| 2271 | return NULL; | ||
| 2272 | } | ||
| 2273 | |||
| 2274 | void rtmsg_ifinfo_send(struct sk_buff *skb, struct net_device *dev, gfp_t flags) | ||
| 2275 | { | ||
| 2276 | struct net *net = dev_net(dev); | ||
| 2277 | |||
| 2278 | rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, flags); | ||
| 2279 | } | ||
| 2280 | |||
| 2281 | void rtmsg_ifinfo(int type, struct net_device *dev, unsigned int change, | ||
| 2282 | gfp_t flags) | ||
| 2283 | { | ||
| 2284 | struct sk_buff *skb; | ||
| 2285 | |||
| 2286 | skb = rtmsg_ifinfo_build_skb(type, dev, change, flags); | ||
| 2287 | if (skb) | ||
| 2288 | rtmsg_ifinfo_send(skb, dev, flags); | ||
| 2272 | } | 2289 | } |
| 2273 | EXPORT_SYMBOL(rtmsg_ifinfo); | 2290 | EXPORT_SYMBOL(rtmsg_ifinfo); |
| 2274 | 2291 | ||
