bonding: sync netpoll code with bridge
V4: rebase to net-next-2.6 V3: remove an useless #ifdef. This patch unifies the netpoll code in bonding with netpoll code in bridge, thanks to Herbert that code is much cleaner now. Signed-off-by: WANG Cong <amwang@redhat.com> Acked-by: Neil Horman <nhorman@tuxdriver.com> Cc: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
70919e23ac
commit
8a8efa22f5
@ -59,7 +59,6 @@
|
|||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/netdevice.h>
|
#include <linux/netdevice.h>
|
||||||
#include <linux/netpoll.h>
|
|
||||||
#include <linux/inetdevice.h>
|
#include <linux/inetdevice.h>
|
||||||
#include <linux/igmp.h>
|
#include <linux/igmp.h>
|
||||||
#include <linux/etherdevice.h>
|
#include <linux/etherdevice.h>
|
||||||
@ -424,15 +423,11 @@ int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb,
|
|||||||
{
|
{
|
||||||
skb->dev = slave_dev;
|
skb->dev = slave_dev;
|
||||||
skb->priority = 1;
|
skb->priority = 1;
|
||||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
if (unlikely(netpoll_tx_running(slave_dev))) {
|
||||||
if (unlikely(bond->dev->priv_flags & IFF_IN_NETPOLL)) {
|
|
||||||
struct netpoll *np = bond->dev->npinfo->netpoll;
|
|
||||||
slave_dev->npinfo = bond->dev->npinfo;
|
|
||||||
slave_dev->priv_flags |= IFF_IN_NETPOLL;
|
slave_dev->priv_flags |= IFF_IN_NETPOLL;
|
||||||
netpoll_send_skb_on_dev(np, skb, slave_dev);
|
bond_netpoll_send_skb(bond_get_slave_by_dev(bond, slave_dev), skb);
|
||||||
slave_dev->priv_flags &= ~IFF_IN_NETPOLL;
|
slave_dev->priv_flags &= ~IFF_IN_NETPOLL;
|
||||||
} else
|
} else
|
||||||
#endif
|
|
||||||
dev_queue_xmit(skb);
|
dev_queue_xmit(skb);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -1288,63 +1283,113 @@ static void bond_detach_slave(struct bonding *bond, struct slave *slave)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||||
/*
|
static inline int slave_enable_netpoll(struct slave *slave)
|
||||||
* You must hold read lock on bond->lock before calling this.
|
|
||||||
*/
|
|
||||||
static bool slaves_support_netpoll(struct net_device *bond_dev)
|
|
||||||
{
|
{
|
||||||
struct bonding *bond = netdev_priv(bond_dev);
|
struct netpoll *np;
|
||||||
struct slave *slave;
|
int err = 0;
|
||||||
int i = 0;
|
|
||||||
bool ret = true;
|
|
||||||
|
|
||||||
bond_for_each_slave(bond, slave, i) {
|
np = kzalloc(sizeof(*np), GFP_KERNEL);
|
||||||
if ((slave->dev->priv_flags & IFF_DISABLE_NETPOLL) ||
|
err = -ENOMEM;
|
||||||
!slave->dev->netdev_ops->ndo_poll_controller)
|
if (!np)
|
||||||
ret = false;
|
goto out;
|
||||||
|
|
||||||
|
np->dev = slave->dev;
|
||||||
|
err = __netpoll_setup(np);
|
||||||
|
if (err) {
|
||||||
|
kfree(np);
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
return i != 0 && ret;
|
slave->np = np;
|
||||||
|
out:
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
static inline void slave_disable_netpoll(struct slave *slave)
|
||||||
|
{
|
||||||
|
struct netpoll *np = slave->np;
|
||||||
|
|
||||||
|
if (!np)
|
||||||
|
return;
|
||||||
|
|
||||||
|
slave->np = NULL;
|
||||||
|
synchronize_rcu_bh();
|
||||||
|
__netpoll_cleanup(np);
|
||||||
|
kfree(np);
|
||||||
|
}
|
||||||
|
static inline bool slave_dev_support_netpoll(struct net_device *slave_dev)
|
||||||
|
{
|
||||||
|
if (slave_dev->priv_flags & IFF_DISABLE_NETPOLL)
|
||||||
|
return false;
|
||||||
|
if (!slave_dev->netdev_ops->ndo_poll_controller)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bond_poll_controller(struct net_device *bond_dev)
|
static void bond_poll_controller(struct net_device *bond_dev)
|
||||||
{
|
{
|
||||||
struct bonding *bond = netdev_priv(bond_dev);
|
}
|
||||||
|
|
||||||
|
static void __bond_netpoll_cleanup(struct bonding *bond)
|
||||||
|
{
|
||||||
struct slave *slave;
|
struct slave *slave;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
bond_for_each_slave(bond, slave, i) {
|
bond_for_each_slave(bond, slave, i)
|
||||||
if (slave->dev && IS_UP(slave->dev))
|
if (IS_UP(slave->dev))
|
||||||
netpoll_poll_dev(slave->dev);
|
slave_disable_netpoll(slave);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bond_netpoll_cleanup(struct net_device *bond_dev)
|
static void bond_netpoll_cleanup(struct net_device *bond_dev)
|
||||||
{
|
{
|
||||||
struct bonding *bond = netdev_priv(bond_dev);
|
struct bonding *bond = netdev_priv(bond_dev);
|
||||||
struct slave *slave;
|
|
||||||
const struct net_device_ops *ops;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
read_lock(&bond->lock);
|
read_lock(&bond->lock);
|
||||||
bond_dev->npinfo = NULL;
|
__bond_netpoll_cleanup(bond);
|
||||||
bond_for_each_slave(bond, slave, i) {
|
|
||||||
if (slave->dev) {
|
|
||||||
ops = slave->dev->netdev_ops;
|
|
||||||
if (ops->ndo_netpoll_cleanup)
|
|
||||||
ops->ndo_netpoll_cleanup(slave->dev);
|
|
||||||
else
|
|
||||||
slave->dev->npinfo = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
read_unlock(&bond->lock);
|
read_unlock(&bond->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
static int bond_netpoll_setup(struct net_device *dev, struct netpoll_info *ni)
|
||||||
|
{
|
||||||
|
struct bonding *bond = netdev_priv(dev);
|
||||||
|
struct slave *slave;
|
||||||
|
int i, err = 0;
|
||||||
|
|
||||||
|
read_lock(&bond->lock);
|
||||||
|
bond_for_each_slave(bond, slave, i) {
|
||||||
|
if (!IS_UP(slave->dev))
|
||||||
|
continue;
|
||||||
|
err = slave_enable_netpoll(slave);
|
||||||
|
if (err) {
|
||||||
|
__bond_netpoll_cleanup(bond);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
read_unlock(&bond->lock);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct netpoll_info *bond_netpoll_info(struct bonding *bond)
|
||||||
|
{
|
||||||
|
return bond->dev->npinfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
static inline int slave_enable_netpoll(struct slave *slave)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static inline void slave_disable_netpoll(struct slave *slave)
|
||||||
|
{
|
||||||
|
}
|
||||||
static void bond_netpoll_cleanup(struct net_device *bond_dev)
|
static void bond_netpoll_cleanup(struct net_device *bond_dev)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
static int bond_netpoll_setup(struct net_device *dev, struct netpoll_info *ni)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static struct netpoll_info *bond_netpoll_info(struct bonding *bond)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*---------------------------------- IOCTL ----------------------------------*/
|
/*---------------------------------- IOCTL ----------------------------------*/
|
||||||
@ -1782,17 +1827,19 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
|
|||||||
bond_set_carrier(bond);
|
bond_set_carrier(bond);
|
||||||
|
|
||||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||||
if (slaves_support_netpoll(bond_dev)) {
|
slave_dev->npinfo = bond_netpoll_info(bond);
|
||||||
bond_dev->priv_flags &= ~IFF_DISABLE_NETPOLL;
|
if (slave_dev->npinfo) {
|
||||||
if (bond_dev->npinfo)
|
if (slave_enable_netpoll(new_slave)) {
|
||||||
slave_dev->npinfo = bond_dev->npinfo;
|
read_unlock(&bond->lock);
|
||||||
} else if (!(bond_dev->priv_flags & IFF_DISABLE_NETPOLL)) {
|
pr_info("Error, %s: master_dev is using netpoll, "
|
||||||
bond_dev->priv_flags |= IFF_DISABLE_NETPOLL;
|
"but new slave device does not support netpoll.\n",
|
||||||
pr_info("New slave device %s does not support netpoll\n",
|
bond_dev->name);
|
||||||
slave_dev->name);
|
res = -EBUSY;
|
||||||
pr_info("Disabling netpoll support for %s\n", bond_dev->name);
|
goto err_close;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
read_unlock(&bond->lock);
|
read_unlock(&bond->lock);
|
||||||
|
|
||||||
res = bond_create_slave_symlinks(bond_dev, slave_dev);
|
res = bond_create_slave_symlinks(bond_dev, slave_dev);
|
||||||
@ -1994,17 +2041,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
|
|||||||
|
|
||||||
netdev_set_bond_master(slave_dev, NULL);
|
netdev_set_bond_master(slave_dev, NULL);
|
||||||
|
|
||||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
slave_disable_netpoll(slave);
|
||||||
read_lock_bh(&bond->lock);
|
|
||||||
|
|
||||||
if (slaves_support_netpoll(bond_dev))
|
|
||||||
bond_dev->priv_flags &= ~IFF_DISABLE_NETPOLL;
|
|
||||||
read_unlock_bh(&bond->lock);
|
|
||||||
if (slave_dev->netdev_ops->ndo_netpoll_cleanup)
|
|
||||||
slave_dev->netdev_ops->ndo_netpoll_cleanup(slave_dev);
|
|
||||||
else
|
|
||||||
slave_dev->npinfo = NULL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* close slave before restoring its mac address */
|
/* close slave before restoring its mac address */
|
||||||
dev_close(slave_dev);
|
dev_close(slave_dev);
|
||||||
@ -2039,6 +2076,7 @@ static int bond_release_and_destroy(struct net_device *bond_dev,
|
|||||||
|
|
||||||
ret = bond_release(bond_dev, slave_dev);
|
ret = bond_release(bond_dev, slave_dev);
|
||||||
if ((ret == 0) && (bond->slave_cnt == 0)) {
|
if ((ret == 0) && (bond->slave_cnt == 0)) {
|
||||||
|
bond_dev->priv_flags |= IFF_DISABLE_NETPOLL;
|
||||||
pr_info("%s: destroying bond %s.\n",
|
pr_info("%s: destroying bond %s.\n",
|
||||||
bond_dev->name, bond_dev->name);
|
bond_dev->name, bond_dev->name);
|
||||||
unregister_netdevice(bond_dev);
|
unregister_netdevice(bond_dev);
|
||||||
@ -2116,6 +2154,8 @@ static int bond_release_all(struct net_device *bond_dev)
|
|||||||
|
|
||||||
netdev_set_bond_master(slave_dev, NULL);
|
netdev_set_bond_master(slave_dev, NULL);
|
||||||
|
|
||||||
|
slave_disable_netpoll(slave);
|
||||||
|
|
||||||
/* close slave before restoring its mac address */
|
/* close slave before restoring its mac address */
|
||||||
dev_close(slave_dev);
|
dev_close(slave_dev);
|
||||||
|
|
||||||
@ -4654,6 +4694,7 @@ static const struct net_device_ops bond_netdev_ops = {
|
|||||||
.ndo_vlan_rx_add_vid = bond_vlan_rx_add_vid,
|
.ndo_vlan_rx_add_vid = bond_vlan_rx_add_vid,
|
||||||
.ndo_vlan_rx_kill_vid = bond_vlan_rx_kill_vid,
|
.ndo_vlan_rx_kill_vid = bond_vlan_rx_kill_vid,
|
||||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||||
|
.ndo_netpoll_setup = bond_netpoll_setup,
|
||||||
.ndo_netpoll_cleanup = bond_netpoll_cleanup,
|
.ndo_netpoll_cleanup = bond_netpoll_cleanup,
|
||||||
.ndo_poll_controller = bond_poll_controller,
|
.ndo_poll_controller = bond_poll_controller,
|
||||||
#endif
|
#endif
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include <linux/if_bonding.h>
|
#include <linux/if_bonding.h>
|
||||||
#include <linux/cpumask.h>
|
#include <linux/cpumask.h>
|
||||||
#include <linux/in6.h>
|
#include <linux/in6.h>
|
||||||
|
#include <linux/netpoll.h>
|
||||||
#include "bond_3ad.h"
|
#include "bond_3ad.h"
|
||||||
#include "bond_alb.h"
|
#include "bond_alb.h"
|
||||||
|
|
||||||
@ -198,6 +199,9 @@ struct slave {
|
|||||||
u16 queue_id;
|
u16 queue_id;
|
||||||
struct ad_slave_info ad_info; /* HUGE - better to dynamically alloc */
|
struct ad_slave_info ad_info; /* HUGE - better to dynamically alloc */
|
||||||
struct tlb_slave_info tlb_info;
|
struct tlb_slave_info tlb_info;
|
||||||
|
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||||
|
struct netpoll *np;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -323,6 +327,22 @@ static inline unsigned long slave_last_rx(struct bonding *bond,
|
|||||||
return slave->dev->last_rx;
|
return slave->dev->last_rx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||||
|
static inline void bond_netpoll_send_skb(const struct slave *slave,
|
||||||
|
struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
struct netpoll *np = slave->np;
|
||||||
|
|
||||||
|
if (np)
|
||||||
|
netpoll_send_skb(np, skb);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static inline void bond_netpoll_send_skb(const struct slave *slave,
|
||||||
|
struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static inline void bond_set_slave_inactive_flags(struct slave *slave)
|
static inline void bond_set_slave_inactive_flags(struct slave *slave)
|
||||||
{
|
{
|
||||||
struct bonding *bond = netdev_priv(slave->dev->master);
|
struct bonding *bond = netdev_priv(slave->dev->master);
|
||||||
|
Loading…
Reference in New Issue
Block a user