You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'bonding_neighbours'
bonding: use neighbours instead of own lists Veaceslav Falico says: ==================== This patchset introduces all the needed infrastructure, on top of current adjacent lists, to be able to remove bond's slave_list/slave->list. The overhead in memory/CPU is minimal, and after the patchset bonding can rely on its slave-related functions, given the proper locking. I've done some netperf benchmarks on a vm, and the delta was about 0.1gbps for 35gbps as a whole, so no speed fluctuations. It also automatically creates lower/upper and master symlinks in dev's sysfs directory. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -2117,7 +2117,7 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
|
||||
read_lock(&bond->lock);
|
||||
|
||||
//check if there are any slaves
|
||||
if (list_empty(&bond->slave_list))
|
||||
if (!bond_has_slaves(bond))
|
||||
goto re_arm;
|
||||
|
||||
// check if agg_select_timer timer after initialize is timed out
|
||||
@@ -2417,14 +2417,15 @@ int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info)
|
||||
|
||||
int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
struct slave *slave, *start_at;
|
||||
struct bonding *bond = netdev_priv(dev);
|
||||
int slave_agg_no;
|
||||
int slaves_in_agg;
|
||||
int agg_id;
|
||||
int i;
|
||||
struct slave *slave, *first_ok_slave;
|
||||
struct aggregator *agg;
|
||||
struct ad_info ad_info;
|
||||
struct list_head *iter;
|
||||
int slaves_in_agg;
|
||||
int slave_agg_no;
|
||||
int res = 1;
|
||||
int agg_id;
|
||||
|
||||
read_lock(&bond->lock);
|
||||
if (__bond_3ad_get_active_agg_info(bond, &ad_info)) {
|
||||
@@ -2437,20 +2438,28 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
|
||||
agg_id = ad_info.aggregator_id;
|
||||
|
||||
if (slaves_in_agg == 0) {
|
||||
/*the aggregator is empty*/
|
||||
pr_debug("%s: Error: active aggregator is empty\n", dev->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
slave_agg_no = bond->xmit_hash_policy(skb, slaves_in_agg);
|
||||
first_ok_slave = NULL;
|
||||
|
||||
bond_for_each_slave(bond, slave) {
|
||||
struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator;
|
||||
bond_for_each_slave(bond, slave, iter) {
|
||||
agg = SLAVE_AD_INFO(slave).port.aggregator;
|
||||
if (!agg || agg->aggregator_identifier != agg_id)
|
||||
continue;
|
||||
|
||||
if (agg && (agg->aggregator_identifier == agg_id)) {
|
||||
if (slave_agg_no >= 0) {
|
||||
if (!first_ok_slave && SLAVE_IS_OK(slave))
|
||||
first_ok_slave = slave;
|
||||
slave_agg_no--;
|
||||
if (slave_agg_no < 0)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (SLAVE_IS_OK(slave)) {
|
||||
res = bond_dev_queue_xmit(bond, skb, slave->dev);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2460,20 +2469,10 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
|
||||
goto out;
|
||||
}
|
||||
|
||||
start_at = slave;
|
||||
|
||||
bond_for_each_slave_from(bond, slave, i, start_at) {
|
||||
int slave_agg_id = 0;
|
||||
struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator;
|
||||
|
||||
if (agg)
|
||||
slave_agg_id = agg->aggregator_identifier;
|
||||
|
||||
if (SLAVE_IS_OK(slave) && agg && (slave_agg_id == agg_id)) {
|
||||
res = bond_dev_queue_xmit(bond, skb, slave->dev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* we couldn't find any suitable slave after the agg_no, so use the
|
||||
* first suitable found, if found. */
|
||||
if (first_ok_slave)
|
||||
res = bond_dev_queue_xmit(bond, skb, first_ok_slave->dev);
|
||||
|
||||
out:
|
||||
read_unlock(&bond->lock);
|
||||
@@ -2515,11 +2514,12 @@ int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
|
||||
void bond_3ad_update_lacp_rate(struct bonding *bond)
|
||||
{
|
||||
struct port *port = NULL;
|
||||
struct list_head *iter;
|
||||
struct slave *slave;
|
||||
int lacp_fast;
|
||||
|
||||
lacp_fast = bond->params.lacp_fast;
|
||||
bond_for_each_slave(bond, slave) {
|
||||
bond_for_each_slave(bond, slave, iter) {
|
||||
port = &(SLAVE_AD_INFO(slave).port);
|
||||
__get_state_machine_lock(port);
|
||||
if (lacp_fast)
|
||||
|
||||
@@ -223,13 +223,14 @@ static long long compute_gap(struct slave *slave)
|
||||
static struct slave *tlb_get_least_loaded_slave(struct bonding *bond)
|
||||
{
|
||||
struct slave *slave, *least_loaded;
|
||||
struct list_head *iter;
|
||||
long long max_gap;
|
||||
|
||||
least_loaded = NULL;
|
||||
max_gap = LLONG_MIN;
|
||||
|
||||
/* Find the slave with the largest gap */
|
||||
bond_for_each_slave(bond, slave) {
|
||||
bond_for_each_slave(bond, slave, iter) {
|
||||
if (SLAVE_IS_OK(slave)) {
|
||||
long long gap = compute_gap(slave);
|
||||
|
||||
@@ -382,30 +383,31 @@ out:
|
||||
static struct slave *rlb_next_rx_slave(struct bonding *bond)
|
||||
{
|
||||
struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
|
||||
struct slave *rx_slave, *slave, *start_at;
|
||||
int i = 0;
|
||||
struct slave *before = NULL, *rx_slave = NULL, *slave;
|
||||
struct list_head *iter;
|
||||
bool found = false;
|
||||
|
||||
if (bond_info->next_rx_slave)
|
||||
start_at = bond_info->next_rx_slave;
|
||||
else
|
||||
start_at = bond_first_slave(bond);
|
||||
|
||||
rx_slave = NULL;
|
||||
|
||||
bond_for_each_slave_from(bond, slave, i, start_at) {
|
||||
if (SLAVE_IS_OK(slave)) {
|
||||
if (!rx_slave) {
|
||||
bond_for_each_slave(bond, slave, iter) {
|
||||
if (!SLAVE_IS_OK(slave))
|
||||
continue;
|
||||
if (!found) {
|
||||
if (!before || before->speed < slave->speed)
|
||||
before = slave;
|
||||
} else {
|
||||
if (!rx_slave || rx_slave->speed < slave->speed)
|
||||
rx_slave = slave;
|
||||
} else if (slave->speed > rx_slave->speed) {
|
||||
rx_slave = slave;
|
||||
}
|
||||
}
|
||||
if (slave == bond_info->rx_slave)
|
||||
found = true;
|
||||
}
|
||||
/* we didn't find anything after the current or we have something
|
||||
* better before and up to the current slave
|
||||
*/
|
||||
if (!rx_slave || (before && rx_slave->speed < before->speed))
|
||||
rx_slave = before;
|
||||
|
||||
if (rx_slave) {
|
||||
slave = bond_next_slave(bond, rx_slave);
|
||||
bond_info->next_rx_slave = slave;
|
||||
}
|
||||
if (rx_slave)
|
||||
bond_info->rx_slave = rx_slave;
|
||||
|
||||
return rx_slave;
|
||||
}
|
||||
@@ -1019,7 +1021,7 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[])
|
||||
|
||||
/* loop through vlans and send one packet for each */
|
||||
rcu_read_lock();
|
||||
netdev_for_each_upper_dev_rcu(bond->dev, upper, iter) {
|
||||
netdev_for_each_all_upper_dev_rcu(bond->dev, upper, iter) {
|
||||
if (upper->priv_flags & IFF_802_1Q_VLAN)
|
||||
alb_send_lp_vid(slave, mac_addr,
|
||||
vlan_dev_vlan_id(upper));
|
||||
@@ -1172,10 +1174,11 @@ static void alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *sla
|
||||
*/
|
||||
static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slave *slave)
|
||||
{
|
||||
struct slave *tmp_slave1, *free_mac_slave = NULL;
|
||||
struct slave *has_bond_addr = bond->curr_active_slave;
|
||||
struct slave *tmp_slave1, *free_mac_slave = NULL;
|
||||
struct list_head *iter;
|
||||
|
||||
if (list_empty(&bond->slave_list)) {
|
||||
if (!bond_has_slaves(bond)) {
|
||||
/* this is the first slave */
|
||||
return 0;
|
||||
}
|
||||
@@ -1196,7 +1199,7 @@ 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.
|
||||
*/
|
||||
bond_for_each_slave(bond, tmp_slave1) {
|
||||
bond_for_each_slave(bond, tmp_slave1, iter) {
|
||||
if (!bond_slave_has_mac(bond, tmp_slave1->perm_hwaddr)) {
|
||||
/* no slave has tmp_slave1's perm addr
|
||||
* as its curr addr
|
||||
@@ -1246,15 +1249,16 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav
|
||||
*/
|
||||
static int alb_set_mac_address(struct bonding *bond, void *addr)
|
||||
{
|
||||
char tmp_addr[ETH_ALEN];
|
||||
struct slave *slave;
|
||||
struct slave *slave, *rollback_slave;
|
||||
struct list_head *iter;
|
||||
struct sockaddr sa;
|
||||
char tmp_addr[ETH_ALEN];
|
||||
int res;
|
||||
|
||||
if (bond->alb_info.rlb_enabled)
|
||||
return 0;
|
||||
|
||||
bond_for_each_slave(bond, slave) {
|
||||
bond_for_each_slave(bond, slave, iter) {
|
||||
/* save net_device's current hw address */
|
||||
memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN);
|
||||
|
||||
@@ -1274,10 +1278,12 @@ unwind:
|
||||
sa.sa_family = bond->dev->type;
|
||||
|
||||
/* unwind from head to the slave that failed */
|
||||
bond_for_each_slave_continue_reverse(bond, slave) {
|
||||
memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN);
|
||||
dev_set_mac_address(slave->dev, &sa);
|
||||
memcpy(slave->dev->dev_addr, tmp_addr, ETH_ALEN);
|
||||
bond_for_each_slave(bond, rollback_slave, iter) {
|
||||
if (rollback_slave == slave)
|
||||
break;
|
||||
memcpy(tmp_addr, rollback_slave->dev->dev_addr, ETH_ALEN);
|
||||
dev_set_mac_address(rollback_slave->dev, &sa);
|
||||
memcpy(rollback_slave->dev->dev_addr, tmp_addr, ETH_ALEN);
|
||||
}
|
||||
|
||||
return res;
|
||||
@@ -1458,11 +1464,12 @@ void bond_alb_monitor(struct work_struct *work)
|
||||
struct bonding *bond = container_of(work, struct bonding,
|
||||
alb_work.work);
|
||||
struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
|
||||
struct list_head *iter;
|
||||
struct slave *slave;
|
||||
|
||||
read_lock(&bond->lock);
|
||||
|
||||
if (list_empty(&bond->slave_list)) {
|
||||
if (!bond_has_slaves(bond)) {
|
||||
bond_info->tx_rebalance_counter = 0;
|
||||
bond_info->lp_counter = 0;
|
||||
goto re_arm;
|
||||
@@ -1480,7 +1487,7 @@ void bond_alb_monitor(struct work_struct *work)
|
||||
*/
|
||||
read_lock(&bond->curr_slave_lock);
|
||||
|
||||
bond_for_each_slave(bond, slave)
|
||||
bond_for_each_slave(bond, slave, iter)
|
||||
alb_send_learning_packets(slave, slave->dev->dev_addr);
|
||||
|
||||
read_unlock(&bond->curr_slave_lock);
|
||||
@@ -1493,7 +1500,7 @@ void bond_alb_monitor(struct work_struct *work)
|
||||
|
||||
read_lock(&bond->curr_slave_lock);
|
||||
|
||||
bond_for_each_slave(bond, slave) {
|
||||
bond_for_each_slave(bond, slave, iter) {
|
||||
tlb_clear_slave(bond, slave, 1);
|
||||
if (slave == bond->curr_active_slave) {
|
||||
SLAVE_TLB_INFO(slave).load =
|
||||
@@ -1599,13 +1606,13 @@ int bond_alb_init_slave(struct bonding *bond, struct slave *slave)
|
||||
*/
|
||||
void bond_alb_deinit_slave(struct bonding *bond, struct slave *slave)
|
||||
{
|
||||
if (!list_empty(&bond->slave_list))
|
||||
if (bond_has_slaves(bond))
|
||||
alb_change_hw_addr_on_detach(bond, slave);
|
||||
|
||||
tlb_clear_slave(bond, slave, 0);
|
||||
|
||||
if (bond->alb_info.rlb_enabled) {
|
||||
bond->alb_info.next_rx_slave = NULL;
|
||||
bond->alb_info.rx_slave = NULL;
|
||||
rlb_clear_slave(bond, slave);
|
||||
}
|
||||
}
|
||||
@@ -1669,7 +1676,7 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave
|
||||
swap_slave = bond->curr_active_slave;
|
||||
rcu_assign_pointer(bond->curr_active_slave, new_slave);
|
||||
|
||||
if (!new_slave || list_empty(&bond->slave_list))
|
||||
if (!new_slave || !bond_has_slaves(bond))
|
||||
return;
|
||||
|
||||
/* set the new curr_active_slave to the bonds mac address
|
||||
|
||||
@@ -154,9 +154,7 @@ struct alb_bond_info {
|
||||
u8 rx_ntt; /* flag - need to transmit
|
||||
* to all rx clients
|
||||
*/
|
||||
struct slave *next_rx_slave;/* next slave to be assigned
|
||||
* to a new rx client for
|
||||
*/
|
||||
struct slave *rx_slave;/* last slave to xmit from */
|
||||
u8 primary_is_promisc; /* boolean */
|
||||
u32 rlb_promisc_timeout_counter;/* counts primary
|
||||
* promiscuity time
|
||||
|
||||
+155
-139
File diff suppressed because it is too large
Load Diff
@@ -10,8 +10,9 @@ static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos)
|
||||
__acquires(&bond->lock)
|
||||
{
|
||||
struct bonding *bond = seq->private;
|
||||
loff_t off = 0;
|
||||
struct list_head *iter;
|
||||
struct slave *slave;
|
||||
loff_t off = 0;
|
||||
|
||||
/* make sure the bond won't be taken away */
|
||||
rcu_read_lock();
|
||||
@@ -20,7 +21,7 @@ static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos)
|
||||
if (*pos == 0)
|
||||
return SEQ_START_TOKEN;
|
||||
|
||||
bond_for_each_slave(bond, slave)
|
||||
bond_for_each_slave(bond, slave, iter)
|
||||
if (++off == *pos)
|
||||
return slave;
|
||||
|
||||
|
||||
@@ -168,41 +168,6 @@ static const struct class_attribute class_attr_bonding_masters = {
|
||||
.namespace = bonding_namespace,
|
||||
};
|
||||
|
||||
int bond_create_slave_symlinks(struct net_device *master,
|
||||
struct net_device *slave)
|
||||
{
|
||||
char linkname[IFNAMSIZ+7];
|
||||
int ret = 0;
|
||||
|
||||
/* first, create a link from the slave back to the master */
|
||||
ret = sysfs_create_link(&(slave->dev.kobj), &(master->dev.kobj),
|
||||
"master");
|
||||
if (ret)
|
||||
return ret;
|
||||
/* next, create a link from the master to the slave */
|
||||
sprintf(linkname, "slave_%s", slave->name);
|
||||
ret = sysfs_create_link(&(master->dev.kobj), &(slave->dev.kobj),
|
||||
linkname);
|
||||
|
||||
/* free the master link created earlier in case of error */
|
||||
if (ret)
|
||||
sysfs_remove_link(&(slave->dev.kobj), "master");
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
void bond_destroy_slave_symlinks(struct net_device *master,
|
||||
struct net_device *slave)
|
||||
{
|
||||
char linkname[IFNAMSIZ+7];
|
||||
|
||||
sysfs_remove_link(&(slave->dev.kobj), "master");
|
||||
sprintf(linkname, "slave_%s", slave->name);
|
||||
sysfs_remove_link(&(master->dev.kobj), linkname);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Show the slaves in the current bond.
|
||||
*/
|
||||
@@ -210,11 +175,12 @@ static ssize_t bonding_show_slaves(struct device *d,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct bonding *bond = to_bond(d);
|
||||
struct list_head *iter;
|
||||
struct slave *slave;
|
||||
int res = 0;
|
||||
|
||||
read_lock(&bond->lock);
|
||||
bond_for_each_slave(bond, slave) {
|
||||
bond_for_each_slave(bond, slave, iter) {
|
||||
if (res > (PAGE_SIZE - IFNAMSIZ)) {
|
||||
/* not enough space for another interface name */
|
||||
if ((PAGE_SIZE - res) > 10)
|
||||
@@ -326,7 +292,7 @@ static ssize_t bonding_store_mode(struct device *d,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!list_empty(&bond->slave_list)) {
|
||||
if (bond_has_slaves(bond)) {
|
||||
pr_err("unable to update mode of %s because it has slaves.\n",
|
||||
bond->dev->name);
|
||||
ret = -EPERM;
|
||||
@@ -522,7 +488,7 @@ static ssize_t bonding_store_fail_over_mac(struct device *d,
|
||||
if (!rtnl_trylock())
|
||||
return restart_syscall();
|
||||
|
||||
if (!list_empty(&bond->slave_list)) {
|
||||
if (bond_has_slaves(bond)) {
|
||||
pr_err("%s: Can't alter fail_over_mac with slaves in bond.\n",
|
||||
bond->dev->name);
|
||||
ret = -EPERM;
|
||||
@@ -656,6 +622,7 @@ static ssize_t bonding_store_arp_targets(struct device *d,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct bonding *bond = to_bond(d);
|
||||
struct list_head *iter;
|
||||
struct slave *slave;
|
||||
__be32 newtarget, *targets;
|
||||
unsigned long *targets_rx;
|
||||
@@ -688,7 +655,7 @@ static ssize_t bonding_store_arp_targets(struct device *d,
|
||||
&newtarget);
|
||||
/* not to race with bond_arp_rcv */
|
||||
write_lock_bh(&bond->lock);
|
||||
bond_for_each_slave(bond, slave)
|
||||
bond_for_each_slave(bond, slave, iter)
|
||||
slave->target_last_arp_rx[ind] = jiffies;
|
||||
targets[ind] = newtarget;
|
||||
write_unlock_bh(&bond->lock);
|
||||
@@ -714,7 +681,7 @@ static ssize_t bonding_store_arp_targets(struct device *d,
|
||||
&newtarget);
|
||||
|
||||
write_lock_bh(&bond->lock);
|
||||
bond_for_each_slave(bond, slave) {
|
||||
bond_for_each_slave(bond, slave, iter) {
|
||||
targets_rx = slave->target_last_arp_rx;
|
||||
j = ind;
|
||||
for (; (j < BOND_MAX_ARP_TARGETS-1) && targets[j+1]; j++)
|
||||
@@ -1111,6 +1078,7 @@ static ssize_t bonding_store_primary(struct device *d,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct bonding *bond = to_bond(d);
|
||||
struct list_head *iter;
|
||||
char ifname[IFNAMSIZ];
|
||||
struct slave *slave;
|
||||
|
||||
@@ -1138,7 +1106,7 @@ static ssize_t bonding_store_primary(struct device *d,
|
||||
goto out;
|
||||
}
|
||||
|
||||
bond_for_each_slave(bond, slave) {
|
||||
bond_for_each_slave(bond, slave, iter) {
|
||||
if (strncmp(slave->dev->name, ifname, IFNAMSIZ) == 0) {
|
||||
pr_info("%s: Setting %s as primary slave.\n",
|
||||
bond->dev->name, slave->dev->name);
|
||||
@@ -1286,6 +1254,7 @@ static ssize_t bonding_store_active_slave(struct device *d,
|
||||
{
|
||||
struct slave *slave, *old_active, *new_active;
|
||||
struct bonding *bond = to_bond(d);
|
||||
struct list_head *iter;
|
||||
char ifname[IFNAMSIZ];
|
||||
|
||||
if (!rtnl_trylock())
|
||||
@@ -1313,7 +1282,7 @@ static ssize_t bonding_store_active_slave(struct device *d,
|
||||
goto out;
|
||||
}
|
||||
|
||||
bond_for_each_slave(bond, slave) {
|
||||
bond_for_each_slave(bond, slave, iter) {
|
||||
if (strncmp(slave->dev->name, ifname, IFNAMSIZ) == 0) {
|
||||
old_active = bond->curr_active_slave;
|
||||
new_active = slave;
|
||||
@@ -1493,6 +1462,7 @@ static ssize_t bonding_show_queue_id(struct device *d,
|
||||
char *buf)
|
||||
{
|
||||
struct bonding *bond = to_bond(d);
|
||||
struct list_head *iter;
|
||||
struct slave *slave;
|
||||
int res = 0;
|
||||
|
||||
@@ -1500,7 +1470,7 @@ static ssize_t bonding_show_queue_id(struct device *d,
|
||||
return restart_syscall();
|
||||
|
||||
read_lock(&bond->lock);
|
||||
bond_for_each_slave(bond, slave) {
|
||||
bond_for_each_slave(bond, slave, iter) {
|
||||
if (res > (PAGE_SIZE - IFNAMSIZ - 6)) {
|
||||
/* not enough space for another interface_name:queue_id pair */
|
||||
if ((PAGE_SIZE - res) > 10)
|
||||
@@ -1529,6 +1499,7 @@ static ssize_t bonding_store_queue_id(struct device *d,
|
||||
{
|
||||
struct slave *slave, *update_slave;
|
||||
struct bonding *bond = to_bond(d);
|
||||
struct list_head *iter;
|
||||
u16 qid;
|
||||
int ret = count;
|
||||
char *delim;
|
||||
@@ -1565,7 +1536,7 @@ static ssize_t bonding_store_queue_id(struct device *d,
|
||||
|
||||
/* Search for thes slave and check for duplicate qids */
|
||||
update_slave = NULL;
|
||||
bond_for_each_slave(bond, slave) {
|
||||
bond_for_each_slave(bond, slave, iter) {
|
||||
if (sdev == slave->dev)
|
||||
/*
|
||||
* We don't need to check the matching
|
||||
@@ -1619,6 +1590,7 @@ static ssize_t bonding_store_slaves_active(struct device *d,
|
||||
{
|
||||
struct bonding *bond = to_bond(d);
|
||||
int new_value, ret = count;
|
||||
struct list_head *iter;
|
||||
struct slave *slave;
|
||||
|
||||
if (sscanf(buf, "%d", &new_value) != 1) {
|
||||
@@ -1641,7 +1613,7 @@ static ssize_t bonding_store_slaves_active(struct device *d,
|
||||
}
|
||||
|
||||
read_lock(&bond->lock);
|
||||
bond_for_each_slave(bond, slave) {
|
||||
bond_for_each_slave(bond, slave, iter) {
|
||||
if (!bond_is_active_slave(slave)) {
|
||||
if (new_value)
|
||||
slave->inactive = 0;
|
||||
|
||||
@@ -72,63 +72,40 @@
|
||||
res; })
|
||||
|
||||
/* slave list primitives */
|
||||
#define bond_to_slave(ptr) list_entry(ptr, struct slave, list)
|
||||
#define bond_slave_list(bond) (&(bond)->dev->adj_list.lower)
|
||||
|
||||
#define bond_has_slaves(bond) !list_empty(bond_slave_list(bond))
|
||||
|
||||
/* IMPORTANT: bond_first/last_slave can return NULL in case of an empty list */
|
||||
#define bond_first_slave(bond) \
|
||||
list_first_entry_or_null(&(bond)->slave_list, struct slave, list)
|
||||
(bond_has_slaves(bond) ? \
|
||||
netdev_adjacent_get_private(bond_slave_list(bond)->next) : \
|
||||
NULL)
|
||||
#define bond_last_slave(bond) \
|
||||
(list_empty(&(bond)->slave_list) ? NULL : \
|
||||
bond_to_slave((bond)->slave_list.prev))
|
||||
(bond_has_slaves(bond) ? \
|
||||
netdev_adjacent_get_private(bond_slave_list(bond)->prev) : \
|
||||
NULL)
|
||||
|
||||
#define bond_is_first_slave(bond, pos) ((pos)->list.prev == &(bond)->slave_list)
|
||||
#define bond_is_last_slave(bond, pos) ((pos)->list.next == &(bond)->slave_list)
|
||||
#define bond_is_first_slave(bond, pos) (pos == bond_first_slave(bond))
|
||||
#define bond_is_last_slave(bond, pos) (pos == bond_last_slave(bond))
|
||||
|
||||
/* Since bond_first/last_slave can return NULL, these can return NULL too */
|
||||
#define bond_next_slave(bond, pos) \
|
||||
(bond_is_last_slave(bond, pos) ? bond_first_slave(bond) : \
|
||||
bond_to_slave((pos)->list.next))
|
||||
|
||||
#define bond_prev_slave(bond, pos) \
|
||||
(bond_is_first_slave(bond, pos) ? bond_last_slave(bond) : \
|
||||
bond_to_slave((pos)->list.prev))
|
||||
|
||||
/**
|
||||
* 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; pos && cnt < (bond)->slave_cnt; \
|
||||
cnt++, pos = bond_next_slave(bond, pos))
|
||||
#define bond_next_slave(bond, pos) __bond_next_slave(bond, pos)
|
||||
|
||||
/**
|
||||
* bond_for_each_slave - iterate over all slaves
|
||||
* @bond: the bond holding this list
|
||||
* @pos: current slave
|
||||
* @iter: list_head * iterator
|
||||
*
|
||||
* Caller must hold bond->lock
|
||||
*/
|
||||
#define bond_for_each_slave(bond, pos) \
|
||||
list_for_each_entry(pos, &(bond)->slave_list, list)
|
||||
#define bond_for_each_slave(bond, pos, iter) \
|
||||
netdev_for_each_lower_private((bond)->dev, pos, iter)
|
||||
|
||||
/* Caller must have rcu_read_lock */
|
||||
#define bond_for_each_slave_rcu(bond, pos) \
|
||||
list_for_each_entry_rcu(pos, &(bond)->slave_list, list)
|
||||
|
||||
/**
|
||||
* bond_for_each_slave_reverse - iterate in reverse from a given position
|
||||
* @bond: the bond holding this list
|
||||
* @pos: slave to continue from
|
||||
*
|
||||
* Caller must hold bond->lock
|
||||
*/
|
||||
#define bond_for_each_slave_continue_reverse(bond, pos) \
|
||||
list_for_each_entry_continue_reverse(pos, &(bond)->slave_list, list)
|
||||
#define bond_for_each_slave_rcu(bond, pos, iter) \
|
||||
netdev_for_each_lower_private_rcu((bond)->dev, pos, iter)
|
||||
|
||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||
extern atomic_t netpoll_block_tx;
|
||||
@@ -188,7 +165,6 @@ struct bond_parm_tbl {
|
||||
|
||||
struct slave {
|
||||
struct net_device *dev; /* first - useful for panic debug */
|
||||
struct list_head list;
|
||||
struct bonding *bond; /* our master */
|
||||
int delay;
|
||||
unsigned long jiffies;
|
||||
@@ -228,7 +204,6 @@ struct slave {
|
||||
*/
|
||||
struct bonding {
|
||||
struct net_device *dev; /* first - useful for panic debug */
|
||||
struct list_head slave_list;
|
||||
struct slave *curr_active_slave;
|
||||
struct slave *current_arp_slave;
|
||||
struct slave *primary_slave;
|
||||
@@ -268,6 +243,34 @@ struct bonding {
|
||||
#define bond_slave_get_rtnl(dev) \
|
||||
((struct slave *) rtnl_dereference(dev->rx_handler_data))
|
||||
|
||||
/**
|
||||
* __bond_next_slave - get the next slave after the one provided
|
||||
* @bond - bonding struct
|
||||
* @slave - the slave provided
|
||||
*
|
||||
* Returns the next slave after the slave provided, first slave if the
|
||||
* slave provided is the last slave and NULL if slave is not found
|
||||
*/
|
||||
static inline struct slave *__bond_next_slave(struct bonding *bond,
|
||||
struct slave *slave)
|
||||
{
|
||||
struct slave *slave_iter;
|
||||
struct list_head *iter;
|
||||
bool found = false;
|
||||
|
||||
netdev_for_each_lower_private(bond->dev, slave_iter, iter) {
|
||||
if (found)
|
||||
return slave_iter;
|
||||
if (slave_iter == slave)
|
||||
found = true;
|
||||
}
|
||||
|
||||
if (found)
|
||||
return bond_first_slave(bond);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns NULL if the net_device does not belong to any of the bond's slaves
|
||||
*
|
||||
@@ -276,13 +279,7 @@ struct bonding {
|
||||
static inline struct slave *bond_get_slave_by_dev(struct bonding *bond,
|
||||
struct net_device *slave_dev)
|
||||
{
|
||||
struct slave *slave = NULL;
|
||||
|
||||
bond_for_each_slave(bond, slave)
|
||||
if (slave->dev == slave_dev)
|
||||
return slave;
|
||||
|
||||
return NULL;
|
||||
return netdev_lower_dev_get_private(bond->dev, slave_dev);
|
||||
}
|
||||
|
||||
static inline struct bonding *bond_get_bond_by_slave(struct slave *slave)
|
||||
@@ -439,8 +436,6 @@ int bond_create(struct net *net, const char *name);
|
||||
int bond_create_sysfs(struct bond_net *net);
|
||||
void bond_destroy_sysfs(struct bond_net *net);
|
||||
void bond_prepare_sysfs_group(struct bonding *bond);
|
||||
int bond_create_slave_symlinks(struct net_device *master, struct net_device *slave);
|
||||
void bond_destroy_slave_symlinks(struct net_device *master, struct net_device *slave);
|
||||
int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev);
|
||||
int bond_release(struct net_device *bond_dev, struct net_device *slave_dev);
|
||||
void bond_mii_monitor(struct work_struct *);
|
||||
@@ -492,9 +487,10 @@ static inline void bond_destroy_proc_dir(struct bond_net *bn)
|
||||
static inline struct slave *bond_slave_has_mac(struct bonding *bond,
|
||||
const u8 *mac)
|
||||
{
|
||||
struct list_head *iter;
|
||||
struct slave *tmp;
|
||||
|
||||
bond_for_each_slave(bond, tmp)
|
||||
bond_for_each_slave(bond, tmp, iter)
|
||||
if (ether_addr_equal_64bits(mac, tmp->dev->dev_addr))
|
||||
return tmp;
|
||||
|
||||
|
||||
@@ -3983,6 +3983,7 @@ static int cxgb4_inet6addr_handler(struct notifier_block *this,
|
||||
struct net_device *event_dev;
|
||||
int ret = NOTIFY_DONE;
|
||||
struct bonding *bond = netdev_priv(ifa->idev->dev);
|
||||
struct list_head *iter;
|
||||
struct slave *slave;
|
||||
struct pci_dev *first_pdev = NULL;
|
||||
|
||||
@@ -3995,7 +3996,7 @@ static int cxgb4_inet6addr_handler(struct notifier_block *this,
|
||||
* in all of them only once.
|
||||
*/
|
||||
read_lock(&bond->lock);
|
||||
bond_for_each_slave(bond, slave) {
|
||||
bond_for_each_slave(bond, slave, iter) {
|
||||
if (!first_pdev) {
|
||||
ret = clip_add(slave->dev, ifa, event);
|
||||
/* If clip_add is success then only initialize
|
||||
|
||||
@@ -1143,8 +1143,18 @@ struct net_device {
|
||||
struct list_head dev_list;
|
||||
struct list_head napi_list;
|
||||
struct list_head unreg_list;
|
||||
struct list_head upper_dev_list; /* List of upper devices */
|
||||
struct list_head lower_dev_list;
|
||||
|
||||
/* directly linked devices, like slaves for bonding */
|
||||
struct {
|
||||
struct list_head upper;
|
||||
struct list_head lower;
|
||||
} adj_list;
|
||||
|
||||
/* all linked devices, *including* neighbours */
|
||||
struct {
|
||||
struct list_head upper;
|
||||
struct list_head lower;
|
||||
} all_adj_list;
|
||||
|
||||
|
||||
/* currently active device features */
|
||||
@@ -2813,24 +2823,49 @@ extern int bpf_jit_enable;
|
||||
extern bool netdev_has_upper_dev(struct net_device *dev,
|
||||
struct net_device *upper_dev);
|
||||
extern bool netdev_has_any_upper_dev(struct net_device *dev);
|
||||
extern struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev,
|
||||
struct list_head **iter);
|
||||
extern struct net_device *netdev_all_upper_get_next_dev_rcu(struct net_device *dev,
|
||||
struct list_head **iter);
|
||||
|
||||
/* iterate through upper list, must be called under RCU read lock */
|
||||
#define netdev_for_each_upper_dev_rcu(dev, upper, iter) \
|
||||
for (iter = &(dev)->upper_dev_list, \
|
||||
upper = netdev_upper_get_next_dev_rcu(dev, &(iter)); \
|
||||
upper; \
|
||||
upper = netdev_upper_get_next_dev_rcu(dev, &(iter)))
|
||||
#define netdev_for_each_all_upper_dev_rcu(dev, updev, iter) \
|
||||
for (iter = &(dev)->all_adj_list.upper, \
|
||||
updev = netdev_all_upper_get_next_dev_rcu(dev, &(iter)); \
|
||||
updev; \
|
||||
updev = netdev_all_upper_get_next_dev_rcu(dev, &(iter)))
|
||||
|
||||
extern void *netdev_lower_get_next_private(struct net_device *dev,
|
||||
struct list_head **iter);
|
||||
extern void *netdev_lower_get_next_private_rcu(struct net_device *dev,
|
||||
struct list_head **iter);
|
||||
|
||||
#define netdev_for_each_lower_private(dev, priv, iter) \
|
||||
for (iter = (dev)->adj_list.lower.next, \
|
||||
priv = netdev_lower_get_next_private(dev, &(iter)); \
|
||||
priv; \
|
||||
priv = netdev_lower_get_next_private(dev, &(iter)))
|
||||
|
||||
#define netdev_for_each_lower_private_rcu(dev, priv, iter) \
|
||||
for (iter = &(dev)->adj_list.lower, \
|
||||
priv = netdev_lower_get_next_private_rcu(dev, &(iter)); \
|
||||
priv; \
|
||||
priv = netdev_lower_get_next_private_rcu(dev, &(iter)))
|
||||
|
||||
extern void *netdev_adjacent_get_private(struct list_head *adj_list);
|
||||
extern struct net_device *netdev_master_upper_dev_get(struct net_device *dev);
|
||||
extern struct net_device *netdev_master_upper_dev_get_rcu(struct net_device *dev);
|
||||
extern int netdev_upper_dev_link(struct net_device *dev,
|
||||
struct net_device *upper_dev);
|
||||
extern int netdev_master_upper_dev_link(struct net_device *dev,
|
||||
struct net_device *upper_dev);
|
||||
extern int netdev_master_upper_dev_link_private(struct net_device *dev,
|
||||
struct net_device *upper_dev,
|
||||
void *private);
|
||||
extern void netdev_upper_dev_unlink(struct net_device *dev,
|
||||
struct net_device *upper_dev);
|
||||
extern void *netdev_lower_dev_get_private_rcu(struct net_device *dev,
|
||||
struct net_device *lower_dev);
|
||||
extern void *netdev_lower_dev_get_private(struct net_device *dev,
|
||||
struct net_device *lower_dev);
|
||||
extern int skb_checksum_help(struct sk_buff *skb);
|
||||
extern struct sk_buff *__skb_gso_segment(struct sk_buff *skb,
|
||||
netdev_features_t features, bool tx_path);
|
||||
|
||||
+9
-9
@@ -98,14 +98,14 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
|
||||
vlan_gvrp_request_leave(dev);
|
||||
|
||||
vlan_group_set_device(grp, vlan->vlan_proto, vlan_id, NULL);
|
||||
|
||||
netdev_upper_dev_unlink(real_dev, dev);
|
||||
/* Because unregister_netdevice_queue() makes sure at least one rcu
|
||||
* grace period is respected before device freeing,
|
||||
* we dont need to call synchronize_net() here.
|
||||
*/
|
||||
unregister_netdevice_queue(dev, head);
|
||||
|
||||
netdev_upper_dev_unlink(real_dev, dev);
|
||||
|
||||
if (grp->nr_vlan_devs == 0) {
|
||||
vlan_mvrp_uninit_applicant(real_dev);
|
||||
vlan_gvrp_uninit_applicant(real_dev);
|
||||
@@ -169,13 +169,13 @@ int register_vlan_dev(struct net_device *dev)
|
||||
if (err < 0)
|
||||
goto out_uninit_mvrp;
|
||||
|
||||
err = netdev_upper_dev_link(real_dev, dev);
|
||||
if (err)
|
||||
goto out_uninit_mvrp;
|
||||
|
||||
err = register_netdevice(dev);
|
||||
if (err < 0)
|
||||
goto out_upper_dev_unlink;
|
||||
goto out_uninit_mvrp;
|
||||
|
||||
err = netdev_upper_dev_link(real_dev, dev);
|
||||
if (err)
|
||||
goto out_unregister_netdev;
|
||||
|
||||
/* Account for reference in struct vlan_dev_priv */
|
||||
dev_hold(real_dev);
|
||||
@@ -191,8 +191,8 @@ int register_vlan_dev(struct net_device *dev)
|
||||
|
||||
return 0;
|
||||
|
||||
out_upper_dev_unlink:
|
||||
netdev_upper_dev_unlink(real_dev, dev);
|
||||
out_unregister_netdev:
|
||||
unregister_netdevice(dev);
|
||||
out_uninit_mvrp:
|
||||
if (grp->nr_vlan_devs == 0)
|
||||
vlan_mvrp_uninit_applicant(real_dev);
|
||||
|
||||
+286
-118
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user