bonding: don't call alb_set_slave_mac_addr() while atomic
authorVeaceslav Falico <vfalico@redhat.com>
Mon, 17 Jun 2013 17:30:35 +0000 (19:30 +0200)
committerDavid S. Miller <davem@davemloft.net>
Mon, 17 Jun 2013 23:27:24 +0000 (16:27 -0700)
alb_set_slave_mac_addr() sets the mac address in alb mode via
dev_set_mac_address(), which might sleep. It's called from
alb_handle_addr_collision_on_attach() in atomic context (under
read_lock(bond->lock)), thus triggering a bug.

Fix this by moving the lock inside alb_handle_addr_collision_on_attach().

v1->v2:
As Nikolay Aleksandrov noticed, we can drop the bond->lock completely.
Also, use bond_slave_has_mac(), when possible.

Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/bonding/bond_alb.c

index a236234d2c2702894e41974d90d7d2351e023ff4..27fe329bdf8350cad97ab6850a7e2eb7e6195e0f 100644 (file)
@@ -1175,16 +1175,13 @@ static void alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *sla
  * @slave.
  *
  * assumption: this function is called before @slave is attached to the
- *            bond slave list.
- *
- * caller must hold the bond lock for write since the mac addresses are compared
- * and may be swapped.
+ *            bond slave list.
  */
 static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slave *slave)
 {
-       struct slave *tmp_slave1, *tmp_slave2, *free_mac_slave;
+       struct slave *tmp_slave1, *free_mac_slave = NULL;
        struct slave *has_bond_addr = bond->curr_active_slave;
-       int i, j, found = 0;
+       int i;
 
        if (bond->slave_cnt == 0) {
                /* this is the first slave */
@@ -1196,15 +1193,7 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav
         * slaves in the bond.
         */
        if (!ether_addr_equal_64bits(slave->perm_hwaddr, bond->dev->dev_addr)) {
-               bond_for_each_slave(bond, tmp_slave1, i) {
-                       if (ether_addr_equal_64bits(tmp_slave1->dev->dev_addr,
-                                                   slave->dev->dev_addr)) {
-                               found = 1;
-                               break;
-                       }
-               }
-
-               if (!found)
+               if (!bond_slave_has_mac(bond, slave->dev->dev_addr))
                        return 0;
 
                /* Try setting slave mac to bond address and fall-through
@@ -1215,19 +1204,8 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav
        /* The slave's address is equal to the address of the bond.
         * Search for a spare address in the bond for this slave.
         */
-       free_mac_slave = NULL;
-
        bond_for_each_slave(bond, tmp_slave1, i) {
-               found = 0;
-               bond_for_each_slave(bond, tmp_slave2, j) {
-                       if (ether_addr_equal_64bits(tmp_slave1->perm_hwaddr,
-                                                   tmp_slave2->dev->dev_addr)) {
-                               found = 1;
-                               break;
-                       }
-               }
-
-               if (!found) {
+               if (!bond_slave_has_mac(bond, tmp_slave1->perm_hwaddr)) {
                        /* no slave has tmp_slave1's perm addr
                         * as its curr addr
                         */
@@ -1607,15 +1585,7 @@ int bond_alb_init_slave(struct bonding *bond, struct slave *slave)
                return res;
        }
 
-       /* caller must hold the bond lock for write since the mac addresses
-        * are compared and may be swapped.
-        */
-       read_lock(&bond->lock);
-
        res = alb_handle_addr_collision_on_attach(bond, slave);
-
-       read_unlock(&bond->lock);
-
        if (res) {
                return res;
        }