aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/bonding
diff options
context:
space:
mode:
authorNikolay Aleksandrov <nikolay@redhat.com>2014-09-09 17:17:00 -0400
committerDavid S. Miller <davem@davemloft.net>2014-09-09 20:31:35 -0400
commit059b47e8aaf997245bc531e980581de492315fe6 (patch)
treee6f179bf980f970af3e53659b491828570f6616d /drivers/net/bonding
parentecfede424e95b211050f777c3ae96356926ed1c4 (diff)
bonding: convert primary_slave to use RCU
This is necessary mainly for two bonding call sites: procfs and sysfs as it was dereferenced without any real protection. Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/bonding')
-rw-r--r--drivers/net/bonding/bond_main.c42
-rw-r--r--drivers/net/bonding/bond_netlink.c7
-rw-r--r--drivers/net/bonding/bond_options.c8
-rw-r--r--drivers/net/bonding/bond_procfs.c8
-rw-r--r--drivers/net/bonding/bond_sysfs.c10
-rw-r--r--drivers/net/bonding/bonding.h2
6 files changed, 43 insertions, 34 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index dcd331bd0c17..629037f79213 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -708,7 +708,7 @@ out:
708 708
709static bool bond_should_change_active(struct bonding *bond) 709static bool bond_should_change_active(struct bonding *bond)
710{ 710{
711 struct slave *prim = bond->primary_slave; 711 struct slave *prim = rtnl_dereference(bond->primary_slave);
712 struct slave *curr = bond_deref_active_protected(bond); 712 struct slave *curr = bond_deref_active_protected(bond);
713 713
714 if (!prim || !curr || curr->link != BOND_LINK_UP) 714 if (!prim || !curr || curr->link != BOND_LINK_UP)
@@ -732,13 +732,14 @@ static bool bond_should_change_active(struct bonding *bond)
732 */ 732 */
733static struct slave *bond_find_best_slave(struct bonding *bond) 733static struct slave *bond_find_best_slave(struct bonding *bond)
734{ 734{
735 struct slave *slave, *bestslave = NULL; 735 struct slave *slave, *bestslave = NULL, *primary;
736 struct list_head *iter; 736 struct list_head *iter;
737 int mintime = bond->params.updelay; 737 int mintime = bond->params.updelay;
738 738
739 if (bond->primary_slave && bond->primary_slave->link == BOND_LINK_UP && 739 primary = rtnl_dereference(bond->primary_slave);
740 if (primary && primary->link == BOND_LINK_UP &&
740 bond_should_change_active(bond)) 741 bond_should_change_active(bond))
741 return bond->primary_slave; 742 return primary;
742 743
743 bond_for_each_slave(bond, slave, iter) { 744 bond_for_each_slave(bond, slave, iter) {
744 if (slave->link == BOND_LINK_UP) 745 if (slave->link == BOND_LINK_UP)
@@ -1482,7 +1483,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
1482 if (bond_uses_primary(bond) && bond->params.primary[0]) { 1483 if (bond_uses_primary(bond) && bond->params.primary[0]) {
1483 /* if there is a primary slave, remember it */ 1484 /* if there is a primary slave, remember it */
1484 if (strcmp(bond->params.primary, new_slave->dev->name) == 0) { 1485 if (strcmp(bond->params.primary, new_slave->dev->name) == 0) {
1485 bond->primary_slave = new_slave; 1486 rcu_assign_pointer(bond->primary_slave, new_slave);
1486 bond->force_primary = true; 1487 bond->force_primary = true;
1487 } 1488 }
1488 } 1489 }
@@ -1596,8 +1597,8 @@ err_detach:
1596 bond_hw_addr_flush(bond_dev, slave_dev); 1597 bond_hw_addr_flush(bond_dev, slave_dev);
1597 1598
1598 vlan_vids_del_by_dev(slave_dev, bond_dev); 1599 vlan_vids_del_by_dev(slave_dev, bond_dev);
1599 if (bond->primary_slave == new_slave) 1600 if (rcu_access_pointer(bond->primary_slave) == new_slave)
1600 bond->primary_slave = NULL; 1601 RCU_INIT_POINTER(bond->primary_slave, NULL);
1601 if (rcu_access_pointer(bond->curr_active_slave) == new_slave) { 1602 if (rcu_access_pointer(bond->curr_active_slave) == new_slave) {
1602 block_netpoll_tx(); 1603 block_netpoll_tx();
1603 write_lock_bh(&bond->curr_slave_lock); 1604 write_lock_bh(&bond->curr_slave_lock);
@@ -1606,6 +1607,8 @@ err_detach:
1606 write_unlock_bh(&bond->curr_slave_lock); 1607 write_unlock_bh(&bond->curr_slave_lock);
1607 unblock_netpoll_tx(); 1608 unblock_netpoll_tx();
1608 } 1609 }
1610 /* either primary_slave or curr_active_slave might've changed */
1611 synchronize_rcu();
1609 slave_disable_netpoll(new_slave); 1612 slave_disable_netpoll(new_slave);
1610 1613
1611err_close: 1614err_close:
@@ -1714,8 +1717,8 @@ static int __bond_release_one(struct net_device *bond_dev,
1714 bond_dev->name, slave_dev->name); 1717 bond_dev->name, slave_dev->name);
1715 } 1718 }
1716 1719
1717 if (bond->primary_slave == slave) 1720 if (rtnl_dereference(bond->primary_slave) == slave)
1718 bond->primary_slave = NULL; 1721 RCU_INIT_POINTER(bond->primary_slave, NULL);
1719 1722
1720 if (oldcurrent == slave) { 1723 if (oldcurrent == slave) {
1721 write_lock_bh(&bond->curr_slave_lock); 1724 write_lock_bh(&bond->curr_slave_lock);
@@ -1976,7 +1979,7 @@ static int bond_miimon_inspect(struct bonding *bond)
1976static void bond_miimon_commit(struct bonding *bond) 1979static void bond_miimon_commit(struct bonding *bond)
1977{ 1980{
1978 struct list_head *iter; 1981 struct list_head *iter;
1979 struct slave *slave; 1982 struct slave *slave, *primary;
1980 1983
1981 bond_for_each_slave(bond, slave, iter) { 1984 bond_for_each_slave(bond, slave, iter) {
1982 switch (slave->new_link) { 1985 switch (slave->new_link) {
@@ -1987,13 +1990,14 @@ static void bond_miimon_commit(struct bonding *bond)
1987 slave->link = BOND_LINK_UP; 1990 slave->link = BOND_LINK_UP;
1988 slave->last_link_up = jiffies; 1991 slave->last_link_up = jiffies;
1989 1992
1993 primary = rtnl_dereference(bond->primary_slave);
1990 if (BOND_MODE(bond) == BOND_MODE_8023AD) { 1994 if (BOND_MODE(bond) == BOND_MODE_8023AD) {
1991 /* prevent it from being the active one */ 1995 /* prevent it from being the active one */
1992 bond_set_backup_slave(slave); 1996 bond_set_backup_slave(slave);
1993 } else if (BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) { 1997 } else if (BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) {
1994 /* make it immediately active */ 1998 /* make it immediately active */
1995 bond_set_active_slave(slave); 1999 bond_set_active_slave(slave);
1996 } else if (slave != bond->primary_slave) { 2000 } else if (slave != primary) {
1997 /* prevent it from being the active one */ 2001 /* prevent it from being the active one */
1998 bond_set_backup_slave(slave); 2002 bond_set_backup_slave(slave);
1999 } 2003 }
@@ -2011,8 +2015,7 @@ static void bond_miimon_commit(struct bonding *bond)
2011 bond_alb_handle_link_change(bond, slave, 2015 bond_alb_handle_link_change(bond, slave,
2012 BOND_LINK_UP); 2016 BOND_LINK_UP);
2013 2017
2014 if (!bond->curr_active_slave || 2018 if (!bond->curr_active_slave || slave == primary)
2015 (slave == bond->primary_slave))
2016 goto do_failover; 2019 goto do_failover;
2017 2020
2018 continue; 2021 continue;
@@ -2633,7 +2636,7 @@ static void bond_ab_arp_commit(struct bonding *bond)
2633 slave->dev->name); 2636 slave->dev->name);
2634 2637
2635 if (!rtnl_dereference(bond->curr_active_slave) || 2638 if (!rtnl_dereference(bond->curr_active_slave) ||
2636 (slave == bond->primary_slave)) 2639 slave == rtnl_dereference(bond->primary_slave))
2637 goto do_failover; 2640 goto do_failover;
2638 2641
2639 } 2642 }
@@ -2860,7 +2863,7 @@ static int bond_master_netdev_event(unsigned long event,
2860static int bond_slave_netdev_event(unsigned long event, 2863static int bond_slave_netdev_event(unsigned long event,
2861 struct net_device *slave_dev) 2864 struct net_device *slave_dev)
2862{ 2865{
2863 struct slave *slave = bond_slave_get_rtnl(slave_dev); 2866 struct slave *slave = bond_slave_get_rtnl(slave_dev), *primary;
2864 struct bonding *bond; 2867 struct bonding *bond;
2865 struct net_device *bond_dev; 2868 struct net_device *bond_dev;
2866 u32 old_speed; 2869 u32 old_speed;
@@ -2874,6 +2877,7 @@ static int bond_slave_netdev_event(unsigned long event,
2874 return NOTIFY_DONE; 2877 return NOTIFY_DONE;
2875 bond_dev = slave->bond->dev; 2878 bond_dev = slave->bond->dev;
2876 bond = slave->bond; 2879 bond = slave->bond;
2880 primary = rtnl_dereference(bond->primary_slave);
2877 2881
2878 switch (event) { 2882 switch (event) {
2879 case NETDEV_UNREGISTER: 2883 case NETDEV_UNREGISTER:
@@ -2921,18 +2925,18 @@ static int bond_slave_netdev_event(unsigned long event,
2921 !bond->params.primary[0]) 2925 !bond->params.primary[0])
2922 break; 2926 break;
2923 2927
2924 if (slave == bond->primary_slave) { 2928 if (slave == primary) {
2925 /* slave's name changed - he's no longer primary */ 2929 /* slave's name changed - he's no longer primary */
2926 bond->primary_slave = NULL; 2930 RCU_INIT_POINTER(bond->primary_slave, NULL);
2927 } else if (!strcmp(slave_dev->name, bond->params.primary)) { 2931 } else if (!strcmp(slave_dev->name, bond->params.primary)) {
2928 /* we have a new primary slave */ 2932 /* we have a new primary slave */
2929 bond->primary_slave = slave; 2933 rcu_assign_pointer(bond->primary_slave, slave);
2930 } else { /* we didn't change primary - exit */ 2934 } else { /* we didn't change primary - exit */
2931 break; 2935 break;
2932 } 2936 }
2933 2937
2934 netdev_info(bond->dev, "Primary slave changed to %s, reselecting active slave\n", 2938 netdev_info(bond->dev, "Primary slave changed to %s, reselecting active slave\n",
2935 bond->primary_slave ? slave_dev->name : "none"); 2939 primary ? slave_dev->name : "none");
2936 2940
2937 block_netpoll_tx(); 2941 block_netpoll_tx();
2938 write_lock_bh(&bond->curr_slave_lock); 2942 write_lock_bh(&bond->curr_slave_lock);
diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c
index e1489d9df2a4..c13d83e15ace 100644
--- a/drivers/net/bonding/bond_netlink.c
+++ b/drivers/net/bonding/bond_netlink.c
@@ -443,6 +443,7 @@ static int bond_fill_info(struct sk_buff *skb,
443 unsigned int packets_per_slave; 443 unsigned int packets_per_slave;
444 int ifindex, i, targets_added; 444 int ifindex, i, targets_added;
445 struct nlattr *targets; 445 struct nlattr *targets;
446 struct slave *primary;
446 447
447 if (nla_put_u8(skb, IFLA_BOND_MODE, BOND_MODE(bond))) 448 if (nla_put_u8(skb, IFLA_BOND_MODE, BOND_MODE(bond)))
448 goto nla_put_failure; 449 goto nla_put_failure;
@@ -492,9 +493,9 @@ static int bond_fill_info(struct sk_buff *skb,
492 bond->params.arp_all_targets)) 493 bond->params.arp_all_targets))
493 goto nla_put_failure; 494 goto nla_put_failure;
494 495
495 if (bond->primary_slave && 496 primary = rtnl_dereference(bond->primary_slave);
496 nla_put_u32(skb, IFLA_BOND_PRIMARY, 497 if (primary &&
497 bond->primary_slave->dev->ifindex)) 498 nla_put_u32(skb, IFLA_BOND_PRIMARY, primary->dev->ifindex))
498 goto nla_put_failure; 499 goto nla_put_failure;
499 500
500 if (nla_put_u8(skb, IFLA_BOND_PRIMARY_RESELECT, 501 if (nla_put_u8(skb, IFLA_BOND_PRIMARY_RESELECT,
diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c
index d8dc17faa6b4..7c9e176baecc 100644
--- a/drivers/net/bonding/bond_options.c
+++ b/drivers/net/bonding/bond_options.c
@@ -1090,7 +1090,7 @@ static int bond_option_primary_set(struct bonding *bond,
1090 /* check to see if we are clearing primary */ 1090 /* check to see if we are clearing primary */
1091 if (!strlen(primary)) { 1091 if (!strlen(primary)) {
1092 netdev_info(bond->dev, "Setting primary slave to None\n"); 1092 netdev_info(bond->dev, "Setting primary slave to None\n");
1093 bond->primary_slave = NULL; 1093 RCU_INIT_POINTER(bond->primary_slave, NULL);
1094 memset(bond->params.primary, 0, sizeof(bond->params.primary)); 1094 memset(bond->params.primary, 0, sizeof(bond->params.primary));
1095 bond_select_active_slave(bond); 1095 bond_select_active_slave(bond);
1096 goto out; 1096 goto out;
@@ -1100,16 +1100,16 @@ static int bond_option_primary_set(struct bonding *bond,
1100 if (strncmp(slave->dev->name, primary, IFNAMSIZ) == 0) { 1100 if (strncmp(slave->dev->name, primary, IFNAMSIZ) == 0) {
1101 netdev_info(bond->dev, "Setting %s as primary slave\n", 1101 netdev_info(bond->dev, "Setting %s as primary slave\n",
1102 slave->dev->name); 1102 slave->dev->name);
1103 bond->primary_slave = slave; 1103 rcu_assign_pointer(bond->primary_slave, slave);
1104 strcpy(bond->params.primary, slave->dev->name); 1104 strcpy(bond->params.primary, slave->dev->name);
1105 bond_select_active_slave(bond); 1105 bond_select_active_slave(bond);
1106 goto out; 1106 goto out;
1107 } 1107 }
1108 } 1108 }
1109 1109
1110 if (bond->primary_slave) { 1110 if (rtnl_dereference(bond->primary_slave)) {
1111 netdev_info(bond->dev, "Setting primary slave to None\n"); 1111 netdev_info(bond->dev, "Setting primary slave to None\n");
1112 bond->primary_slave = NULL; 1112 RCU_INIT_POINTER(bond->primary_slave, NULL);
1113 bond_select_active_slave(bond); 1113 bond_select_active_slave(bond);
1114 } 1114 }
1115 strncpy(bond->params.primary, primary, IFNAMSIZ); 1115 strncpy(bond->params.primary, primary, IFNAMSIZ);
diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c
index de62c0385dfb..1a9fe1ba4c60 100644
--- a/drivers/net/bonding/bond_procfs.c
+++ b/drivers/net/bonding/bond_procfs.c
@@ -66,7 +66,7 @@ static void bond_info_show_master(struct seq_file *seq)
66{ 66{
67 struct bonding *bond = seq->private; 67 struct bonding *bond = seq->private;
68 const struct bond_opt_value *optval; 68 const struct bond_opt_value *optval;
69 struct slave *curr; 69 struct slave *curr, *primary;
70 int i; 70 int i;
71 71
72 curr = rcu_dereference(bond->curr_active_slave); 72 curr = rcu_dereference(bond->curr_active_slave);
@@ -92,10 +92,10 @@ static void bond_info_show_master(struct seq_file *seq)
92 } 92 }
93 93
94 if (bond_uses_primary(bond)) { 94 if (bond_uses_primary(bond)) {
95 primary = rcu_dereference(bond->primary_slave);
95 seq_printf(seq, "Primary Slave: %s", 96 seq_printf(seq, "Primary Slave: %s",
96 (bond->primary_slave) ? 97 primary ? primary->dev->name : "None");
97 bond->primary_slave->dev->name : "None"); 98 if (primary) {
98 if (bond->primary_slave) {
99 optval = bond_opt_get_val(BOND_OPT_PRIMARY_RESELECT, 99 optval = bond_opt_get_val(BOND_OPT_PRIMARY_RESELECT,
100 bond->params.primary_reselect); 100 bond->params.primary_reselect);
101 seq_printf(seq, " (primary_reselect %s)", 101 seq_printf(seq, " (primary_reselect %s)",
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 98db8edd9c75..5555517284db 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -425,11 +425,15 @@ static ssize_t bonding_show_primary(struct device *d,
425 struct device_attribute *attr, 425 struct device_attribute *attr,
426 char *buf) 426 char *buf)
427{ 427{
428 int count = 0;
429 struct bonding *bond = to_bond(d); 428 struct bonding *bond = to_bond(d);
429 struct slave *primary;
430 int count = 0;
430 431
431 if (bond->primary_slave) 432 rcu_read_lock();
432 count = sprintf(buf, "%s\n", bond->primary_slave->dev->name); 433 primary = rcu_dereference(bond->primary_slave);
434 if (primary)
435 count = sprintf(buf, "%s\n", primary->dev->name);
436 rcu_read_unlock();
433 437
434 return count; 438 return count;
435} 439}
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index aace510d08d1..c798561a6f01 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -195,7 +195,7 @@ struct bonding {
195 struct net_device *dev; /* first - useful for panic debug */ 195 struct net_device *dev; /* first - useful for panic debug */
196 struct slave __rcu *curr_active_slave; 196 struct slave __rcu *curr_active_slave;
197 struct slave __rcu *current_arp_slave; 197 struct slave __rcu *current_arp_slave;
198 struct slave *primary_slave; 198 struct slave __rcu *primary_slave;
199 bool force_primary; 199 bool force_primary;
200 s32 slave_cnt; /* never change this value outside the attach/detach wrappers */ 200 s32 slave_cnt; /* never change this value outside the attach/detach wrappers */
201 int (*recv_probe)(const struct sk_buff *, struct bonding *, 201 int (*recv_probe)(const struct sk_buff *, struct bonding *,