提交 d90a162a 编写于 作者: M Moni Shoua 提交者: Jeff Garzik

net/bonding: Destroy bonding master when last slave is gone

When bonding enslaves non Ethernet devices it takes pointers to functions
in the module that owns the slaves. In this case it becomes unsafe
to keep the bonding master registered after last slave was unenslaved
because we don't know if the pointers are still valid.  Destroying the bond when slave_cnt is zero
ensures that these functions be used anymore.

Signed-off-by: Moni Shoua <monis at voltaire.com>
Acked-by: NJay Vosburgh <fubar@us.ibm.com>
Signed-off-by: NJeff Garzik <jeff@garzik.org>
上级 1053f62c
...@@ -1257,6 +1257,8 @@ static int bond_compute_features(struct bonding *bond) ...@@ -1257,6 +1257,8 @@ static int bond_compute_features(struct bonding *bond)
static void bond_setup_by_slave(struct net_device *bond_dev, static void bond_setup_by_slave(struct net_device *bond_dev,
struct net_device *slave_dev) struct net_device *slave_dev)
{ {
struct bonding *bond = bond_dev->priv;
bond_dev->neigh_setup = slave_dev->neigh_setup; bond_dev->neigh_setup = slave_dev->neigh_setup;
bond_dev->type = slave_dev->type; bond_dev->type = slave_dev->type;
...@@ -1265,6 +1267,7 @@ static void bond_setup_by_slave(struct net_device *bond_dev, ...@@ -1265,6 +1267,7 @@ static void bond_setup_by_slave(struct net_device *bond_dev,
memcpy(bond_dev->broadcast, slave_dev->broadcast, memcpy(bond_dev->broadcast, slave_dev->broadcast,
slave_dev->addr_len); slave_dev->addr_len);
bond->setup_by_slave = 1;
} }
/* enslave device <slave> to bond device <master> */ /* enslave device <slave> to bond device <master> */
...@@ -1827,6 +1830,35 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) ...@@ -1827,6 +1830,35 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
return 0; /* deletion OK */ return 0; /* deletion OK */
} }
/*
* Destroy a bonding device.
* Must be under rtnl_lock when this function is called.
*/
void bond_destroy(struct bonding *bond)
{
bond_deinit(bond->dev);
bond_destroy_sysfs_entry(bond);
unregister_netdevice(bond->dev);
}
/*
* First release a slave and than destroy the bond if no more slaves iare left.
* Must be under rtnl_lock when this function is called.
*/
int bond_release_and_destroy(struct net_device *bond_dev, struct net_device *slave_dev)
{
struct bonding *bond = bond_dev->priv;
int ret;
ret = bond_release(bond_dev, slave_dev);
if ((ret == 0) && (bond->slave_cnt == 0)) {
printk(KERN_INFO DRV_NAME ": %s: destroying bond %s.\n",
bond_dev->name, bond_dev->name);
bond_destroy(bond);
}
return ret;
}
/* /*
* This function releases all slaves. * This function releases all slaves.
*/ */
...@@ -3325,6 +3357,11 @@ static int bond_slave_netdev_event(unsigned long event, struct net_device *slave ...@@ -3325,6 +3357,11 @@ static int bond_slave_netdev_event(unsigned long event, struct net_device *slave
* ... Or is it this? * ... Or is it this?
*/ */
break; break;
case NETDEV_GOING_DOWN:
dprintk("slave %s is going down\n", slave_dev->name);
if (bond->setup_by_slave)
bond_release_and_destroy(bond_dev, slave_dev);
break;
case NETDEV_CHANGEMTU: case NETDEV_CHANGEMTU:
/* /*
* TODO: Should slaves be allowed to * TODO: Should slaves be allowed to
...@@ -4298,6 +4335,7 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params) ...@@ -4298,6 +4335,7 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params)
bond->primary_slave = NULL; bond->primary_slave = NULL;
bond->dev = bond_dev; bond->dev = bond_dev;
bond->send_grat_arp = 0; bond->send_grat_arp = 0;
bond->setup_by_slave = 0;
INIT_LIST_HEAD(&bond->vlan_list); INIT_LIST_HEAD(&bond->vlan_list);
/* Initialize the device entry points */ /* Initialize the device entry points */
......
...@@ -164,9 +164,7 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t ...@@ -164,9 +164,7 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t
printk(KERN_INFO DRV_NAME printk(KERN_INFO DRV_NAME
": %s is being deleted...\n", ": %s is being deleted...\n",
bond->dev->name); bond->dev->name);
bond_deinit(bond->dev); bond_destroy(bond);
bond_destroy_sysfs_entry(bond);
unregister_netdevice(bond->dev);
rtnl_unlock(); rtnl_unlock();
goto out; goto out;
} }
...@@ -363,7 +361,10 @@ static ssize_t bonding_store_slaves(struct device *d, ...@@ -363,7 +361,10 @@ static ssize_t bonding_store_slaves(struct device *d,
printk(KERN_INFO DRV_NAME ": %s: Removing slave %s\n", printk(KERN_INFO DRV_NAME ": %s: Removing slave %s\n",
bond->dev->name, dev->name); bond->dev->name, dev->name);
rtnl_lock(); rtnl_lock();
res = bond_release(bond->dev, dev); if (bond->setup_by_slave)
res = bond_release_and_destroy(bond->dev, dev);
else
res = bond_release(bond->dev, dev);
rtnl_unlock(); rtnl_unlock();
if (res) { if (res) {
ret = res; ret = res;
......
...@@ -188,6 +188,7 @@ struct bonding { ...@@ -188,6 +188,7 @@ struct bonding {
s8 kill_timers; s8 kill_timers;
s8 do_set_mac_addr; s8 do_set_mac_addr;
s8 send_grat_arp; s8 send_grat_arp;
s8 setup_by_slave;
struct net_device_stats stats; struct net_device_stats stats;
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
struct proc_dir_entry *proc_entry; struct proc_dir_entry *proc_entry;
...@@ -295,6 +296,8 @@ static inline void bond_unset_master_alb_flags(struct bonding *bond) ...@@ -295,6 +296,8 @@ static inline void bond_unset_master_alb_flags(struct bonding *bond)
struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr); struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr);
int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev); int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev);
int bond_create(char *name, struct bond_params *params, struct bonding **newbond); int bond_create(char *name, struct bond_params *params, struct bonding **newbond);
void bond_destroy(struct bonding *bond);
int bond_release_and_destroy(struct net_device *bond_dev, struct net_device *slave_dev);
void bond_deinit(struct net_device *bond_dev); void bond_deinit(struct net_device *bond_dev);
int bond_create_sysfs(void); int bond_create_sysfs(void);
void bond_destroy_sysfs(void); void bond_destroy_sysfs(void);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册