diff -Nuarp a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c --- a/drivers/net/bonding/bond_3ad.c Sun Dec 21 16:08:47 2003 +++ b/drivers/net/bonding/bond_3ad.c Sun Dec 21 16:08:48 2003 @@ -198,13 +198,11 @@ static inline struct bonding *__get_bond */ static inline struct port *__get_first_port(struct bonding *bond) { - struct slave *slave = bond->next; - - if (slave == (struct slave *)bond) { + if (bond->slave_cnt == 0) { return NULL; } - return &(SLAVE_AD_INFO(slave).port); + return &(SLAVE_AD_INFO(bond->first_slave).port); } /** @@ -220,7 +218,7 @@ static inline struct port *__get_next_po struct slave *slave = port->slave; // If there's no bond for this port, or this is the last slave - if ((bond == NULL) || (slave->next == bond->next)) { + if ((bond == NULL) || (slave->next == bond->first_slave)) { return NULL; } @@ -238,12 +236,12 @@ static inline struct aggregator *__get_f { struct bonding *bond = __get_bond_by_port(port); - // If there's no bond for this port, or this is the last slave - if ((bond == NULL) || (bond->next == (struct slave *)bond)) { + // If there's no bond for this port, or bond has no slaves + if ((bond == NULL) || (bond->slave_cnt == 0)) { return NULL; } - return &(SLAVE_AD_INFO(bond->next).aggregator); + return &(SLAVE_AD_INFO(bond->first_slave).aggregator); } /** @@ -259,7 +257,7 @@ static inline struct aggregator *__get_n struct bonding *bond = bond_get_bond_by_slave(slave); // If there's no bond for this aggregator, or this is the last slave - if ((bond == NULL) || (slave->next == bond->next)) { + if ((bond == NULL) || (slave->next == bond->first_slave)) { return NULL; } @@ -2131,7 +2129,7 @@ void bond_3ad_state_machine_handler(stru } //check if there are any slaves - if (bond->next == (struct slave *)bond) { + if (bond->slave_cnt == 0) { goto re_arm; } @@ -2359,6 +2357,7 @@ int bond_3ad_xmit_xor(struct sk_buff *sk int slave_agg_no; int slaves_in_agg; int agg_id; + int i; struct ad_info ad_info; if (!IS_UP(dev)) { /* bond down */ @@ -2373,10 +2372,9 @@ int bond_3ad_xmit_xor(struct sk_buff *sk } read_lock(&bond->lock); - slave = bond->prev; /* check if bond is empty */ - if ((slave == (struct slave *)bond) || (bond->slave_cnt == 0)) { + if (bond->slave_cnt == 0) { printk(KERN_DEBUG DRV_NAME ": Error: bond is empty\n"); dev_kfree_skb(skb); read_unlock(&bond->lock); @@ -2401,16 +2399,9 @@ int bond_3ad_xmit_xor(struct sk_buff *sk return 0; } - /* we're at the root, get the first slave */ - if ((slave == NULL) || (slave->dev == NULL)) { - /* no suitable interface, frame not sent */ - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; - } + slave_agg_no = (data->h_dest[5]^bond->device->dev_addr[5]) % slaves_in_agg; - slave_agg_no = (data->h_dest[5]^slave->dev->dev_addr[5]) % slaves_in_agg; - while (slave != (struct slave *)bond) { + bond_for_each_slave(bond, slave, i) { struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator; if (agg && (agg->aggregator_identifier == agg_id)) { @@ -2419,17 +2410,9 @@ int bond_3ad_xmit_xor(struct sk_buff *sk break; } } - - slave = slave->prev; - if (slave == NULL) { - printk(KERN_ERR DRV_NAME ": Error: slave is NULL\n"); - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; - } } - if (slave == (struct slave *)bond) { + if (slave_agg_no >= 0) { printk(KERN_ERR DRV_NAME ": Error: Couldn't find a slave to tx on for aggregator ID %d\n", agg_id); dev_kfree_skb(skb); read_unlock(&bond->lock); @@ -2438,18 +2421,9 @@ int bond_3ad_xmit_xor(struct sk_buff *sk start_at = slave; - do { + bond_for_each_slave_from(bond, slave, i, start_at) { int slave_agg_id = 0; - struct aggregator *agg; - - if (slave == NULL) { - printk(KERN_ERR DRV_NAME ": Error: slave is NULL\n"); - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; - } - - agg = SLAVE_AD_INFO(slave).port.aggregator; + struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator; if (agg) { slave_agg_id = agg->aggregator_identifier; @@ -2463,7 +2437,7 @@ int bond_3ad_xmit_xor(struct sk_buff *sk read_unlock(&bond->lock); return 0; } - } while ((slave = slave->next) != start_at); + } /* no suitable interface, frame not sent */ dev_kfree_skb(skb); diff -Nuarp a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c --- a/drivers/net/bonding/bond_alb.c Sun Dec 21 16:08:47 2003 +++ b/drivers/net/bonding/bond_alb.c Sun Dec 21 16:08:48 2003 @@ -232,17 +232,17 @@ tlb_get_least_loaded_slave(struct bondin struct slave *slave; struct slave *least_loaded; s64 curr_gap, max_gap; + int i, found = 0; /* Find the first enabled slave */ - slave = bond_get_first_slave(bond); - while (slave) { + bond_for_each_slave(bond, slave, i) { if (SLAVE_IS_OK(slave)) { + found = 1; break; } - slave = bond_get_next_slave(bond, slave); } - if (!slave) { + if (!found) { return NULL; } @@ -251,8 +251,7 @@ tlb_get_least_loaded_slave(struct bondin (s64)(SLAVE_TLB_INFO(slave).load * 8); /* Find the slave with the largest gap */ - slave = bond_get_next_slave(bond, slave); - while (slave) { + bond_for_each_slave_from(bond, slave, i, least_loaded) { if (SLAVE_IS_OK(slave)) { curr_gap = (s64)(slave->speed * 1000000) - (s64)(SLAVE_TLB_INFO(slave).load * 8); @@ -261,7 +260,6 @@ tlb_get_least_loaded_slave(struct bondin max_gap = curr_gap; } } - slave = bond_get_next_slave(bond, slave); } return least_loaded; @@ -398,14 +396,10 @@ rlb_next_rx_slave(struct bonding *bond) slave = bond_info->next_rx_slave; if (slave == NULL) { - slave = bond->next; + slave = bond->first_slave; } - /* this loop uses the circular linked list property of the - * slave's list to go through all slaves - */ - for (i = 0; i < bond->slave_cnt; i++, slave = slave->next) { - + bond_for_each_slave(bond, slave, i) { if (SLAVE_IS_OK(slave)) { if (!rx_slave) { rx_slave = slave; @@ -972,6 +966,7 @@ alb_change_hw_addr_on_detach(struct bond struct slave *tmp_slave; int perm_curr_diff; int perm_bond_diff; + int i, found = 0; perm_curr_diff = memcmp(slave->perm_hwaddr, slave->dev->dev_addr, @@ -980,17 +975,16 @@ alb_change_hw_addr_on_detach(struct bond bond->device->dev_addr, ETH_ALEN); if (perm_curr_diff && perm_bond_diff) { - tmp_slave = bond_get_first_slave(bond); - while (tmp_slave) { + bond_for_each_slave(bond, tmp_slave, i) { if (!memcmp(slave->perm_hwaddr, tmp_slave->dev->dev_addr, ETH_ALEN)) { + found = 1; break; } - tmp_slave = bond_get_next_slave(bond, tmp_slave); } - if (tmp_slave) { + if (found) { alb_swap_mac_addr(bond, slave, tmp_slave); } } @@ -1024,7 +1018,8 @@ alb_change_hw_addr_on_detach(struct bond static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slave *slave) { - struct slave *tmp_slave1, *tmp_slave2; + struct slave *tmp_slave1, *tmp_slave2, *free_mac_slave; + int i, j, found = 0; if (bond->slave_cnt == 0) { /* this is the first slave */ @@ -1036,14 +1031,14 @@ alb_handle_addr_collision_on_attach(stru * slaves in the bond. */ if (memcmp(slave->perm_hwaddr, bond->device->dev_addr, ETH_ALEN)) { - tmp_slave1 = bond_get_first_slave(bond); - for (; tmp_slave1; tmp_slave1 = bond_get_next_slave(bond, tmp_slave1)) { + bond_for_each_slave(bond, tmp_slave1, i) { if (!memcmp(tmp_slave1->dev->dev_addr, slave->dev->dev_addr, ETH_ALEN)) { + found = 1; break; } } - if (tmp_slave1) { + if (found) { /* a slave was found that is using the mac address * of the new slave */ @@ -1059,36 +1054,36 @@ alb_handle_addr_collision_on_attach(stru /* the slave's address is equal to the address of the bond * search for a spare address in the bond for this slave. */ - tmp_slave1 = bond_get_first_slave(bond); - for (; tmp_slave1; tmp_slave1 = bond_get_next_slave(bond, tmp_slave1)) { - - tmp_slave2 = bond_get_first_slave(bond); - for (; tmp_slave2; tmp_slave2 = bond_get_next_slave(bond, tmp_slave2)) { + free_mac_slave = NULL; + bond_for_each_slave(bond, tmp_slave1, i) { + found = 0; + bond_for_each_slave(bond, tmp_slave2, j) { if (!memcmp(tmp_slave1->perm_hwaddr, tmp_slave2->dev->dev_addr, ETH_ALEN)) { - + found = 1; break; } } - if (!tmp_slave2) { + if (!found) { /* no slave has tmp_slave1's perm addr * as its curr addr */ + free_mac_slave = tmp_slave1; break; } } - if (tmp_slave1) { - alb_set_slave_mac_addr(slave, tmp_slave1->perm_hwaddr, + if (free_mac_slave) { + alb_set_slave_mac_addr(slave, free_mac_slave->perm_hwaddr, bond->alb_info.rlb_enabled); printk(KERN_WARNING DRV_NAME ": Warning: the hw address of slave %s is in use by " "the bond; giving it the hw address of %s\n", - slave->dev->name, tmp_slave1->dev->name); + slave->dev->name, free_mac_slave->dev->name); } else { printk(KERN_ERR DRV_NAME ": Error: the hw address of slave %s is in use by the " @@ -1119,16 +1114,16 @@ static inline int alb_set_mac_address(struct bonding *bond, void *addr) { struct sockaddr sa; - struct slave *slave; + struct slave *slave, *stop_at; char tmp_addr[ETH_ALEN]; int error; + int i; if (bond->alb_info.rlb_enabled) { return 0; } - slave = bond_get_first_slave(bond); - for (; slave; slave = bond_get_next_slave(bond, slave)) { + bond_for_each_slave(bond, slave, i) { if (slave->dev->set_mac_address == NULL) { error = -EOPNOTSUPP; goto unwind; @@ -1152,8 +1147,10 @@ alb_set_mac_address(struct bonding *bond unwind: memcpy(sa.sa_data, bond->device->dev_addr, bond->device->addr_len); sa.sa_family = bond->device->type; - slave = bond_get_first_slave(bond); - for (; slave; slave = bond_get_next_slave(bond, slave)) { + + /* unwind from head to the slave that failed */ + stop_at = slave; + bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at) { memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN); slave->dev->set_mac_address(slave->dev, &sa); memcpy(slave->dev->dev_addr, tmp_addr, ETH_ALEN); @@ -1324,6 +1321,7 @@ bond_alb_monitor(struct bonding *bond) struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); struct slave *slave = NULL; int delta_in_ticks = HZ / ALB_TIMER_TICKS_PER_SEC; + int i; read_lock(&bond->lock); @@ -1348,10 +1346,8 @@ bond_alb_monitor(struct bonding *bond) * read. */ read_lock(&bond->ptrlock); - slave = bond_get_first_slave(bond); - while (slave) { + bond_for_each_slave(bond, slave, i) { alb_send_learning_packets(slave,slave->dev->dev_addr); - slave = bond_get_next_slave(bond, slave); } read_unlock(&bond->ptrlock); @@ -1361,8 +1357,7 @@ bond_alb_monitor(struct bonding *bond) /* rebalance tx traffic */ if (bond_info->tx_rebalance_counter >= BOND_TLB_REBALANCE_TICKS) { read_lock(&bond->ptrlock); - slave = bond_get_first_slave(bond); - while (slave) { + bond_for_each_slave(bond, slave, i) { tlb_clear_slave(bond, slave, 1); if (slave == bond->current_slave) { SLAVE_TLB_INFO(slave).load = @@ -1370,7 +1365,6 @@ bond_alb_monitor(struct bonding *bond) BOND_TLB_REBALANCE_INTERVAL; bond_info->unbalanced_load = 0; } - slave = bond_get_next_slave(bond, slave); } read_unlock(&bond->ptrlock); bond_info->tx_rebalance_counter = 0; @@ -1520,6 +1514,7 @@ void bond_alb_assign_current_slave(struct bonding *bond, struct slave *new_slave) { struct slave *swap_slave = bond->current_slave; + int i, found = 0; if (bond->current_slave == new_slave) { return; @@ -1542,18 +1537,17 @@ bond_alb_assign_current_slave(struct bon */ if (!swap_slave) { /* find slave that is holding the bond's mac address */ - swap_slave = bond_get_first_slave(bond); - while (swap_slave) { + bond_for_each_slave(bond, swap_slave, i) { if (!memcmp(swap_slave->dev->dev_addr, bond->device->dev_addr, ETH_ALEN)) { + found = 1; break; } - swap_slave = bond_get_next_slave(bond, swap_slave); } } /* current_slave must be set before calling alb_swap_mac_addr */ - if (swap_slave) { + if (found) { /* swap mac address */ alb_swap_mac_addr(bond, swap_slave, new_slave); } else { @@ -1572,6 +1566,7 @@ bond_alb_set_mac_address(struct net_devi struct sockaddr *sa = addr; struct slave *swap_slave = NULL; int error = 0; + int i, found = 0; if (!is_valid_ether_addr(sa->sa_data)) { return -EADDRNOTAVAIL; @@ -1592,15 +1587,14 @@ bond_alb_set_mac_address(struct net_devi return 0; } - swap_slave = bond_get_first_slave(bond); - while (swap_slave) { + bond_for_each_slave(bond, swap_slave, i) { if (!memcmp(swap_slave->dev->dev_addr, dev->dev_addr, ETH_ALEN)) { + found = 1; break; } - swap_slave = bond_get_next_slave(bond, swap_slave); } - if (swap_slave) { + if (found) { alb_swap_mac_addr(bond, swap_slave, bond->current_slave); } else { alb_set_slave_mac_addr(bond->current_slave, dev->dev_addr, diff -Nuarp a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c --- a/drivers/net/bonding/bond_main.c Sun Dec 21 16:08:47 2003 +++ b/drivers/net/bonding/bond_main.c Sun Dec 21 16:08:48 2003 @@ -644,99 +644,60 @@ void bond_set_slave_active_flags(struct slave->dev->flags &= ~IFF_NOARP; } -/* - * This function counts and verifies the the number of attached - * slaves, checking the count against the expected value (given that incr - * is either 1 or -1, for add or removal of a slave). Only - * bond_xmit_xor() uses the slave_cnt value, but this is still a good - * consistency check. - */ -static inline void -update_slave_cnt(struct bonding *bond, int incr) -{ - struct slave *slave = NULL; - int expect = bond->slave_cnt + incr; - - bond->slave_cnt = 0; - for (slave = bond->prev; slave != (struct slave *)bond; - slave = slave->prev) { - bond->slave_cnt++; - } - - if (expect != bond->slave_cnt) - BUG(); -} - /* - * This function detaches the slave from the list . + * This function detaches the slave from the list. * WARNING: no check is made to verify if the slave effectively - * belongs to . It returns in case it's needed. + * belongs to . * Nothing is freed on return, structures are just unchained. - * If the bond->current_slave pointer was pointing to , + * If any slave pointer in bond was pointing to , * it should be changed by the calling function. * * bond->lock held for writing by caller. */ -static struct slave * +static void bond_detach_slave(struct bonding *bond, struct slave *slave) { - if (bond->next == slave) { /* is the slave at the head ? */ - if (bond->prev == slave) { /* is the slave alone ? */ - bond->prev = bond->next = (struct slave *)bond; - } else { /* not alone */ - bond->next = slave->next; - slave->next->prev = (struct slave *)bond; - bond->prev->next = slave->next; - } - } else { + if (slave->next) { + slave->next->prev = slave->prev; + } + + if (slave->prev) { slave->prev->next = slave->next; - if (bond->prev == slave) { /* is this slave the last one ? */ - bond->prev = slave->prev; + } + + if (bond->first_slave == slave) { /* slave is the first slave */ + if (bond->slave_cnt > 1) { /* there are more slave */ + bond->first_slave = slave->next; } else { - slave->next->prev = slave->prev; + bond->first_slave = NULL; /* slave was the last one */ } } - update_slave_cnt(bond, -1); - - return slave; + slave->next = NULL; + slave->prev = NULL; + bond->slave_cnt--; } /* - * This function attaches the slave to the list . + * This function attaches the slave to the end of list. * * bond->lock held for writing by caller. */ static void bond_attach_slave(struct bonding *bond, struct slave *new_slave) { - /* - * queue to the end of the slaves list, make the first element its - * successor, the last one its predecessor, and make it the bond's - * predecessor. - * - * Just to clarify, so future bonding driver hackers don't go through - * the same confusion stage I did trying to figure this out, the - * slaves are stored in a double linked circular list, sortof. - * In the ->next direction, the last slave points to the first slave, - * bypassing bond; only the slaves are in the ->next direction. - * In the ->prev direction, however, the first slave points to bond - * and bond points to the last slave. - * - * It looks like a circle with a little bubble hanging off one side - * in the ->prev direction only. - * - * When going through the list once, its best to start at bond->prev - * and go in the ->prev direction, testing for bond. Doing this - * in the ->next direction doesn't work. Trust me, I know this now. - * :) -mts 2002.03.14 - */ - new_slave->prev = bond->prev; - new_slave->prev->next = new_slave; - bond->prev = new_slave; - new_slave->next = bond->next; + if (bond->first_slave == NULL) { /* attaching the first slave */ + new_slave->next = new_slave; + new_slave->prev = new_slave; + bond->first_slave = new_slave; + } else { + new_slave->next = bond->first_slave; + new_slave->prev = bond->first_slave->prev; + new_slave->next->prev = new_slave; + new_slave->prev->next = new_slave; + } - update_slave_cnt(bond, 1); + bond->slave_cnt++; } @@ -1065,8 +1026,10 @@ static void bond_mc_add(struct bonding * dev_mc_add(bond->current_slave->dev, addr, alen, 0); } else { struct slave *slave; - for (slave = bond->prev; slave != (struct slave *)bond; slave = slave->prev) + int i; + bond_for_each_slave(bond, slave, i) { dev_mc_add(slave->dev, addr, alen, 0); + } } } @@ -1082,8 +1045,10 @@ static void bond_mc_delete(struct bondin dev_mc_delete(bond->current_slave->dev, addr, alen, 0); } else { struct slave *slave; - for (slave = bond->prev; slave != (struct slave *)bond; slave = slave->prev) + int i; + bond_for_each_slave(bond, slave, i) { dev_mc_delete(slave->dev, addr, alen, 0); + } } } @@ -1134,9 +1099,9 @@ static void bond_set_promiscuity(struct } } else { - struct slave *slave; - for (slave = bond->prev; slave != (struct slave *)bond; - slave = slave->prev) { + struct slave *slave; + int i; + bond_for_each_slave(bond, slave, i) { dev_set_promiscuity(slave->dev, inc); } } @@ -1152,9 +1117,11 @@ static void bond_set_allmulti(struct bon if (bond->current_slave != NULL) dev_set_allmulti(bond->current_slave->dev, inc); } else { - struct slave *slave; - for (slave = bond->prev; slave != (struct slave *)bond; slave = slave->prev) + struct slave *slave; + int i; + bond_for_each_slave(bond, slave, i) { dev_set_allmulti(slave->dev, inc); + } } } @@ -1532,7 +1499,7 @@ static int bond_enslave(struct net_devic */ bond_set_slave_inactive_flags(new_slave); /* if this is the first slave */ - if (new_slave == bond->next) { + if (bond->slave_cnt == 1) { SLAVE_AD_INFO(new_slave).id = 1; /* Initialize AD with the number of times that the AD timer is called in 1 second * can be called only after the mac address of the bond is set @@ -1645,7 +1612,6 @@ err_free: static int bond_change_active(struct net_device *master_dev, struct net_device *slave_dev) { struct bonding *bond; - struct slave *slave; struct slave *oldactive = NULL; struct slave *newactive = NULL; int ret = 0; @@ -1659,15 +1625,9 @@ static int bond_change_active(struct net bond = (struct bonding *)master_dev->priv; write_lock_bh(&bond->lock); - slave = (struct slave *)bond; - oldactive = bond->current_slave; - while ((slave = slave->prev) != (struct slave *)bond) { - if(slave_dev == slave->dev) { - newactive = slave; - break; - } - } + oldactive = bond->current_slave; + newactive = bond_get_slave_by_dev(bond, slave_dev); /* * Changing to the current active: do nothing; return success. @@ -1700,12 +1660,13 @@ static struct slave *find_best_interface struct slave *newslave, *oldslave; struct slave *bestslave = NULL; int mintime; + int i; newslave = oldslave = bond->current_slave; if (newslave == NULL) { /* there were no active slaves left */ - if (bond->next != (struct slave *)bond) { /* found one slave */ - newslave = bond->next; + if (bond->slave_cnt > 0) { /* found one slave */ + newslave = bond->first_slave; } else { return NULL; /* still no slave, return NULL */ } @@ -1726,7 +1687,7 @@ static struct slave *find_best_interface /* remember where to stop iterating over the slaves */ oldslave = newslave; - do { + bond_for_each_slave_from(bond, newslave, i, oldslave) { if (IS_UP(newslave->dev)) { if (newslave->link == BOND_LINK_UP) { return newslave; @@ -1739,7 +1700,7 @@ static struct slave *find_best_interface } } } - } while ((newslave = newslave->next) != oldslave); + } return bestslave; } @@ -1859,9 +1820,8 @@ static int bond_release(struct net_devic struct bonding *bond; struct slave *our_slave; struct sockaddr addr; - - bond = (struct bonding *)master->priv; - + int mac_addr_differ; + /* slave is not a slave or master is not master of this slave */ if (!(slave->flags & IFF_SLAVE) || (slave->master != master)) { @@ -1871,89 +1831,87 @@ static int bond_release(struct net_devic return -EINVAL; } - write_lock_bh(&bond->lock); - bond->current_arp_slave = NULL; - our_slave = (struct slave *)bond; - while ((our_slave = our_slave->prev) != (struct slave *)bond) { - if (our_slave->dev == slave) { - int mac_addr_differ = memcmp(bond->device->dev_addr, - our_slave->perm_hwaddr, - ETH_ALEN); - if (!mac_addr_differ && (bond->slave_cnt > 1)) { - printk(KERN_WARNING DRV_NAME - ": Warning: the permanent HWaddr of %s " - "- %02X:%02X:%02X:%02X:%02X:%02X - is " - "still in use by %s. Set the HWaddr of " - "%s to a different address to avoid " - "conflicts.\n", - slave->name, - our_slave->perm_hwaddr[0], - our_slave->perm_hwaddr[1], - our_slave->perm_hwaddr[2], - our_slave->perm_hwaddr[3], - our_slave->perm_hwaddr[4], - our_slave->perm_hwaddr[5], - bond->device->name, - slave->name); - } + bond = (struct bonding *)master->priv; - /* Inform AD package of unbinding of slave. */ - if (bond_mode == BOND_MODE_8023AD) { - /* must be called before the slave is - * detached from the list - */ - bond_3ad_unbind_slave(our_slave); - } + write_lock_bh(&bond->lock); - printk(KERN_INFO DRV_NAME - ": %s: releasing %s interface %s\n", - master->name, - (our_slave->state == BOND_STATE_ACTIVE) - ? "active" : "backup", - slave->name); + our_slave = bond_get_slave_by_dev(bond, slave); + if (our_slave == NULL) { + /* not a slave of this bond */ + printk(KERN_INFO DRV_NAME + ": %s: %s not enslaved\n", + master->name, slave->name); + return -EINVAL; + } - /* release the slave from its bond */ - bond_detach_slave(bond, our_slave); + mac_addr_differ = memcmp(bond->device->dev_addr, + our_slave->perm_hwaddr, + ETH_ALEN); + if (!mac_addr_differ && (bond->slave_cnt > 1)) { + printk(KERN_WARNING DRV_NAME + ": Warning: the permanent HWaddr of %s " + "- %02X:%02X:%02X:%02X:%02X:%02X - is " + "still in use by %s. Set the HWaddr of " + "%s to a different address to avoid " + "conflicts.\n", + slave->name, + our_slave->perm_hwaddr[0], + our_slave->perm_hwaddr[1], + our_slave->perm_hwaddr[2], + our_slave->perm_hwaddr[3], + our_slave->perm_hwaddr[4], + our_slave->perm_hwaddr[5], + bond->device->name, + slave->name); + } - if (bond->primary_slave == our_slave) { - bond->primary_slave = NULL; - } + /* Inform AD package of unbinding of slave. */ + if (bond_mode == BOND_MODE_8023AD) { + /* must be called before the slave is + * detached from the list + */ + bond_3ad_unbind_slave(our_slave); + } - if (bond->current_slave == our_slave) { - change_active_interface(bond, NULL); - reselect_active_interface(bond); - } + printk(KERN_INFO DRV_NAME + ": %s: releasing %s interface %s\n", + master->name, + (our_slave->state == BOND_STATE_ACTIVE) + ? "active" : "backup", + slave->name); - if (bond->current_slave == NULL) { - printk(KERN_INFO DRV_NAME - ": %s: now running without any active " - "interface !\n", - master->name); - } + bond->current_arp_slave = NULL; - if ((bond_mode == BOND_MODE_TLB) || - (bond_mode == BOND_MODE_ALB)) { - /* must be called only after the slave has been - * detached from the list and the current_slave - * has been replaced (if our_slave == old_current) - */ - bond_alb_deinit_slave(bond, our_slave); - } + /* release the slave from its bond */ + bond_detach_slave(bond, our_slave); - break; - } + if (bond->primary_slave == our_slave) { + bond->primary_slave = NULL; + } + if (bond->current_slave == our_slave) { + change_active_interface(bond, NULL); + reselect_active_interface(bond); } - write_unlock_bh(&bond->lock); - - if (our_slave == (struct slave *)bond) { - /* if we get here, it's because the device was not found */ + + if (bond->current_slave == NULL) { printk(KERN_INFO DRV_NAME - ": %s: %s not enslaved\n", - master->name, slave->name); - return -EINVAL; + ": %s: now running without any active " + "interface !\n", + master->name); + } + + if ((bond_mode == BOND_MODE_TLB) || + (bond_mode == BOND_MODE_ALB)) { + /* must be called only after the slave has been + * detached from the list and the current_slave + * has been replaced (if our_slave == old_current) + */ + bond_alb_deinit_slave(bond, our_slave); } + write_unlock_bh(&bond->lock); + /* If the mode USES_PRIMARY, then we should only remove its * promisc and mc settings if it was the current_slave, but that was * already taken care of above when we detached the slave @@ -1997,7 +1955,7 @@ static int bond_release(struct net_devic * of the master so it will be set by the application * to the mac address of the first slave */ - if (bond->next == (struct slave *)bond) { + if (bond->slave_cnt == 0) { memset(master->dev_addr, 0, master->addr_len); } @@ -2018,7 +1976,8 @@ static int bond_release_all(struct net_d bond = (struct bonding *)master->priv; write_lock_bh(&bond->lock); - if (bond->next == (struct slave *) bond) { + + if (bond->slave_cnt == 0) { goto out; } @@ -2026,7 +1985,7 @@ static int bond_release_all(struct net_d bond->primary_slave = NULL; change_active_interface(bond, NULL); - while ((our_slave = bond->prev) != (struct slave *)bond) { + while ((our_slave = bond->first_slave) != NULL) { /* Inform AD package of unbinding of slave * before slave is detached from the list. */ @@ -2117,6 +2076,7 @@ static void bond_mii_monitor(struct net_ int slave_died = 0; int do_failover = 0; int delta_in_ticks = miimon * HZ / 1000; + int i; read_lock(&bond->lock); @@ -2134,13 +2094,11 @@ static void bond_mii_monitor(struct net_ * program could monitor the link itself if needed. */ - slave = (struct slave *)bond; - read_lock(&bond->ptrlock); oldcurrent = bond->current_slave; read_unlock(&bond->ptrlock); - while ((slave = slave->prev) != (struct slave *)bond) { + bond_for_each_slave(bond, slave, i) { struct net_device *dev = slave->dev; int link_state; u16 old_speed = slave->speed; @@ -2320,7 +2278,7 @@ static void bond_mii_monitor(struct net_ } } - } /* end of while */ + } /* end of for */ if (do_failover) { write_lock(&bond->ptrlock); @@ -2355,6 +2313,7 @@ static void loadbalance_arp_monitor(stru struct slave *slave, *oldcurrent; int do_failover = 0; int the_delta_in_ticks = arp_interval * HZ / 1000; + int i; read_lock(&bond->lock); @@ -2378,8 +2337,7 @@ static void loadbalance_arp_monitor(stru * TODO: what about up/down delay in arp mode? it wasn't here before * so it can wait */ - slave = (struct slave *)bond; - while ((slave = slave->prev) != (struct slave *)bond) { + bond_for_each_slave(bond, slave, i) { if (slave->link != BOND_LINK_UP) { @@ -2489,6 +2447,7 @@ static void activebackup_arp_monitor(str struct bonding *bond = (struct bonding *)master->priv; struct slave *slave; int the_delta_in_ticks = arp_interval * HZ / 1000; + int i; read_lock(&bond->lock); @@ -2505,8 +2464,7 @@ static void activebackup_arp_monitor(str * TODO: what about up/down delay in arp mode? it wasn't here before * so it can wait */ - slave = (struct slave *)bond; - while ((slave = slave->prev) != (struct slave *)bond) { + bond_for_each_slave(bond, slave, i) { if (slave->link != BOND_LINK_UP) { if ((jiffies - slave->dev->last_rx) <= @@ -2651,17 +2609,15 @@ static void activebackup_arp_monitor(str */ if (slave == NULL) { - if ((bond->current_arp_slave == NULL) || - (bond->current_arp_slave == (struct slave *)bond)) { - bond->current_arp_slave = bond->prev; + if (bond->current_arp_slave == NULL) { + bond->current_arp_slave = bond->first_slave; } - if (bond->current_arp_slave != (struct slave *)bond) { + if (bond->current_arp_slave) { bond_set_slave_inactive_flags(bond->current_arp_slave); - slave = bond->current_arp_slave->next; /* search for next candidate */ - do { + bond_for_each_slave_from(bond, slave, i, bond->current_arp_slave) { if (IS_UP(slave->dev)) { slave->link = BOND_LINK_BACK; bond_set_slave_active_flags(slave); @@ -2692,8 +2648,7 @@ static void activebackup_arp_monitor(str master->name, slave->dev->name); } - } while ((slave = slave->next) != - bond->current_arp_slave->next); + } } } @@ -2715,16 +2670,12 @@ static int bond_sethwaddr(struct net_dev static int bond_info_query(struct net_device *master, struct ifbond *info) { struct bonding *bond = (struct bonding *)master->priv; - struct slave *slave; info->bond_mode = bond_mode; - info->num_slaves = 0; info->miimon = miimon; read_lock_bh(&bond->lock); - for (slave = bond->prev; slave != (struct slave *)bond; slave = slave->prev) { - info->num_slaves++; - } + info->num_slaves = bond->slave_cnt; read_unlock_bh(&bond->lock); return 0; @@ -2735,21 +2686,22 @@ static int bond_slave_info_query(struct { struct bonding *bond = (struct bonding *)master->priv; struct slave *slave; - int cur_ndx = 0; + int i, found = 0; if (info->slave_id < 0) { return -ENODEV; } read_lock_bh(&bond->lock); - for (slave = bond->prev; - slave != (struct slave *)bond && cur_ndx < info->slave_id; - slave = slave->prev) { - cur_ndx++; + bond_for_each_slave(bond, slave, i) { + if (i == (int)info->slave_id) { + found = 1; + break; + } } read_unlock_bh(&bond->lock); - if (slave != (struct slave *)bond) { + if (found) { strcpy(info->slave_name, slave->dev->name); info->link = slave->link; info->state = slave->state; @@ -2966,7 +2918,8 @@ static int bond_xmit_broadcast(struct sk { struct slave *slave, *start_at; struct bonding *bond = (struct bonding *)dev->priv; - struct net_device *device_we_should_send_to = 0; + struct net_device *device_we_should_send_to = NULL; + int i; if (!IS_UP(dev)) { /* bond down */ dev_kfree_skb(skb); @@ -2976,17 +2929,17 @@ static int bond_xmit_broadcast(struct sk read_lock(&bond->lock); read_lock(&bond->ptrlock); - slave = start_at = bond->current_slave; + start_at = bond->current_slave; read_unlock(&bond->ptrlock); - if (slave == NULL) { /* we're at the root, get the first slave */ + if (start_at == NULL) { /* we're at the root, get the first slave */ /* no suitable interface, frame not sent */ read_unlock(&bond->lock); dev_kfree_skb(skb); return 0; } - do { + bond_for_each_slave_from(bond, slave, i, start_at) { if (IS_UP(slave->dev) && (slave->link == BOND_LINK_UP) && (slave->state == BOND_STATE_ACTIVE)) { @@ -3005,7 +2958,7 @@ static int bond_xmit_broadcast(struct sk } device_we_should_send_to = slave->dev; } - } while ((slave = slave->next) != start_at); + } if (device_we_should_send_to) { skb->dev = device_we_should_send_to; @@ -3023,6 +2976,7 @@ static int bond_xmit_roundrobin(struct s { struct slave *slave, *start_at; struct bonding *bond = (struct bonding *)dev->priv; + int i; if (!IS_UP(dev)) { /* bond down */ dev_kfree_skb(skb); @@ -3042,7 +2996,7 @@ static int bond_xmit_roundrobin(struct s return 0; } - do { + bond_for_each_slave_from(bond, slave, i, start_at) { if (IS_UP(slave->dev) && (slave->link == BOND_LINK_UP) && (slave->state == BOND_STATE_ACTIVE)) { @@ -3058,7 +3012,7 @@ static int bond_xmit_roundrobin(struct s read_unlock(&bond->lock); return 0; } - } while ((slave = slave->next) != start_at); + } /* no suitable interface, frame not sent */ dev_kfree_skb(skb); @@ -3077,6 +3031,7 @@ static int bond_xmit_xor(struct sk_buff struct bonding *bond = (struct bonding *)dev->priv; struct ethhdr *data = (struct ethhdr *)skb->data; int slave_no; + int i; if (!IS_UP(dev)) { /* bond down */ dev_kfree_skb(skb); @@ -3084,9 +3039,7 @@ static int bond_xmit_xor(struct sk_buff } read_lock(&bond->lock); - slave = bond->prev; - /* we're at the root, get the first slave */ if (bond->slave_cnt == 0) { /* no suitable interface, frame not sent */ dev_kfree_skb(skb); @@ -3094,15 +3047,18 @@ static int bond_xmit_xor(struct sk_buff return 0; } - slave_no = (data->h_dest[5]^slave->dev->dev_addr[5]) % bond->slave_cnt; + slave_no = (data->h_dest[5]^bond->device->dev_addr[5]) % bond->slave_cnt; - while ( (slave_no > 0) && (slave != (struct slave *)bond) ) { - slave = slave->prev; + bond_for_each_slave(bond, slave, i) { slave_no--; - } + if (slave_no < 0) { + break; + } + } + start_at = slave; - do { + bond_for_each_slave_from(bond, slave, i, start_at) { if (IS_UP(slave->dev) && (slave->link == BOND_LINK_UP) && (slave->state == BOND_STATE_ACTIVE)) { @@ -3114,7 +3070,7 @@ static int bond_xmit_xor(struct sk_buff read_unlock(&bond->lock); return 0; } - } while ((slave = slave->next) != start_at); + } /* no suitable interface, frame not sent */ dev_kfree_skb(skb); @@ -3174,12 +3130,13 @@ static struct net_device_stats *bond_get struct bonding *bond = (struct bonding *)dev->priv; struct net_device_stats *stats = &(bond->stats), *sstats; struct slave *slave; + int i; memset(stats, 0, sizeof(struct net_device_stats)); read_lock_bh(&bond->lock); - for (slave = bond->prev; slave != (struct slave *)bond; slave = slave->prev) { + bond_for_each_slave(bond, slave, i) { sstats = slave->dev->get_stats(slave->dev); stats->rx_packets += sstats->rx_packets; @@ -3223,6 +3180,7 @@ static void *bond_info_seq_start(struct struct bonding *bond = seq->private; loff_t off = 0; struct slave *slave; + int i; /* make sure the bond won't be taken away */ read_lock(&dev_base_lock); @@ -3232,9 +3190,7 @@ static void *bond_info_seq_start(struct return SEQ_START_TOKEN; } - for (slave = bond->prev; slave != (struct slave *)bond; - slave = slave->prev) { - + bond_for_each_slave(bond, slave, i) { if (++off == *pos) { return slave; } @@ -3250,12 +3206,12 @@ static void *bond_info_seq_next(struct s ++*pos; if (v == SEQ_START_TOKEN) { - slave = bond->prev; - } else { - slave = slave->prev; + return bond->first_slave; } - return (slave == (struct slave *) bond) ? NULL : slave; + slave = slave->next; + + return (slave == bond->first_slave) ? NULL : slave; } static void bond_info_seq_stop(struct seq_file *seq, void *v) @@ -3495,8 +3451,9 @@ bond_set_mac_address(struct net_device * { struct bonding *bond = (struct bonding *)dev->priv; struct sockaddr *sa = addr, tmp_sa; - struct slave *slave; + struct slave *slave, *stop_at; int error; + int i; dprintk("bond=%p, name=%s\n", bond, (bond_dev ? bond_dev->name : "None")); @@ -3504,8 +3461,22 @@ bond_set_mac_address(struct net_device * return -EADDRNOTAVAIL; } - for (slave = bond->prev; slave != (struct slave *)bond; - slave = slave->prev) { + /* Can't hold bond->lock with bh disabled here since + * some base drivers panic. On the other hand we can't + * hold bond->lock without bh disabled because we'll + * deadlock. The only solution is to rely on the fact + * that we're under rtnl_lock here, and the slaves + * list won't change. This doesn't solve the problem + * of setting the slave's hw address while it is + * transmitting, but the assumption is that the base + * driver can handle that. + * + * TODO: figure out a way to safely iterate the slaves + * list, but without holding a lock around the actual + * call to the base driver. + */ + + bond_for_each_slave(bond, slave, i) { dprintk("slave %p %s\n", slave, slave->dev->name); if (slave->dev->set_mac_address == NULL) { error = -EOPNOTSUPP; @@ -3534,8 +3505,9 @@ unwind: memcpy(tmp_sa.sa_data, dev->dev_addr, dev->addr_len); tmp_sa.sa_family = dev->type; - for (slave = slave->next; slave != bond->next; - slave = slave->next) { + /* unwind from the first slave that failed to head */ + stop_at = slave; + bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at) { int tmp_error; tmp_error = slave->dev->set_mac_address(slave->dev, &tmp_sa); @@ -3555,14 +3527,29 @@ static inline int bond_change_mtu(struct net_device *dev, int newmtu) { struct bonding *bond = (struct bonding *)dev->priv; - struct slave *slave; + struct slave *slave, *stop_at; int error; + int i; dprintk("bond=%p, name=%s, new_mtu=%d\n", bond, (bond_dev ? bond_dev->name : "None"), new_mtu); - for (slave = bond->prev; slave != (struct slave *)bond; - slave = slave->prev) { + /* Can't hold bond->lock with bh disabled here since + * some base drivers panic. On the other hand we can't + * hold bond->lock without bh disabled because we'll + * deadlock. The only solution is to rely on the fact + * that we're under rtnl_lock here, and the slaves + * list won't change. This doesn't solve the problem + * of setting the slave's MTU while it is + * transmitting, but the assumption is that the base + * driver can handle that. + * + * TODO: figure out a way to safely iterate the slaves + * list, but without holding a lock around the actual + * call to the base driver. + */ + + bond_for_each_slave(bond, slave, i) { dprintk("s %p s->p %p c_m %p\n", slave, slave->prev, slave->dev->change_mtu); if (slave->dev->change_mtu) { @@ -3591,9 +3578,9 @@ bond_change_mtu(struct net_device *dev, unwind: - for (slave = slave->next; slave != bond->next; - slave = slave->next) { - + /* unwind from the first slave that failed to head */ + stop_at = slave; + bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at) { if (slave->dev->change_mtu) { slave->dev->change_mtu(slave->dev, dev->mtu); } else { @@ -3769,7 +3756,7 @@ static int __init bond_init(struct net_d rwlock_init(&bond->ptrlock); /* Initialize pointers */ - bond->next = bond->prev = (struct slave *)bond; + bond->first_slave = NULL; bond->current_slave = NULL; bond->current_arp_slave = NULL; bond->primary_slave = NULL; diff -Nuarp a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h --- a/drivers/net/bonding/bonding.h Sun Dec 21 16:08:47 2003 +++ b/drivers/net/bonding/bonding.h Sun Dec 21 16:08:47 2003 @@ -88,12 +88,11 @@ struct slave { * beforehand. */ struct bonding { - struct slave *next; - struct slave *prev; + struct slave *first_slave; struct slave *current_slave; struct slave *primary_slave; struct slave *current_arp_slave; - __s32 slave_cnt; + int slave_cnt; /* never change this value outside the attach/detach wrappers */ rwlock_t lock; rwlock_t ptrlock; struct timer_list mii_timer; @@ -112,37 +111,45 @@ struct bonding { struct alb_bond_info alb_info; }; -/* Forward declarations */ -void bond_set_slave_active_flags(struct slave *slave); -void bond_set_slave_inactive_flags(struct slave *slave); +/** + * bond_for_each_slave_from - iterate the slaves list from a starting point + * @bond: the bond holding this list. + * @pos: current slave. + * @cnt: counter for max number of moves + * @start: starting point. + * + * Caller must hold bond->lock + */ +#define bond_for_each_slave_from(bond, pos, cnt, start) \ + for (cnt = 0, pos = start; \ + cnt < (bond)->slave_cnt; \ + cnt++, pos = (pos)->next) /** - * These functions can be used for iterating the slave list - * (which is circular) - * Caller must hold bond lock for read + * bond_for_each_slave_from_to - iterate the slaves list from start point to stop point + * @bond: the bond holding this list. + * @pos: current slave. + * @cnt: counter for number max of moves + * @start: start point. + * @stop: stop point. + * + * Caller must hold bond->lock */ -extern inline struct slave * -bond_get_first_slave(struct bonding *bond) -{ - /* if there are no slaves return NULL */ - if (bond->next == (struct slave *)bond) { - return NULL; - } - return bond->next; -} +#define bond_for_each_slave_from_to(bond, pos, cnt, start, stop) \ + for (cnt = 0, pos = start; \ + ((cnt < (bond)->slave_cnt) && (pos != (stop)->next)); \ + cnt++, pos = (pos)->next) /** - * Caller must hold bond lock for read + * bond_for_each_slave - iterate the slaves list from head + * @bond: the bond holding this list. + * @pos: current slave. + * @cnt: counter for max number of moves + * + * Caller must hold bond->lock */ -extern inline struct slave * -bond_get_next_slave(struct bonding *bond, struct slave *slave) -{ - /* If we have reached the last slave return NULL */ - if (slave->next == bond->next) { - return NULL; - } - return slave->next; -} +#define bond_for_each_slave(bond, pos, cnt) \ + bond_for_each_slave_from(bond, pos, cnt, (bond)->first_slave) /** * Returns NULL if the net_device does not belong to any of the bond's slaves @@ -152,19 +159,16 @@ bond_get_next_slave(struct bonding *bond extern inline struct slave * bond_get_slave_by_dev(struct bonding *bond, struct net_device *slave_dev) { - struct slave *our_slave = bond->next; - - /* check if the list of slaves is empty */ - if (our_slave == (struct slave *)bond) { - return NULL; - } + struct slave *slave = NULL; + int i; - for (; our_slave; our_slave = bond_get_next_slave(bond, our_slave)) { - if (our_slave->dev == slave_dev) { + bond_for_each_slave(bond, slave, i) { + if (slave->dev == slave_dev) { break; } } - return our_slave; + + return slave; } extern inline struct bonding * @@ -177,5 +181,9 @@ bond_get_bond_by_slave(struct slave *sla return (struct bonding *)slave->dev->master->priv; } +/* Forward declarations */ +void bond_set_slave_active_flags(struct slave *slave); +void bond_set_slave_inactive_flags(struct slave *slave); + #endif /* _LINUX_BONDING_H */