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

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
Loading
Loading
Loading
Loading
+52 −3
Original line number Diff line number Diff line
@@ -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:
+2 −0
Original line number Diff line number Diff line
@@ -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:
+3 −4
Original line number Diff line number Diff line
@@ -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 list_head **iter);
struct net_device *netdev_all_lower_get_next_rcu(struct net_device *dev,
struct net_device *netdev_next_lower_dev_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),
+3 −3
Original line number Diff line number Diff line
@@ -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,7 +7206,7 @@ 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 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)
{