From f9f3664f9ea959d92b7185bb5b4f6c5dcfc995f3 Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Thu, 6 May 2010 00:48:51 -0700 Subject: [PATCH] --- yaml --- r: 194795 b: refs/heads/master c: f6dc31a85cd46a959bdd987adad14c3b645e03c1 h: refs/heads/master i: 194793: c8ad0a5552b99f57ca2b5b35d9cf6c3e3f6d60c5 194791: 8dbceedc87470efe931c6fa8fed34ab5ff371e98 v: v3 --- [refs] | 2 +- trunk/drivers/net/bonding/bond_main.c | 99 ++++++++++++++++++++++++++- 2 files changed, 99 insertions(+), 2 deletions(-) diff --git a/[refs] b/[refs] index d98f946e9183..d1b8548cd75a 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: c06ee961d3c0e51009cbd0e123b61fbb97f37d0b +refs/heads/master: f6dc31a85cd46a959bdd987adad14c3b645e03c1 diff --git a/trunk/drivers/net/bonding/bond_main.c b/trunk/drivers/net/bonding/bond_main.c index 85e813c7762b..5e12462a9d5e 100644 --- a/trunk/drivers/net/bonding/bond_main.c +++ b/trunk/drivers/net/bonding/bond_main.c @@ -59,6 +59,7 @@ #include #include #include +#include #include #include #include @@ -430,7 +431,18 @@ int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, } skb->priority = 1; - dev_queue_xmit(skb); +#ifdef CONFIG_NET_POLL_CONTROLLER + if (unlikely(bond->dev->priv_flags & IFF_IN_NETPOLL)) { + struct netpoll *np = bond->dev->npinfo->netpoll; + slave_dev->npinfo = bond->dev->npinfo; + np->real_dev = np->dev = skb->dev; + slave_dev->priv_flags |= IFF_IN_NETPOLL; + netpoll_send_skb(np, skb); + slave_dev->priv_flags &= ~IFF_IN_NETPOLL; + np->dev = bond->dev; + } else +#endif + dev_queue_xmit(skb); return 0; } @@ -1256,6 +1268,61 @@ static void bond_detach_slave(struct bonding *bond, struct slave *slave) bond->slave_cnt--; } +#ifdef CONFIG_NET_POLL_CONTROLLER +/* + * 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 slave *slave; + int i = 0; + bool ret = true; + + bond_for_each_slave(bond, slave, i) { + if ((slave->dev->priv_flags & IFF_DISABLE_NETPOLL) || + !slave->dev->netdev_ops->ndo_poll_controller) + ret = false; + } + return i != 0 && ret; +} + +static void bond_poll_controller(struct net_device *bond_dev) +{ + struct net_device *dev = bond_dev->npinfo->netpoll->real_dev; + if (dev != bond_dev) + netpoll_poll_dev(dev); +} + +static void bond_netpoll_cleanup(struct net_device *bond_dev) +{ + struct bonding *bond = netdev_priv(bond_dev); + struct slave *slave; + const struct net_device_ops *ops; + int i; + + read_lock(&bond->lock); + bond_dev->npinfo = NULL; + 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); +} + +#else + +static void bond_netpoll_cleanup(struct net_device *bond_dev) +{ +} + +#endif + /*---------------------------------- IOCTL ----------------------------------*/ static int bond_sethwaddr(struct net_device *bond_dev, @@ -1674,6 +1741,18 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) bond_set_carrier(bond); +#ifdef CONFIG_NET_POLL_CONTROLLER + if (slaves_support_netpoll(bond_dev)) { + bond_dev->priv_flags &= ~IFF_DISABLE_NETPOLL; + if (bond_dev->npinfo) + slave_dev->npinfo = bond_dev->npinfo; + } else if (!(bond_dev->priv_flags & IFF_DISABLE_NETPOLL)) { + bond_dev->priv_flags |= IFF_DISABLE_NETPOLL; + pr_info("New slave device %s does not support netpoll\n", + slave_dev->name); + pr_info("Disabling netpoll support for %s\n", bond_dev->name); + } +#endif read_unlock(&bond->lock); res = bond_create_slave_symlinks(bond_dev, slave_dev); @@ -1740,6 +1819,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) return -EINVAL; } + netdev_bonding_change(bond_dev, NETDEV_BONDING_DESLAVE); write_lock_bh(&bond->lock); slave = bond_get_slave_by_dev(bond, slave_dev); @@ -1868,6 +1948,17 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) netdev_set_master(slave_dev, NULL); +#ifdef CONFIG_NET_POLL_CONTROLLER + 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 */ dev_close(slave_dev); @@ -4406,6 +4497,10 @@ static const struct net_device_ops bond_netdev_ops = { .ndo_vlan_rx_register = bond_vlan_rx_register, .ndo_vlan_rx_add_vid = bond_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = bond_vlan_rx_kill_vid, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_netpoll_cleanup = bond_netpoll_cleanup, + .ndo_poll_controller = bond_poll_controller, +#endif }; static void bond_destructor(struct net_device *bond_dev) @@ -4499,6 +4594,8 @@ static void bond_uninit(struct net_device *bond_dev) { struct bonding *bond = netdev_priv(bond_dev); + bond_netpoll_cleanup(bond_dev); + /* Release the bonded slaves */ bond_release_all(bond_dev);