diff options
author | nikolay@redhat.com <nikolay@redhat.com> | 2013-02-18 09:09:42 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-02-19 00:51:09 -0500 |
commit | 0896341a44bf04bf6149d9307fe4686006f3eee1 (patch) | |
tree | ea26f8337c05dadb0b93107a440ad4e95257a178 /drivers/net/bonding | |
parent | 7341a73c12b6133aaf3dade95942041043b11ba3 (diff) |
bonding: fix bond_release_all inconsistencies
This patch fixes the following inconsistencies in bond_release_all:
- IFF_BONDING flag is not stripped from slaves
- MTU is not restored
- no netdev notifiers are sent
Instead of trying to keep bond_release and bond_release_all in sync
I think we can re-use bond_release as the environment for calling it
is correct (RTNL is held). I have been running tests for the past
week and they came out successful. The only way for bond_release to fail
is for the slave to be attached in a different bond or to not be a slave
but that cannot happen as RTNL is held and no slave manipulations can be
achieved.
V2: As suggested bond_release is renamed to __bond_release_one with a
new parameter "all" introduced so to avoid calling unnecessary code while
destroying a bond, and a wrapper for it called bond_release is created
because of ndo_del_link. bond_release_all() is removed.
Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com>
Signed-off-by: Jay Vosburgh <fubar@us.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/bonding')
-rw-r--r-- | drivers/net/bonding/bond_main.c | 135 |
1 files changed, 18 insertions, 117 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 94c1534dd578..e242dd12e5a3 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c | |||
@@ -1937,7 +1937,8 @@ err_undo_flags: | |||
1937 | /* | 1937 | /* |
1938 | * Try to release the slave device <slave> from the bond device <master> | 1938 | * Try to release the slave device <slave> from the bond device <master> |
1939 | * It is legal to access curr_active_slave without a lock because all the function | 1939 | * It is legal to access curr_active_slave without a lock because all the function |
1940 | * is write-locked. | 1940 | * is write-locked. If "all" is true it means that the function is being called |
1941 | * while destroying a bond interface and all slaves are being released. | ||
1941 | * | 1942 | * |
1942 | * The rules for slave state should be: | 1943 | * The rules for slave state should be: |
1943 | * for Active/Backup: | 1944 | * for Active/Backup: |
@@ -1945,7 +1946,9 @@ err_undo_flags: | |||
1945 | * for Bonded connections: | 1946 | * for Bonded connections: |
1946 | * The first up interface should be left on and all others downed. | 1947 | * The first up interface should be left on and all others downed. |
1947 | */ | 1948 | */ |
1948 | int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) | 1949 | static int __bond_release_one(struct net_device *bond_dev, |
1950 | struct net_device *slave_dev, | ||
1951 | bool all) | ||
1949 | { | 1952 | { |
1950 | struct bonding *bond = netdev_priv(bond_dev); | 1953 | struct bonding *bond = netdev_priv(bond_dev); |
1951 | struct slave *slave, *oldcurrent; | 1954 | struct slave *slave, *oldcurrent; |
@@ -1982,7 +1985,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) | |||
1982 | synchronize_net(); | 1985 | synchronize_net(); |
1983 | write_lock_bh(&bond->lock); | 1986 | write_lock_bh(&bond->lock); |
1984 | 1987 | ||
1985 | if (!bond->params.fail_over_mac) { | 1988 | if (!all && !bond->params.fail_over_mac) { |
1986 | if (ether_addr_equal(bond_dev->dev_addr, slave->perm_hwaddr) && | 1989 | if (ether_addr_equal(bond_dev->dev_addr, slave->perm_hwaddr) && |
1987 | bond->slave_cnt > 1) | 1990 | bond->slave_cnt > 1) |
1988 | pr_warning("%s: Warning: the permanent HWaddr of %s - %pM - is still in use by %s. Set the HWaddr of %s to a different address to avoid conflicts.\n", | 1991 | pr_warning("%s: Warning: the permanent HWaddr of %s - %pM - is still in use by %s. Set the HWaddr of %s to a different address to avoid conflicts.\n", |
@@ -2028,7 +2031,9 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) | |||
2028 | write_lock_bh(&bond->lock); | 2031 | write_lock_bh(&bond->lock); |
2029 | } | 2032 | } |
2030 | 2033 | ||
2031 | if (oldcurrent == slave) { | 2034 | if (all) { |
2035 | bond->curr_active_slave = NULL; | ||
2036 | } else if (oldcurrent == slave) { | ||
2032 | /* | 2037 | /* |
2033 | * Note that we hold RTNL over this sequence, so there | 2038 | * Note that we hold RTNL over this sequence, so there |
2034 | * is no concern that another slave add/remove event | 2039 | * is no concern that another slave add/remove event |
@@ -2117,6 +2122,12 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) | |||
2117 | return 0; /* deletion OK */ | 2122 | return 0; /* deletion OK */ |
2118 | } | 2123 | } |
2119 | 2124 | ||
2125 | /* A wrapper used because of ndo_del_link */ | ||
2126 | int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) | ||
2127 | { | ||
2128 | return __bond_release_one(bond_dev, slave_dev, false); | ||
2129 | } | ||
2130 | |||
2120 | /* | 2131 | /* |
2121 | * First release a slave and then destroy the bond if no more slaves are left. | 2132 | * First release a slave and then destroy the bond if no more slaves are left. |
2122 | * Must be under rtnl_lock when this function is called. | 2133 | * Must be under rtnl_lock when this function is called. |
@@ -2138,118 +2149,6 @@ static int bond_release_and_destroy(struct net_device *bond_dev, | |||
2138 | } | 2149 | } |
2139 | 2150 | ||
2140 | /* | 2151 | /* |
2141 | * This function releases all slaves. | ||
2142 | */ | ||
2143 | static int bond_release_all(struct net_device *bond_dev) | ||
2144 | { | ||
2145 | struct bonding *bond = netdev_priv(bond_dev); | ||
2146 | struct slave *slave; | ||
2147 | struct net_device *slave_dev; | ||
2148 | struct sockaddr addr; | ||
2149 | |||
2150 | write_lock_bh(&bond->lock); | ||
2151 | |||
2152 | netif_carrier_off(bond_dev); | ||
2153 | |||
2154 | if (bond->slave_cnt == 0) | ||
2155 | goto out; | ||
2156 | |||
2157 | bond->current_arp_slave = NULL; | ||
2158 | bond->primary_slave = NULL; | ||
2159 | bond_change_active_slave(bond, NULL); | ||
2160 | |||
2161 | while ((slave = bond->first_slave) != NULL) { | ||
2162 | /* Inform AD package of unbinding of slave | ||
2163 | * before slave is detached from the list. | ||
2164 | */ | ||
2165 | if (bond->params.mode == BOND_MODE_8023AD) | ||
2166 | bond_3ad_unbind_slave(slave); | ||
2167 | |||
2168 | slave_dev = slave->dev; | ||
2169 | bond_detach_slave(bond, slave); | ||
2170 | |||
2171 | /* now that the slave is detached, unlock and perform | ||
2172 | * all the undo steps that should not be called from | ||
2173 | * within a lock. | ||
2174 | */ | ||
2175 | write_unlock_bh(&bond->lock); | ||
2176 | |||
2177 | /* unregister rx_handler early so bond_handle_frame wouldn't | ||
2178 | * be called for this slave anymore. | ||
2179 | */ | ||
2180 | netdev_rx_handler_unregister(slave_dev); | ||
2181 | synchronize_net(); | ||
2182 | |||
2183 | if (bond_is_lb(bond)) { | ||
2184 | /* must be called only after the slave | ||
2185 | * has been detached from the list | ||
2186 | */ | ||
2187 | bond_alb_deinit_slave(bond, slave); | ||
2188 | } | ||
2189 | |||
2190 | bond_destroy_slave_symlinks(bond_dev, slave_dev); | ||
2191 | bond_del_vlans_from_slave(bond, slave_dev); | ||
2192 | |||
2193 | /* If the mode USES_PRIMARY, then we should only remove its | ||
2194 | * promisc and mc settings if it was the curr_active_slave, but that was | ||
2195 | * already taken care of above when we detached the slave | ||
2196 | */ | ||
2197 | if (!USES_PRIMARY(bond->params.mode)) { | ||
2198 | /* unset promiscuity level from slave */ | ||
2199 | if (bond_dev->flags & IFF_PROMISC) | ||
2200 | dev_set_promiscuity(slave_dev, -1); | ||
2201 | |||
2202 | /* unset allmulti level from slave */ | ||
2203 | if (bond_dev->flags & IFF_ALLMULTI) | ||
2204 | dev_set_allmulti(slave_dev, -1); | ||
2205 | |||
2206 | /* flush master's mc_list from slave */ | ||
2207 | netif_addr_lock_bh(bond_dev); | ||
2208 | bond_mc_list_flush(bond_dev, slave_dev); | ||
2209 | netif_addr_unlock_bh(bond_dev); | ||
2210 | } | ||
2211 | |||
2212 | bond_upper_dev_unlink(bond_dev, slave_dev); | ||
2213 | |||
2214 | slave_disable_netpoll(slave); | ||
2215 | |||
2216 | /* close slave before restoring its mac address */ | ||
2217 | dev_close(slave_dev); | ||
2218 | |||
2219 | if (!bond->params.fail_over_mac) { | ||
2220 | /* restore original ("permanent") mac address*/ | ||
2221 | memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN); | ||
2222 | addr.sa_family = slave_dev->type; | ||
2223 | dev_set_mac_address(slave_dev, &addr); | ||
2224 | } | ||
2225 | |||
2226 | kfree(slave); | ||
2227 | |||
2228 | /* re-acquire the lock before getting the next slave */ | ||
2229 | write_lock_bh(&bond->lock); | ||
2230 | } | ||
2231 | |||
2232 | eth_hw_addr_random(bond_dev); | ||
2233 | bond->dev_addr_from_first = true; | ||
2234 | |||
2235 | if (bond_vlan_used(bond)) { | ||
2236 | pr_warning("%s: Warning: clearing HW address of %s while it still has VLANs.\n", | ||
2237 | bond_dev->name, bond_dev->name); | ||
2238 | pr_warning("%s: When re-adding slaves, make sure the bond's HW address matches its VLANs'.\n", | ||
2239 | bond_dev->name); | ||
2240 | } | ||
2241 | |||
2242 | pr_info("%s: released all slaves\n", bond_dev->name); | ||
2243 | |||
2244 | out: | ||
2245 | write_unlock_bh(&bond->lock); | ||
2246 | |||
2247 | bond_compute_features(bond); | ||
2248 | |||
2249 | return 0; | ||
2250 | } | ||
2251 | |||
2252 | /* | ||
2253 | * This function changes the active slave to slave <slave_dev>. | 2152 | * This function changes the active slave to slave <slave_dev>. |
2254 | * It returns -EINVAL in the following cases. | 2153 | * It returns -EINVAL in the following cases. |
2255 | * - <slave_dev> is not found in the list. | 2154 | * - <slave_dev> is not found in the list. |
@@ -4440,7 +4339,9 @@ static void bond_uninit(struct net_device *bond_dev) | |||
4440 | bond_netpoll_cleanup(bond_dev); | 4339 | bond_netpoll_cleanup(bond_dev); |
4441 | 4340 | ||
4442 | /* Release the bonded slaves */ | 4341 | /* Release the bonded slaves */ |
4443 | bond_release_all(bond_dev); | 4342 | while (bond->first_slave != NULL) |
4343 | __bond_release_one(bond_dev, bond->first_slave->dev, true); | ||
4344 | pr_info("%s: released all slaves\n", bond_dev->name); | ||
4444 | 4345 | ||
4445 | list_del(&bond->bond_list); | 4346 | list_del(&bond->bond_list); |
4446 | 4347 | ||