Commit 8a8efa22 authored by Amerigo Wang's avatar Amerigo Wang Committed by David S. Miller

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: default avatarWANG Cong <amwang@redhat.com>
Acked-by: default avatarNeil Horman <nhorman@tuxdriver.com>
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 70919e23
...@@ -59,7 +59,6 @@ ...@@ -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, ...@@ -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) ...@@ -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);
read_lock(&bond->lock);
__bond_netpoll_cleanup(bond);
read_unlock(&bond->lock);
}
static int bond_netpoll_setup(struct net_device *dev, struct netpoll_info *ni)
{
struct bonding *bond = netdev_priv(dev);
struct slave *slave; struct slave *slave;
const struct net_device_ops *ops; int i, err = 0;
int i;
read_lock(&bond->lock); read_lock(&bond->lock);
bond_dev->npinfo = NULL;
bond_for_each_slave(bond, slave, i) { bond_for_each_slave(bond, slave, i) {
if (slave->dev) { if (!IS_UP(slave->dev))
ops = slave->dev->netdev_ops; continue;
if (ops->ndo_netpoll_cleanup) err = slave_enable_netpoll(slave);
ops->ndo_netpoll_cleanup(slave->dev); if (err) {
else __bond_netpoll_cleanup(bond);
slave->dev->npinfo = NULL; break;
} }
} }
read_unlock(&bond->lock); read_unlock(&bond->lock);
return err;
} }
#else 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) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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 = { ...@@ -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 @@ ...@@ -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 { ...@@ -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, ...@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment