Commit c230978f authored by David S. Miller's avatar David S. Miller

Merge branch 'bonding-fix-bonding-interface-bugs'

Taehee Yoo says:

====================
bonding: fix bonding interface bugs

This patchset fixes lockdep problem in bonding interface

1. The first patch is to add missing netdev_update_lockdep_key().
After bond_release(), netdev_update_lockdep_key() should be called.
But both ioctl path and attribute path don't call
netdev_update_lockdep_key().
This patch adds missing netdev_update_lockdep_key().

2. The second patch is to export netdev_next_lower_dev_rcu symbol.
netdev_next_lower_dev_rcu() is useful to implement the function,
which is to walk their all lower interfaces.
This patch is actually a preparing patch for the third patch.

3. The last patch is to fix lockdep waring in bond_get_stats().
The stats_lock uses a dynamic lockdep key.
So, after "nomaster" operation, updating the dynamic lockdep key
routine is needed. but it doesn't
So, lockdep warning occurs.

Change log:
v1 -> v2:
 - Update headline from "fix bonding interface bugs"
   to "bonding: fix bonding interface bugs"
 - Drop a patch("bonding: do not collect slave's stats")
 - Add new patches
   - ("net: export netdev_next_lower_dev_rcu()")
   - ("bonding: fix lockdep warning in bond_get_stats()")
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents c4c10784 b3e80d44
...@@ -3526,6 +3526,47 @@ static void bond_fold_stats(struct rtnl_link_stats64 *_res, ...@@ -3526,6 +3526,47 @@ static void bond_fold_stats(struct rtnl_link_stats64 *_res,
} }
} }
#ifdef CONFIG_LOCKDEP
static int bond_get_lowest_level_rcu(struct net_device *dev)
{
struct net_device *ldev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];
struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1];
int cur = 0, max = 0;
now = dev;
iter = &dev->adj_list.lower;
while (1) {
next = NULL;
while (1) {
ldev = netdev_next_lower_dev_rcu(now, &iter);
if (!ldev)
break;
next = ldev;
niter = &ldev->adj_list.lower;
dev_stack[cur] = now;
iter_stack[cur++] = iter;
if (max <= cur)
max = cur;
break;
}
if (!next) {
if (!cur)
return max;
next = dev_stack[--cur];
niter = iter_stack[cur];
}
now = next;
iter = niter;
}
return max;
}
#endif
static void bond_get_stats(struct net_device *bond_dev, static void bond_get_stats(struct net_device *bond_dev,
struct rtnl_link_stats64 *stats) struct rtnl_link_stats64 *stats)
{ {
...@@ -3533,11 +3574,17 @@ static void bond_get_stats(struct net_device *bond_dev, ...@@ -3533,11 +3574,17 @@ static void bond_get_stats(struct net_device *bond_dev,
struct rtnl_link_stats64 temp; struct rtnl_link_stats64 temp;
struct list_head *iter; struct list_head *iter;
struct slave *slave; struct slave *slave;
int nest_level = 0;
spin_lock(&bond->stats_lock);
memcpy(stats, &bond->bond_stats, sizeof(*stats));
rcu_read_lock(); rcu_read_lock();
#ifdef CONFIG_LOCKDEP
nest_level = bond_get_lowest_level_rcu(bond_dev);
#endif
spin_lock_nested(&bond->stats_lock, nest_level);
memcpy(stats, &bond->bond_stats, sizeof(*stats));
bond_for_each_slave_rcu(bond, slave, iter) { bond_for_each_slave_rcu(bond, slave, iter) {
const struct rtnl_link_stats64 *new = const struct rtnl_link_stats64 *new =
dev_get_stats(slave->dev, &temp); dev_get_stats(slave->dev, &temp);
...@@ -3547,10 +3594,10 @@ static void bond_get_stats(struct net_device *bond_dev, ...@@ -3547,10 +3594,10 @@ static void bond_get_stats(struct net_device *bond_dev,
/* save off the slave stats for the next run */ /* save off the slave stats for the next run */
memcpy(&slave->slave_stats, new, sizeof(*new)); memcpy(&slave->slave_stats, new, sizeof(*new));
} }
rcu_read_unlock();
memcpy(&bond->bond_stats, stats, sizeof(*stats)); memcpy(&bond->bond_stats, stats, sizeof(*stats));
spin_unlock(&bond->stats_lock); spin_unlock(&bond->stats_lock);
rcu_read_unlock();
} }
static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd) static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd)
...@@ -3640,6 +3687,8 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd ...@@ -3640,6 +3687,8 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd
case BOND_RELEASE_OLD: case BOND_RELEASE_OLD:
case SIOCBONDRELEASE: case SIOCBONDRELEASE:
res = bond_release(bond_dev, slave_dev); res = bond_release(bond_dev, slave_dev);
if (!res)
netdev_update_lockdep_key(slave_dev);
break; break;
case BOND_SETHWADDR_OLD: case BOND_SETHWADDR_OLD:
case SIOCBONDSETHWADDR: case SIOCBONDSETHWADDR:
......
...@@ -1398,6 +1398,8 @@ static int bond_option_slaves_set(struct bonding *bond, ...@@ -1398,6 +1398,8 @@ static int bond_option_slaves_set(struct bonding *bond,
case '-': case '-':
slave_dbg(bond->dev, dev, "Releasing interface\n"); slave_dbg(bond->dev, dev, "Releasing interface\n");
ret = bond_release(bond->dev, dev); ret = bond_release(bond->dev, dev);
if (!ret)
netdev_update_lockdep_key(dev);
break; break;
default: default:
......
...@@ -72,6 +72,8 @@ void netdev_set_default_ethtool_ops(struct net_device *dev, ...@@ -72,6 +72,8 @@ void netdev_set_default_ethtool_ops(struct net_device *dev,
#define NET_RX_SUCCESS 0 /* keep 'em coming, baby */ #define NET_RX_SUCCESS 0 /* keep 'em coming, baby */
#define NET_RX_DROP 1 /* packet dropped */ #define NET_RX_DROP 1 /* packet dropped */
#define MAX_NEST_DEV 8
/* /*
* Transmit return codes: transmit return codes originate from three different * Transmit return codes: transmit return codes originate from three different
* namespaces: * namespaces:
...@@ -4389,11 +4391,8 @@ void *netdev_lower_get_next(struct net_device *dev, ...@@ -4389,11 +4391,8 @@ void *netdev_lower_get_next(struct net_device *dev,
ldev; \ ldev; \
ldev = netdev_lower_get_next(dev, &(iter))) ldev = netdev_lower_get_next(dev, &(iter)))
struct net_device *netdev_all_lower_get_next(struct net_device *dev, struct net_device *netdev_next_lower_dev_rcu(struct net_device *dev,
struct list_head **iter); struct list_head **iter);
struct net_device *netdev_all_lower_get_next_rcu(struct net_device *dev,
struct list_head **iter);
int netdev_walk_all_lower_dev(struct net_device *dev, int netdev_walk_all_lower_dev(struct net_device *dev,
int (*fn)(struct net_device *lower_dev, int (*fn)(struct net_device *lower_dev,
void *data), void *data),
......
...@@ -146,7 +146,6 @@ ...@@ -146,7 +146,6 @@
#include "net-sysfs.h" #include "net-sysfs.h"
#define MAX_GRO_SKBS 8 #define MAX_GRO_SKBS 8
#define MAX_NEST_DEV 8
/* This should be increased if a protocol with a bigger head is added. */ /* This should be increased if a protocol with a bigger head is added. */
#define GRO_MAX_HEAD (MAX_HEADER + 128) #define GRO_MAX_HEAD (MAX_HEADER + 128)
...@@ -7207,8 +7206,8 @@ static int __netdev_walk_all_lower_dev(struct net_device *dev, ...@@ -7207,8 +7206,8 @@ static int __netdev_walk_all_lower_dev(struct net_device *dev,
return 0; return 0;
} }
static struct net_device *netdev_next_lower_dev_rcu(struct net_device *dev, struct net_device *netdev_next_lower_dev_rcu(struct net_device *dev,
struct list_head **iter) struct list_head **iter)
{ {
struct netdev_adjacent *lower; struct netdev_adjacent *lower;
...@@ -7220,6 +7219,7 @@ static struct net_device *netdev_next_lower_dev_rcu(struct net_device *dev, ...@@ -7220,6 +7219,7 @@ static struct net_device *netdev_next_lower_dev_rcu(struct net_device *dev,
return lower->dev; return lower->dev;
} }
EXPORT_SYMBOL(netdev_next_lower_dev_rcu);
static u8 __netdev_upper_depth(struct net_device *dev) static u8 __netdev_upper_depth(struct net_device *dev)
{ {
......
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