diff options
-rw-r--r-- | drivers/net/bonding/bond_main.c | 46 | ||||
-rw-r--r-- | drivers/net/bonding/bond_sysfs.c | 8 | ||||
-rw-r--r-- | drivers/net/bonding/bonding.h | 30 |
3 files changed, 80 insertions, 4 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 813cc2f8edd6..b46cb139477d 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c | |||
@@ -76,6 +76,7 @@ | |||
76 | #include <linux/if_vlan.h> | 76 | #include <linux/if_vlan.h> |
77 | #include <linux/if_bonding.h> | 77 | #include <linux/if_bonding.h> |
78 | #include <linux/jiffies.h> | 78 | #include <linux/jiffies.h> |
79 | #include <linux/preempt.h> | ||
79 | #include <net/route.h> | 80 | #include <net/route.h> |
80 | #include <net/net_namespace.h> | 81 | #include <net/net_namespace.h> |
81 | #include <net/netns/generic.h> | 82 | #include <net/netns/generic.h> |
@@ -169,6 +170,10 @@ MODULE_PARM_DESC(resend_igmp, "Number of IGMP membership reports to send on link | |||
169 | 170 | ||
170 | /*----------------------------- Global variables ----------------------------*/ | 171 | /*----------------------------- Global variables ----------------------------*/ |
171 | 172 | ||
173 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
174 | cpumask_var_t netpoll_block_tx; | ||
175 | #endif | ||
176 | |||
172 | static const char * const version = | 177 | static const char * const version = |
173 | DRV_DESCRIPTION ": v" DRV_VERSION " (" DRV_RELDATE ")\n"; | 178 | DRV_DESCRIPTION ": v" DRV_VERSION " (" DRV_RELDATE ")\n"; |
174 | 179 | ||
@@ -310,6 +315,7 @@ static int bond_del_vlan(struct bonding *bond, unsigned short vlan_id) | |||
310 | 315 | ||
311 | pr_debug("bond: %s, vlan id %d\n", bond->dev->name, vlan_id); | 316 | pr_debug("bond: %s, vlan id %d\n", bond->dev->name, vlan_id); |
312 | 317 | ||
318 | block_netpoll_tx(); | ||
313 | write_lock_bh(&bond->lock); | 319 | write_lock_bh(&bond->lock); |
314 | 320 | ||
315 | list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { | 321 | list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { |
@@ -344,6 +350,7 @@ static int bond_del_vlan(struct bonding *bond, unsigned short vlan_id) | |||
344 | 350 | ||
345 | out: | 351 | out: |
346 | write_unlock_bh(&bond->lock); | 352 | write_unlock_bh(&bond->lock); |
353 | unblock_netpoll_tx(); | ||
347 | return res; | 354 | return res; |
348 | } | 355 | } |
349 | 356 | ||
@@ -1804,10 +1811,6 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) | |||
1804 | bond_set_carrier(bond); | 1811 | bond_set_carrier(bond); |
1805 | 1812 | ||
1806 | #ifdef CONFIG_NET_POLL_CONTROLLER | 1813 | #ifdef CONFIG_NET_POLL_CONTROLLER |
1807 | /* | ||
1808 | * Netpoll and bonding is broken, make sure it is not initialized | ||
1809 | * until it is fixed. | ||
1810 | */ | ||
1811 | if (disable_netpoll) { | 1814 | if (disable_netpoll) { |
1812 | bond_dev->priv_flags |= IFF_DISABLE_NETPOLL; | 1815 | bond_dev->priv_flags |= IFF_DISABLE_NETPOLL; |
1813 | } else { | 1816 | } else { |
@@ -1892,6 +1895,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) | |||
1892 | return -EINVAL; | 1895 | return -EINVAL; |
1893 | } | 1896 | } |
1894 | 1897 | ||
1898 | block_netpoll_tx(); | ||
1895 | netdev_bonding_change(bond_dev, NETDEV_BONDING_DESLAVE); | 1899 | netdev_bonding_change(bond_dev, NETDEV_BONDING_DESLAVE); |
1896 | write_lock_bh(&bond->lock); | 1900 | write_lock_bh(&bond->lock); |
1897 | 1901 | ||
@@ -1901,6 +1905,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) | |||
1901 | pr_info("%s: %s not enslaved\n", | 1905 | pr_info("%s: %s not enslaved\n", |
1902 | bond_dev->name, slave_dev->name); | 1906 | bond_dev->name, slave_dev->name); |
1903 | write_unlock_bh(&bond->lock); | 1907 | write_unlock_bh(&bond->lock); |
1908 | unblock_netpoll_tx(); | ||
1904 | return -EINVAL; | 1909 | return -EINVAL; |
1905 | } | 1910 | } |
1906 | 1911 | ||
@@ -1994,6 +1999,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) | |||
1994 | } | 1999 | } |
1995 | 2000 | ||
1996 | write_unlock_bh(&bond->lock); | 2001 | write_unlock_bh(&bond->lock); |
2002 | unblock_netpoll_tx(); | ||
1997 | 2003 | ||
1998 | /* must do this from outside any spinlocks */ | 2004 | /* must do this from outside any spinlocks */ |
1999 | bond_destroy_slave_symlinks(bond_dev, slave_dev); | 2005 | bond_destroy_slave_symlinks(bond_dev, slave_dev); |
@@ -2085,6 +2091,7 @@ static int bond_release_all(struct net_device *bond_dev) | |||
2085 | struct net_device *slave_dev; | 2091 | struct net_device *slave_dev; |
2086 | struct sockaddr addr; | 2092 | struct sockaddr addr; |
2087 | 2093 | ||
2094 | block_netpoll_tx(); | ||
2088 | write_lock_bh(&bond->lock); | 2095 | write_lock_bh(&bond->lock); |
2089 | 2096 | ||
2090 | netif_carrier_off(bond_dev); | 2097 | netif_carrier_off(bond_dev); |
@@ -2183,6 +2190,7 @@ static int bond_release_all(struct net_device *bond_dev) | |||
2183 | 2190 | ||
2184 | out: | 2191 | out: |
2185 | write_unlock_bh(&bond->lock); | 2192 | write_unlock_bh(&bond->lock); |
2193 | unblock_netpoll_tx(); | ||
2186 | 2194 | ||
2187 | return 0; | 2195 | return 0; |
2188 | } | 2196 | } |
@@ -2232,9 +2240,11 @@ static int bond_ioctl_change_active(struct net_device *bond_dev, struct net_devi | |||
2232 | (old_active) && | 2240 | (old_active) && |
2233 | (new_active->link == BOND_LINK_UP) && | 2241 | (new_active->link == BOND_LINK_UP) && |
2234 | IS_UP(new_active->dev)) { | 2242 | IS_UP(new_active->dev)) { |
2243 | block_netpoll_tx(); | ||
2235 | write_lock_bh(&bond->curr_slave_lock); | 2244 | write_lock_bh(&bond->curr_slave_lock); |
2236 | bond_change_active_slave(bond, new_active); | 2245 | bond_change_active_slave(bond, new_active); |
2237 | write_unlock_bh(&bond->curr_slave_lock); | 2246 | write_unlock_bh(&bond->curr_slave_lock); |
2247 | unblock_netpoll_tx(); | ||
2238 | } else | 2248 | } else |
2239 | res = -EINVAL; | 2249 | res = -EINVAL; |
2240 | 2250 | ||
@@ -2466,9 +2476,11 @@ static void bond_miimon_commit(struct bonding *bond) | |||
2466 | 2476 | ||
2467 | do_failover: | 2477 | do_failover: |
2468 | ASSERT_RTNL(); | 2478 | ASSERT_RTNL(); |
2479 | block_netpoll_tx(); | ||
2469 | write_lock_bh(&bond->curr_slave_lock); | 2480 | write_lock_bh(&bond->curr_slave_lock); |
2470 | bond_select_active_slave(bond); | 2481 | bond_select_active_slave(bond); |
2471 | write_unlock_bh(&bond->curr_slave_lock); | 2482 | write_unlock_bh(&bond->curr_slave_lock); |
2483 | unblock_netpoll_tx(); | ||
2472 | } | 2484 | } |
2473 | 2485 | ||
2474 | bond_set_carrier(bond); | 2486 | bond_set_carrier(bond); |
@@ -2911,11 +2923,13 @@ void bond_loadbalance_arp_mon(struct work_struct *work) | |||
2911 | } | 2923 | } |
2912 | 2924 | ||
2913 | if (do_failover) { | 2925 | if (do_failover) { |
2926 | block_netpoll_tx(); | ||
2914 | write_lock_bh(&bond->curr_slave_lock); | 2927 | write_lock_bh(&bond->curr_slave_lock); |
2915 | 2928 | ||
2916 | bond_select_active_slave(bond); | 2929 | bond_select_active_slave(bond); |
2917 | 2930 | ||
2918 | write_unlock_bh(&bond->curr_slave_lock); | 2931 | write_unlock_bh(&bond->curr_slave_lock); |
2932 | unblock_netpoll_tx(); | ||
2919 | } | 2933 | } |
2920 | 2934 | ||
2921 | re_arm: | 2935 | re_arm: |
@@ -3074,9 +3088,11 @@ static void bond_ab_arp_commit(struct bonding *bond, int delta_in_ticks) | |||
3074 | 3088 | ||
3075 | do_failover: | 3089 | do_failover: |
3076 | ASSERT_RTNL(); | 3090 | ASSERT_RTNL(); |
3091 | block_netpoll_tx(); | ||
3077 | write_lock_bh(&bond->curr_slave_lock); | 3092 | write_lock_bh(&bond->curr_slave_lock); |
3078 | bond_select_active_slave(bond); | 3093 | bond_select_active_slave(bond); |
3079 | write_unlock_bh(&bond->curr_slave_lock); | 3094 | write_unlock_bh(&bond->curr_slave_lock); |
3095 | unblock_netpoll_tx(); | ||
3080 | } | 3096 | } |
3081 | 3097 | ||
3082 | bond_set_carrier(bond); | 3098 | bond_set_carrier(bond); |
@@ -4564,6 +4580,13 @@ static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
4564 | { | 4580 | { |
4565 | struct bonding *bond = netdev_priv(dev); | 4581 | struct bonding *bond = netdev_priv(dev); |
4566 | 4582 | ||
4583 | /* | ||
4584 | * If we risk deadlock from transmitting this in the | ||
4585 | * netpoll path, tell netpoll to queue the frame for later tx | ||
4586 | */ | ||
4587 | if (is_netpoll_tx_blocked(dev)) | ||
4588 | return NETDEV_TX_BUSY; | ||
4589 | |||
4567 | if (TX_QUEUE_OVERRIDE(bond->params.mode)) { | 4590 | if (TX_QUEUE_OVERRIDE(bond->params.mode)) { |
4568 | if (!bond_slave_override(bond, skb)) | 4591 | if (!bond_slave_override(bond, skb)) |
4569 | return NETDEV_TX_OK; | 4592 | return NETDEV_TX_OK; |
@@ -5286,6 +5309,13 @@ static int __init bonding_init(void) | |||
5286 | if (res) | 5309 | if (res) |
5287 | goto out; | 5310 | goto out; |
5288 | 5311 | ||
5312 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
5313 | if (!alloc_cpumask_var(&netpoll_block_tx, GFP_KERNEL)) { | ||
5314 | res = -ENOMEM; | ||
5315 | goto out; | ||
5316 | } | ||
5317 | #endif | ||
5318 | |||
5289 | res = register_pernet_subsys(&bond_net_ops); | 5319 | res = register_pernet_subsys(&bond_net_ops); |
5290 | if (res) | 5320 | if (res) |
5291 | goto out; | 5321 | goto out; |
@@ -5304,6 +5334,7 @@ static int __init bonding_init(void) | |||
5304 | if (res) | 5334 | if (res) |
5305 | goto err; | 5335 | goto err; |
5306 | 5336 | ||
5337 | |||
5307 | register_netdevice_notifier(&bond_netdev_notifier); | 5338 | register_netdevice_notifier(&bond_netdev_notifier); |
5308 | register_inetaddr_notifier(&bond_inetaddr_notifier); | 5339 | register_inetaddr_notifier(&bond_inetaddr_notifier); |
5309 | bond_register_ipv6_notifier(); | 5340 | bond_register_ipv6_notifier(); |
@@ -5313,6 +5344,9 @@ err: | |||
5313 | rtnl_link_unregister(&bond_link_ops); | 5344 | rtnl_link_unregister(&bond_link_ops); |
5314 | err_link: | 5345 | err_link: |
5315 | unregister_pernet_subsys(&bond_net_ops); | 5346 | unregister_pernet_subsys(&bond_net_ops); |
5347 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
5348 | free_cpumask_var(netpoll_block_tx); | ||
5349 | #endif | ||
5316 | goto out; | 5350 | goto out; |
5317 | 5351 | ||
5318 | } | 5352 | } |
@@ -5327,6 +5361,10 @@ static void __exit bonding_exit(void) | |||
5327 | 5361 | ||
5328 | rtnl_link_unregister(&bond_link_ops); | 5362 | rtnl_link_unregister(&bond_link_ops); |
5329 | unregister_pernet_subsys(&bond_net_ops); | 5363 | unregister_pernet_subsys(&bond_net_ops); |
5364 | |||
5365 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
5366 | free_cpumask_var(netpoll_block_tx); | ||
5367 | #endif | ||
5330 | } | 5368 | } |
5331 | 5369 | ||
5332 | module_init(bonding_init); | 5370 | module_init(bonding_init); |
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 01b4c3f5d9e7..8fd0174c5380 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c | |||
@@ -1066,6 +1066,7 @@ static ssize_t bonding_store_primary(struct device *d, | |||
1066 | 1066 | ||
1067 | if (!rtnl_trylock()) | 1067 | if (!rtnl_trylock()) |
1068 | return restart_syscall(); | 1068 | return restart_syscall(); |
1069 | block_netpoll_tx(); | ||
1069 | read_lock(&bond->lock); | 1070 | read_lock(&bond->lock); |
1070 | write_lock_bh(&bond->curr_slave_lock); | 1071 | write_lock_bh(&bond->curr_slave_lock); |
1071 | 1072 | ||
@@ -1101,6 +1102,7 @@ static ssize_t bonding_store_primary(struct device *d, | |||
1101 | out: | 1102 | out: |
1102 | write_unlock_bh(&bond->curr_slave_lock); | 1103 | write_unlock_bh(&bond->curr_slave_lock); |
1103 | read_unlock(&bond->lock); | 1104 | read_unlock(&bond->lock); |
1105 | unblock_netpoll_tx(); | ||
1104 | rtnl_unlock(); | 1106 | rtnl_unlock(); |
1105 | 1107 | ||
1106 | return count; | 1108 | return count; |
@@ -1146,11 +1148,13 @@ static ssize_t bonding_store_primary_reselect(struct device *d, | |||
1146 | bond->dev->name, pri_reselect_tbl[new_value].modename, | 1148 | bond->dev->name, pri_reselect_tbl[new_value].modename, |
1147 | new_value); | 1149 | new_value); |
1148 | 1150 | ||
1151 | block_netpoll_tx(); | ||
1149 | read_lock(&bond->lock); | 1152 | read_lock(&bond->lock); |
1150 | write_lock_bh(&bond->curr_slave_lock); | 1153 | write_lock_bh(&bond->curr_slave_lock); |
1151 | bond_select_active_slave(bond); | 1154 | bond_select_active_slave(bond); |
1152 | write_unlock_bh(&bond->curr_slave_lock); | 1155 | write_unlock_bh(&bond->curr_slave_lock); |
1153 | read_unlock(&bond->lock); | 1156 | read_unlock(&bond->lock); |
1157 | unblock_netpoll_tx(); | ||
1154 | out: | 1158 | out: |
1155 | rtnl_unlock(); | 1159 | rtnl_unlock(); |
1156 | return ret; | 1160 | return ret; |
@@ -1232,6 +1236,8 @@ static ssize_t bonding_store_active_slave(struct device *d, | |||
1232 | 1236 | ||
1233 | if (!rtnl_trylock()) | 1237 | if (!rtnl_trylock()) |
1234 | return restart_syscall(); | 1238 | return restart_syscall(); |
1239 | |||
1240 | block_netpoll_tx(); | ||
1235 | read_lock(&bond->lock); | 1241 | read_lock(&bond->lock); |
1236 | write_lock_bh(&bond->curr_slave_lock); | 1242 | write_lock_bh(&bond->curr_slave_lock); |
1237 | 1243 | ||
@@ -1288,6 +1294,8 @@ static ssize_t bonding_store_active_slave(struct device *d, | |||
1288 | out: | 1294 | out: |
1289 | write_unlock_bh(&bond->curr_slave_lock); | 1295 | write_unlock_bh(&bond->curr_slave_lock); |
1290 | read_unlock(&bond->lock); | 1296 | read_unlock(&bond->lock); |
1297 | unblock_netpoll_tx(); | ||
1298 | |||
1291 | rtnl_unlock(); | 1299 | rtnl_unlock(); |
1292 | 1300 | ||
1293 | return count; | 1301 | return count; |
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index c15f21347486..2c12a5f812f4 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/proc_fs.h> | 19 | #include <linux/proc_fs.h> |
20 | #include <linux/if_bonding.h> | 20 | #include <linux/if_bonding.h> |
21 | #include <linux/kobject.h> | 21 | #include <linux/kobject.h> |
22 | #include <linux/cpumask.h> | ||
22 | #include <linux/in6.h> | 23 | #include <linux/in6.h> |
23 | #include "bond_3ad.h" | 24 | #include "bond_3ad.h" |
24 | #include "bond_alb.h" | 25 | #include "bond_alb.h" |
@@ -117,6 +118,35 @@ | |||
117 | bond_for_each_slave_from(bond, pos, cnt, (bond)->first_slave) | 118 | bond_for_each_slave_from(bond, pos, cnt, (bond)->first_slave) |
118 | 119 | ||
119 | 120 | ||
121 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
122 | extern cpumask_var_t netpoll_block_tx; | ||
123 | |||
124 | static inline void block_netpoll_tx(void) | ||
125 | { | ||
126 | preempt_disable(); | ||
127 | BUG_ON(cpumask_test_and_set_cpu(smp_processor_id(), | ||
128 | netpoll_block_tx)); | ||
129 | } | ||
130 | |||
131 | static inline void unblock_netpoll_tx(void) | ||
132 | { | ||
133 | BUG_ON(!cpumask_test_and_clear_cpu(smp_processor_id(), | ||
134 | netpoll_block_tx)); | ||
135 | preempt_enable(); | ||
136 | } | ||
137 | |||
138 | static inline int is_netpoll_tx_blocked(struct net_device *dev) | ||
139 | { | ||
140 | if (unlikely(dev->priv_flags & IFF_IN_NETPOLL)) | ||
141 | return cpumask_test_cpu(smp_processor_id(), netpoll_block_tx); | ||
142 | return 0; | ||
143 | } | ||
144 | #else | ||
145 | #define block_netpoll_tx() | ||
146 | #define unblock_netpoll_tx() | ||
147 | #define is_netpoll_tx_blocked(dev) (0) | ||
148 | #endif | ||
149 | |||
120 | struct bond_params { | 150 | struct bond_params { |
121 | int mode; | 151 | int mode; |
122 | int xmit_policy; | 152 | int xmit_policy; |