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: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2020-02-16 19:32:11 -08:00
commit c230978fb7
4 changed files with 60 additions and 10 deletions

View file

@ -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,
struct rtnl_link_stats64 *stats)
{
@ -3533,11 +3574,17 @@ static void bond_get_stats(struct net_device *bond_dev,
struct rtnl_link_stats64 temp;
struct list_head *iter;
struct slave *slave;
int nest_level = 0;
spin_lock(&bond->stats_lock);
memcpy(stats, &bond->bond_stats, sizeof(*stats));
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) {
const struct rtnl_link_stats64 *new =
dev_get_stats(slave->dev, &temp);
@ -3547,10 +3594,10 @@ static void bond_get_stats(struct net_device *bond_dev,
/* save off the slave stats for the next run */
memcpy(&slave->slave_stats, new, sizeof(*new));
}
rcu_read_unlock();
memcpy(&bond->bond_stats, stats, sizeof(*stats));
spin_unlock(&bond->stats_lock);
rcu_read_unlock();
}
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 SIOCBONDRELEASE:
res = bond_release(bond_dev, slave_dev);
if (!res)
netdev_update_lockdep_key(slave_dev);
break;
case BOND_SETHWADDR_OLD:
case SIOCBONDSETHWADDR:

View file

@ -1398,6 +1398,8 @@ static int bond_option_slaves_set(struct bonding *bond,
case '-':
slave_dbg(bond->dev, dev, "Releasing interface\n");
ret = bond_release(bond->dev, dev);
if (!ret)
netdev_update_lockdep_key(dev);
break;
default:

View file

@ -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_DROP 1 /* packet dropped */
#define MAX_NEST_DEV 8
/*
* Transmit return codes: transmit return codes originate from three different
* namespaces:
@ -4389,11 +4391,8 @@ void *netdev_lower_get_next(struct net_device *dev,
ldev; \
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 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 (*fn)(struct net_device *lower_dev,
void *data),

View file

@ -146,7 +146,6 @@
#include "net-sysfs.h"
#define MAX_GRO_SKBS 8
#define MAX_NEST_DEV 8
/* This should be increased if a protocol with a bigger head is added. */
#define GRO_MAX_HEAD (MAX_HEADER + 128)
@ -7207,8 +7206,8 @@ static int __netdev_walk_all_lower_dev(struct net_device *dev,
return 0;
}
static struct net_device *netdev_next_lower_dev_rcu(struct net_device *dev,
struct list_head **iter)
struct net_device *netdev_next_lower_dev_rcu(struct net_device *dev,
struct list_head **iter)
{
struct netdev_adjacent *lower;
@ -7220,6 +7219,7 @@ static struct net_device *netdev_next_lower_dev_rcu(struct net_device *dev,
return lower->dev;
}
EXPORT_SYMBOL(netdev_next_lower_dev_rcu);
static u8 __netdev_upper_depth(struct net_device *dev)
{