All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RFC net-next 0/21] bonding: use neighbours instead of own lists
@ 2013-09-02 21:39 Veaceslav Falico
  2013-09-02 21:39 ` [PATCH RFC net-next 01/21] net: add neighbour_dev_list to save only neighbours Veaceslav Falico
                   ` (20 more replies)
  0 siblings, 21 replies; 27+ messages in thread
From: Veaceslav Falico @ 2013-09-02 21:39 UTC (permalink / raw)
  To: netdev
  Cc: Jay Vosburgh, Andy Gospodarek, David S. Miller, Patrick McHardy,
	Eric Dumazet, Jiri Pirko, Alexander Duyck, Veaceslav Falico

(on top of "net: correctly interlink lower/upper devices" - the fix is
vital)

Hi,

I'm sending it as early as possible, because it's quite a big patchset and
some of the approaches I've chosen are not really easy/straightforward. It
will require a lot of work, obviously, before I can send it as a proper
patchset ready to be considered for inclusion, even though it works now.

I'm sending it to gather any feedback possible.

This patchset introduces all the needed infrastructure, on top of current
adjacent lists, to be able to remove bond's slave_list/slave->list. The
overhead in memory/CPU is minimal, and after the patchset bonding can rely
on its slave-related functions, given the proper locking.

It also automatically creates slave/upper and master symlinks in dev's
sysfs directory.

The current version works ok, as first tests have shown. I'm testing it
further.

Here is a short description of each:

net: add neighbour_dev_list to save only neighbours
	Adding two new lists, each for the device neighbours only - it's
	done for speed when going through slaves.
net: add RCU variant to search for netdev_adjacent link
net: add netdev_adjacent->private and allow to use it
	These two patches add infrastructure for the netdev_adjacent new
	member - private, which contains master's private info for the
	slave - in case of bonding it's struct slave *.
net: expose the master link to sysfs, and remove it from bond
	Create sysfs link for master devices.
vlan: link the upper neighbour only after registering
	vlan linked itself before registering, which ends badly if we'll
	have a user before it registers, and is not ready for sysfs
	operations.
net: create sysfs symlinks for neighbour devices
	Create sysfs links to slave/upper devices.
bonding: add bond_has_slaves() and use it
	It'll be easier for modification in the future.
bonding: convert bond_has_slaves() to use the neighbour list
	First usage of the neighbour_dev_list.lower - bonding's lower
	devices are *always* slaves, so we can verify if it's empty or not.
bonding: populate neighbour's private on enslave
	Attach struct slave * to each lower link.
bonding: modify bond_get_slave_by_dev() to use neighbours
	We can search already for ->private here.
bonding: remove bond_for_each_slave_reverse()
	It's useless and hard to read sometimes.
net: add for_each iterators through neighbour lower link's private
bonding: make bond_for_each_slave() use lower neighbour's private
	These two patches convert bond_for_each_slave() to use neighbours
	lower list.
net: add netdev_for_each_lower_neigh_private_continue()
bonding: use neighbour list for bond_for_each_slave_continue()
	These two - bond_for_each_slave_continue().
net: add a possibility to get private from netdev_adjacent->list
bonding: convert first/last slave logic to use neighbours
	Convert those little helpers without huge functions - just use the
	list's next/prev.
net: add a function to get the next/prev private
bonding: use neighbours for bond_next/prev_slave()
	Same.
bonding: use bond_for_each_slave() in bond_uninit()
	We can safely use it - we're using the ->next field.
bonding: remove slave lists
	Finally.

I'll update if anything comes up.

Thanks in advance.

CC: Jay Vosburgh <fubar@us.ibm.com>
CC: Andy Gospodarek <andy@greyhouse.net>
CC: "David S. Miller" <davem@davemloft.net>
CC: Patrick McHardy <kaber@trash.net>
CC: Eric Dumazet <edumazet@google.com>
CC: Jiri Pirko <jiri@resnulli.us>
CC: Alexander Duyck <alexander.h.duyck@intel.com>
Signed-off-by: Veaceslav Falico <vfalico@redhat.com>

---
 drivers/net/bonding/bond_3ad.c    |  13 +-
 drivers/net/bonding/bond_alb.c    |  42 ++--
 drivers/net/bonding/bond_main.c   | 204 +++++++++-------
 drivers/net/bonding/bond_procfs.c |   5 +-
 drivers/net/bonding/bond_sysfs.c  |  62 ++---
 drivers/net/bonding/bonding.h     |  65 ++---
 include/linux/netdevice.h         |  67 +++++-
 net/8021q/vlan.c                  |  14 +-
 net/core/dev.c                    | 483 +++++++++++++++++++++++++++++++++-----
 9 files changed, 686 insertions(+), 269 deletions(-)

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH RFC net-next 01/21] net: add neighbour_dev_list to save only neighbours
  2013-09-02 21:39 [PATCH RFC net-next 0/21] bonding: use neighbours instead of own lists Veaceslav Falico
@ 2013-09-02 21:39 ` Veaceslav Falico
  2013-09-03  8:29   ` Jiri Pirko
  2013-09-02 21:39 ` [PATCH RFC net-next 02/21] net: add RCU variant to search for netdev_adjacent link Veaceslav Falico
                   ` (19 subsequent siblings)
  20 siblings, 1 reply; 27+ messages in thread
From: Veaceslav Falico @ 2013-09-02 21:39 UTC (permalink / raw)
  To: netdev
  Cc: Veaceslav Falico, David S. Miller, Eric Dumazet, Jiri Pirko,
	Alexander Duyck, Cong Wang

Currently, we distinguish neighbours (first-level linked devices) from
non-neighbours by the neighbour bool in the netdev_adjacent. This could be
quite time-consuming in case we would like to traverse *only* through
neighbours - cause we'd have to traverse through all devices and check for
this flag, and in a (quite common) scenario where we have lots of vlans on
top of bridge, which is on top of a bond - the bonding would have to go
through all those vlans to get its upper neighbour linked devices.

This situation is really unpleasant, cause there are already a lot of cases
when a device with slaves needs to go through them in hot path.

To fix this, introduce a new upper/lower device lists structure -
neighbour_dev_list, which contains only the neighbours. It works always in
pair with the all_device_list structure (renamed from upper/lower_dev_list),
i.e. both of them contain the same links, only that all_dev_list contains
also non-neighbour device links. It's really a small change visible,
currently, only for __netdev_adjacent_dev_insert/remove(), and doesn't
change the main linked logic at all.

Also, add some comments a fix a name collision in
netdev_for_each_upper_dev_rcu().

CC: "David S. Miller" <davem@davemloft.net>
CC: Eric Dumazet <edumazet@google.com>
CC: Jiri Pirko <jiri@resnulli.us>
CC: Alexander Duyck <alexander.h.duyck@intel.com>
CC: Cong Wang <amwang@redhat.com>
Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
---
 include/linux/netdevice.h |  24 ++++---
 net/core/dev.c            | 157 ++++++++++++++++++++++++++++++++++------------
 2 files changed, 134 insertions(+), 47 deletions(-)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 3ad49b8..df50548 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1124,8 +1124,18 @@ struct net_device {
 	struct list_head	dev_list;
 	struct list_head	napi_list;
 	struct list_head	unreg_list;
-	struct list_head	upper_dev_list; /* List of upper devices */
-	struct list_head	lower_dev_list;
+
+	/* directly linked devices, like slaves for bonding */
+	struct {
+		struct list_head upper;
+		struct list_head lower;
+	} neighbour_dev_list ;
+
+	/* all linked devices, *including* neighbours */
+	struct {
+		struct list_head upper;
+		struct list_head lower;
+	} all_dev_list ;
 
 
 	/* currently active device features */
@@ -2772,11 +2782,11 @@ extern struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev,
 							struct list_head **iter);
 
 /* iterate through upper list, must be called under RCU read lock */
-#define netdev_for_each_upper_dev_rcu(dev, upper, iter) \
-	for (iter = &(dev)->upper_dev_list, \
-	     upper = netdev_upper_get_next_dev_rcu(dev, &(iter)); \
-	     upper; \
-	     upper = netdev_upper_get_next_dev_rcu(dev, &(iter)))
+#define netdev_for_each_upper_dev_rcu(dev, updev, iter) \
+	for (iter = &(dev)->all_dev_list.upper, \
+	     updev= netdev_upper_get_next_dev_rcu(dev, &(iter)); \
+	     updev; \
+	     updev = netdev_upper_get_next_dev_rcu(dev, &(iter)))
 
 extern struct net_device *netdev_master_upper_dev_get(struct net_device *dev);
 extern struct net_device *netdev_master_upper_dev_get_rcu(struct net_device *dev);
diff --git a/net/core/dev.c b/net/core/dev.c
index 743620e..9e4eb40 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4373,9 +4373,6 @@ struct netdev_adjacent {
 	/* upper master flag, there can only be one master device per list */
 	bool master;
 
-	/* indicates that this dev is our first-level lower/upper device */
-	bool neighbour;
-
 	/* counter for the number of times this device was added to us */
 	u16 ref_nr;
 
@@ -4385,12 +4382,17 @@ struct netdev_adjacent {
 
 static struct netdev_adjacent *__netdev_find_adj(struct net_device *dev,
 						 struct net_device *adj_dev,
-						 bool upper)
+						 bool upper, bool neighbour)
 {
 	struct netdev_adjacent *adj;
 	struct list_head *dev_list;
 
-	dev_list = upper ? &dev->upper_dev_list : &dev->lower_dev_list;
+	if (neighbour)
+		dev_list = upper ? &dev->neighbour_dev_list.upper :
+				   &dev->neighbour_dev_list.lower;
+	else
+		dev_list = upper ? &dev->all_dev_list.upper :
+				   &dev->all_dev_list.lower;
 
 	list_for_each_entry(adj, dev_list, list) {
 		if (adj->dev == adj_dev)
@@ -4402,13 +4404,25 @@ static struct netdev_adjacent *__netdev_find_adj(struct net_device *dev,
 static inline struct netdev_adjacent *__netdev_find_upper(struct net_device *dev,
 							  struct net_device *udev)
 {
-	return __netdev_find_adj(dev, udev, true);
+	return __netdev_find_adj(dev, udev, true, false);
 }
 
 static inline struct netdev_adjacent *__netdev_find_lower(struct net_device *dev,
 							  struct net_device *ldev)
 {
-	return __netdev_find_adj(dev, ldev, false);
+	return __netdev_find_adj(dev, ldev, false, false);
+}
+
+static inline struct netdev_adjacent *__netdev_find_upper_neighbour(struct net_device *dev,
+								    struct net_device *udev)
+{
+	return __netdev_find_adj(dev, udev, true, true);
+}
+
+static inline struct netdev_adjacent *__netdev_find_lower_neighbour(struct net_device *dev,
+								    struct net_device *ldev)
+{
+	return __netdev_find_adj(dev, ldev, false, true);
 }
 
 /**
@@ -4440,7 +4454,7 @@ bool netdev_has_any_upper_dev(struct net_device *dev)
 {
 	ASSERT_RTNL();
 
-	return !list_empty(&dev->upper_dev_list);
+	return !list_empty(&dev->all_dev_list.upper);
 }
 EXPORT_SYMBOL(netdev_has_any_upper_dev);
 
@@ -4457,10 +4471,10 @@ struct net_device *netdev_master_upper_dev_get(struct net_device *dev)
 
 	ASSERT_RTNL();
 
-	if (list_empty(&dev->upper_dev_list))
+	if (list_empty(&dev->neighbour_dev_list.upper))
 		return NULL;
 
-	upper = list_first_entry(&dev->upper_dev_list,
+	upper = list_first_entry(&dev->neighbour_dev_list.upper,
 				 struct netdev_adjacent, list);
 	if (likely(upper->master))
 		return upper->dev;
@@ -4484,7 +4498,7 @@ struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev,
 
 	upper = list_entry_rcu((*iter)->next, struct netdev_adjacent, list);
 
-	if (&upper->list == &dev->upper_dev_list)
+	if (&upper->list == &dev->all_dev_list.upper)
 		return NULL;
 
 	*iter = &upper->list;
@@ -4504,7 +4518,7 @@ struct net_device *netdev_master_upper_dev_get_rcu(struct net_device *dev)
 {
 	struct netdev_adjacent *upper;
 
-	upper = list_first_or_null_rcu(&dev->upper_dev_list,
+	upper = list_first_or_null_rcu(&dev->neighbour_dev_list.upper,
 				       struct netdev_adjacent, list);
 	if (upper && likely(upper->master))
 		return upper->dev;
@@ -4517,11 +4531,12 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev,
 					bool neighbour, bool master,
 					bool upper)
 {
-	struct netdev_adjacent *adj;
+	struct netdev_adjacent *adj, *neigh = NULL;
 
-	adj = __netdev_find_adj(dev, adj_dev, upper);
+	adj = __netdev_find_adj(dev, adj_dev, upper, false);
 
 	if (adj) {
+		/* we cannot insert a neighbour device twice */
 		BUG_ON(neighbour);
 		adj->ref_nr++;
 		return 0;
@@ -4533,24 +4548,50 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev,
 
 	adj->dev = adj_dev;
 	adj->master = master;
-	adj->neighbour = neighbour;
 	adj->ref_nr = 1;
-
 	dev_hold(adj_dev);
+
+	if (neighbour) {
+		neigh = kmalloc(sizeof(*neigh), GFP_KERNEL);
+		if (!neigh) {
+			kfree(adj);
+			return -ENOMEM;
+		}
+		neigh->dev = adj_dev;
+		neigh->master = master;
+		neigh->ref_nr = 1;
+		dev_hold(adj_dev);
+	}
+
 	pr_debug("dev_hold for %s, because of %s link added from %s to %s\n",
 		 adj_dev->name, upper ? "upper" : "lower", dev->name,
 		 adj_dev->name);
+	if (neigh)
+		pr_debug("dev_hold for %s, because of %s link added from %s"
+			 " to %s (neighbour)\n",
+			 adj_dev->name, upper ? "upper" : "lower", dev->name,
+			 adj_dev->name);
 
 	if (!upper) {
-		list_add_tail_rcu(&adj->list, &dev->lower_dev_list);
+		if (neigh)
+			list_add_tail_rcu(&neigh->list,
+					  &dev->neighbour_dev_list.lower);
+		list_add_tail_rcu(&adj->list, &dev->all_dev_list.lower);
 		return 0;
 	}
 
 	/* Ensure that master upper link is always the first item in list. */
-	if (master)
-		list_add_rcu(&adj->list, &dev->upper_dev_list);
-	else
-		list_add_tail_rcu(&adj->list, &dev->upper_dev_list);
+	if (master) {
+		if (neigh)
+			list_add_rcu(&neigh->list,
+				     &dev->neighbour_dev_list.upper);
+		list_add_rcu(&adj->list, &dev->all_dev_list.upper);
+	} else {
+		if (neigh)
+			list_add_tail_rcu(&neigh->list,
+					  &dev->neighbour_dev_list.upper);
+		list_add_tail_rcu(&adj->list, &dev->all_dev_list.upper);
+	}
 
 	return 0;
 }
@@ -4574,17 +4615,36 @@ static inline int __netdev_lower_dev_insert(struct net_device *dev,
 void __netdev_adjacent_dev_remove(struct net_device *dev,
 				  struct net_device *adj_dev, bool upper)
 {
-	struct netdev_adjacent *adj;
+	struct netdev_adjacent *adj, *neighbour;
 
-	if (upper)
+	if (upper) {
 		adj = __netdev_find_upper(dev, adj_dev);
-	else
+		neighbour = __netdev_find_upper_neighbour(dev, adj_dev);
+	} else {
 		adj = __netdev_find_lower(dev, adj_dev);
+		neighbour = __netdev_find_lower_neighbour(dev, adj_dev);
+	}
 
-	if (!adj)
+	if (!adj) {
+		pr_err("tried to remove %s device %s from %s\n",
+		       upper ? "upper" : "lower", dev->name, adj_dev->name);
 		BUG();
+	}
 
 	if (adj->ref_nr > 1) {
+		pr_debug("rec_cnt-- for link to %s, because of %s link removed"
+			 " from %s to %s, remains %d\n",
+			 adj_dev->name, upper ? "upper" : "lower", dev->name,
+			 adj_dev->name, adj->ref_nr-1);
+		if (neighbour) {
+			pr_debug("rec_cnt-- for link to %s, because of %s link"
+				 " removed from %s to %s, remain %d (neigh)\n",
+				 adj_dev->name, upper ? "upper" : "lower",
+				 dev->name, adj_dev->name,
+				 neighbour->ref_nr-1);
+			BUG_ON(adj->ref_nr != neighbour->ref_nr);
+			neighbour->ref_nr--;
+		}
 		adj->ref_nr--;
 		return;
 	}
@@ -4595,6 +4655,15 @@ void __netdev_adjacent_dev_remove(struct net_device *dev,
 		 adj_dev->name);
 	dev_put(adj_dev);
 	kfree_rcu(adj, rcu);
+	if (neighbour) {
+		pr_debug("dev_put for %s, because of %s link removed from %s"
+			 " to %s (neighbour)\n",
+			 adj_dev->name, upper ? "upper" : "lower", dev->name,
+			 adj_dev->name);
+		list_del_rcu(&neighbour->list);
+		dev_put(adj_dev);
+		kfree_rcu(neighbour, rcu);
+	}
 }
 
 static inline void __netdev_upper_dev_remove(struct net_device *dev,
@@ -4675,12 +4744,14 @@ static int __netdev_upper_dev_link(struct net_device *dev,
 		return ret;
 
 	/* Now that we linked these devs, make all the upper_dev's
-	 * upper_dev_list visible to every dev's lower_dev_list and vice
+	 * all_dev_list.upper visible to every dev's all_dev_list.lower an
 	 * versa, and don't forget the devices itself. All of these
 	 * links are non-neighbours.
 	 */
-	list_for_each_entry(i, &dev->lower_dev_list, list) {
-		list_for_each_entry(j, &upper_dev->upper_dev_list, list) {
+	list_for_each_entry(i, &dev->all_dev_list.lower, list) {
+		list_for_each_entry(j, &upper_dev->all_dev_list.upper, list) {
+			pr_debug("Interlinking %s with %s, non-neighbour\n",
+				 i->dev->name, j->dev->name);
 			ret = __netdev_adjacent_dev_link(i->dev, j->dev);
 			if (ret)
 				goto rollback_mesh;
@@ -4688,14 +4759,18 @@ static int __netdev_upper_dev_link(struct net_device *dev,
 	}
 
 	/* add dev to every upper_dev's upper device */
-	list_for_each_entry(i, &upper_dev->upper_dev_list, list) {
+	list_for_each_entry(i, &upper_dev->all_dev_list.upper, list) {
+		pr_debug("linking %s's upper device %s with %s\n", upper_dev->name,
+			 i->dev->name, dev->name);
 		ret = __netdev_adjacent_dev_link(dev, i->dev);
 		if (ret)
 			goto rollback_upper_mesh;
 	}
 
 	/* add upper_dev to every dev's lower device */
-	list_for_each_entry(i, &dev->lower_dev_list, list) {
+	list_for_each_entry(i, &dev->all_dev_list.lower, list) {
+		pr_debug("linking %s's lower device %s with %s\n", dev->name,
+			 i->dev->name, upper_dev->name);
 		ret = __netdev_adjacent_dev_link(i->dev, upper_dev);
 		if (ret)
 			goto rollback_lower_mesh;
@@ -4706,7 +4781,7 @@ static int __netdev_upper_dev_link(struct net_device *dev,
 
 rollback_lower_mesh:
 	to_i = i;
-	list_for_each_entry(i, &dev->lower_dev_list, list) {
+	list_for_each_entry(i, &dev->all_dev_list.lower, list) {
 		if (i == to_i)
 			break;
 		__netdev_adjacent_dev_unlink(i->dev, upper_dev);
@@ -4716,7 +4791,7 @@ rollback_lower_mesh:
 
 rollback_upper_mesh:
 	to_i = i;
-	list_for_each_entry(i, &upper_dev->upper_dev_list, list) {
+	list_for_each_entry(i, &upper_dev->all_dev_list.upper, list) {
 		if (i == to_i)
 			break;
 		__netdev_adjacent_dev_unlink(dev, i->dev);
@@ -4727,8 +4802,8 @@ rollback_upper_mesh:
 rollback_mesh:
 	to_i = i;
 	to_j = j;
-	list_for_each_entry(i, &dev->lower_dev_list, list) {
-		list_for_each_entry(j, &upper_dev->upper_dev_list, list) {
+	list_for_each_entry(i, &dev->all_dev_list.lower, list) {
+		list_for_each_entry(j, &upper_dev->all_dev_list.upper, list) {
 			if (i == to_i && j == to_j)
 				break;
 			__netdev_adjacent_dev_unlink(i->dev, j->dev);
@@ -4797,17 +4872,17 @@ void netdev_upper_dev_unlink(struct net_device *dev,
 	 * devices from all upper_dev's upper devices and vice
 	 * versa, to maintain the graph relationship.
 	 */
-	list_for_each_entry(i, &dev->lower_dev_list, list)
-		list_for_each_entry(j, &upper_dev->upper_dev_list, list)
+	list_for_each_entry(i, &dev->all_dev_list.lower, list)
+		list_for_each_entry(j, &upper_dev->all_dev_list.upper, list)
 			__netdev_adjacent_dev_unlink(i->dev, j->dev);
 
 	/* remove also the devices itself from lower/upper device
 	 * list
 	 */
-	list_for_each_entry(i, &dev->lower_dev_list, list)
+	list_for_each_entry(i, &dev->all_dev_list.lower, list)
 		__netdev_adjacent_dev_unlink(i->dev, upper_dev);
 
-	list_for_each_entry(i, &upper_dev->upper_dev_list, list)
+	list_for_each_entry(i, &upper_dev->all_dev_list.upper, list)
 		__netdev_adjacent_dev_unlink(dev, i->dev);
 
 	call_netdevice_notifiers(NETDEV_CHANGEUPPER, dev);
@@ -6069,8 +6144,10 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
 	INIT_LIST_HEAD(&dev->napi_list);
 	INIT_LIST_HEAD(&dev->unreg_list);
 	INIT_LIST_HEAD(&dev->link_watch_list);
-	INIT_LIST_HEAD(&dev->upper_dev_list);
-	INIT_LIST_HEAD(&dev->lower_dev_list);
+	INIT_LIST_HEAD(&dev->neighbour_dev_list.upper);
+	INIT_LIST_HEAD(&dev->neighbour_dev_list.lower);
+	INIT_LIST_HEAD(&dev->all_dev_list.upper);
+	INIT_LIST_HEAD(&dev->all_dev_list.lower);
 	dev->priv_flags = IFF_XMIT_DST_RELEASE;
 	setup(dev);
 
-- 
1.8.4

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH RFC net-next 02/21] net: add RCU variant to search for netdev_adjacent link
  2013-09-02 21:39 [PATCH RFC net-next 0/21] bonding: use neighbours instead of own lists Veaceslav Falico
  2013-09-02 21:39 ` [PATCH RFC net-next 01/21] net: add neighbour_dev_list to save only neighbours Veaceslav Falico
@ 2013-09-02 21:39 ` Veaceslav Falico
  2013-09-02 21:39 ` [PATCH RFC net-next 03/21] net: add netdev_adjacent->private and allow to use it Veaceslav Falico
                   ` (18 subsequent siblings)
  20 siblings, 0 replies; 27+ messages in thread
From: Veaceslav Falico @ 2013-09-02 21:39 UTC (permalink / raw)
  To: netdev
  Cc: Veaceslav Falico, David S. Miller, Eric Dumazet, Jiri Pirko,
	Alexander Duyck, Cong Wang

Currently we have only the RTNL flavour, however we can traverse it while
holding only RCU, so add the RCU search.

CC: "David S. Miller" <davem@davemloft.net>
CC: Eric Dumazet <edumazet@google.com>
CC: Jiri Pirko <jiri@resnulli.us>
CC: Alexander Duyck <alexander.h.duyck@intel.com>
CC: Cong Wang <amwang@redhat.com>
Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
---
 net/core/dev.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)

diff --git a/net/core/dev.c b/net/core/dev.c
index 9e4eb40..4e67a67 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4380,6 +4380,51 @@ struct netdev_adjacent {
 	struct rcu_head rcu;
 };
 
+static struct netdev_adjacent *__netdev_find_adj_rcu(struct net_device *dev,
+						     struct net_device *adj_dev,
+						     bool upper, bool neighbour)
+{
+	struct netdev_adjacent *adj;
+	struct list_head *dev_list;
+
+	if (neighbour)
+		dev_list = upper ? &dev->neighbour_dev_list.upper :
+				   &dev->neighbour_dev_list.lower;
+	else
+		dev_list = upper ? &dev->all_dev_list.upper :
+				   &dev->all_dev_list.lower;
+
+	list_for_each_entry_rcu(adj, dev_list, list) {
+		if (adj->dev == adj_dev)
+			return adj;
+	}
+	return NULL;
+}
+
+static inline struct netdev_adjacent *__netdev_find_upper_rcu(struct net_device *dev,
+							      struct net_device *udev)
+{
+	return __netdev_find_adj_rcu(dev, udev, true, false);
+}
+
+static inline struct netdev_adjacent *__netdev_find_lower_rcu(struct net_device *dev,
+							      struct net_device *ldev)
+{
+	return __netdev_find_adj_rcu(dev, ldev, false, false);
+}
+
+static inline struct netdev_adjacent *__netdev_find_upper_neighbour_rcu(struct net_device *dev,
+									struct net_device *udev)
+{
+	return __netdev_find_adj_rcu(dev, udev, true, true);
+}
+
+static inline struct netdev_adjacent *__netdev_find_lower_neighbour_rcu(struct net_device *dev,
+									struct net_device *ldev)
+{
+	return __netdev_find_adj_rcu(dev, ldev, false, true);
+}
+
 static struct netdev_adjacent *__netdev_find_adj(struct net_device *dev,
 						 struct net_device *adj_dev,
 						 bool upper, bool neighbour)
-- 
1.8.4

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH RFC net-next 03/21] net: add netdev_adjacent->private and allow to use it
  2013-09-02 21:39 [PATCH RFC net-next 0/21] bonding: use neighbours instead of own lists Veaceslav Falico
  2013-09-02 21:39 ` [PATCH RFC net-next 01/21] net: add neighbour_dev_list to save only neighbours Veaceslav Falico
  2013-09-02 21:39 ` [PATCH RFC net-next 02/21] net: add RCU variant to search for netdev_adjacent link Veaceslav Falico
@ 2013-09-02 21:39 ` Veaceslav Falico
  2013-09-02 21:39 ` [PATCH RFC net-next 04/21] net: expose the master link to sysfs, and remove it from bond Veaceslav Falico
                   ` (17 subsequent siblings)
  20 siblings, 0 replies; 27+ messages in thread
From: Veaceslav Falico @ 2013-09-02 21:39 UTC (permalink / raw)
  To: netdev
  Cc: Veaceslav Falico, David S. Miller, Eric Dumazet, Jiri Pirko,
	Alexander Duyck

Currently, even though we can access any linked device, we can't attach
anything to it, which is vital to properly manage them.

To fix this, add a new void *private to netdev_adjacent and functions
setting/getting it (per link), so that we can save, per example, bonding's
slave structures there, per slave device.

netdev_master_upper_dev_link_private(dev, upper_dev, private) links dev to
upper dev and populates the neighbour link only with private.

netdev_lower_dev_get_private{,_rcu}() returns the private, if found.

CC: "David S. Miller" <davem@davemloft.net>
CC: Eric Dumazet <edumazet@google.com>
CC: Jiri Pirko <jiri@resnulli.us>
CC: Alexander Duyck <alexander.h.duyck@intel.com>
Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
---
 include/linux/netdevice.h |  7 ++++
 net/core/dev.c            | 83 ++++++++++++++++++++++++++++++++++++++---------
 2 files changed, 75 insertions(+), 15 deletions(-)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index df50548..ef1ddee 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2794,8 +2794,15 @@ extern int netdev_upper_dev_link(struct net_device *dev,
 				 struct net_device *upper_dev);
 extern int netdev_master_upper_dev_link(struct net_device *dev,
 					struct net_device *upper_dev);
+extern int netdev_master_upper_dev_link_private(struct net_device *dev,
+						struct net_device *upper_dev,
+						void *private);
 extern void netdev_upper_dev_unlink(struct net_device *dev,
 				    struct net_device *upper_dev);
+extern void *netdev_lower_dev_get_private_rcu(struct net_device *dev,
+					      struct net_device *lower_dev);
+extern void *netdev_lower_dev_get_private(struct net_device *dev,
+					  struct net_device *lower_dev);
 extern int skb_checksum_help(struct sk_buff *skb);
 extern struct sk_buff *__skb_gso_segment(struct sk_buff *skb,
 	netdev_features_t features, bool tx_path);
diff --git a/net/core/dev.c b/net/core/dev.c
index 4e67a67..fc5c5a1 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4376,6 +4376,9 @@ struct netdev_adjacent {
 	/* counter for the number of times this device was added to us */
 	u16 ref_nr;
 
+	/* private field for the users */
+	void *private;
+
 	struct list_head list;
 	struct rcu_head rcu;
 };
@@ -4574,7 +4577,7 @@ EXPORT_SYMBOL(netdev_master_upper_dev_get_rcu);
 static int __netdev_adjacent_dev_insert(struct net_device *dev,
 					struct net_device *adj_dev,
 					bool neighbour, bool master,
-					bool upper)
+					bool upper, void *private)
 {
 	struct netdev_adjacent *adj, *neigh = NULL;
 
@@ -4618,9 +4621,15 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev,
 			 adj_dev->name);
 
 	if (!upper) {
-		if (neigh)
+		if (neigh) {
+			/* we're backlinging the master device to its
+			 * slave, so save the private in this link.
+			 */
+			if (master)
+				neigh->private = private;
 			list_add_tail_rcu(&neigh->list,
 					  &dev->neighbour_dev_list.lower);
+		}
 		list_add_tail_rcu(&adj->list, &dev->all_dev_list.lower);
 		return 0;
 	}
@@ -4646,15 +4655,16 @@ static inline int __netdev_upper_dev_insert(struct net_device *dev,
 					    bool master, bool neighbour)
 {
 	return __netdev_adjacent_dev_insert(dev, udev, neighbour, master,
-					    true);
+					    true, NULL);
 }
 
 static inline int __netdev_lower_dev_insert(struct net_device *dev,
 					    struct net_device *ldev,
-					    bool neighbour)
+					    bool master, bool neighbour,
+					    void *private)
 {
-	return __netdev_adjacent_dev_insert(dev, ldev, neighbour, false,
-					    false);
+	return __netdev_adjacent_dev_insert(dev, ldev, neighbour, master,
+					    false, private);
 }
 
 void __netdev_adjacent_dev_remove(struct net_device *dev,
@@ -4725,7 +4735,8 @@ static inline void __netdev_lower_dev_remove(struct net_device *dev,
 
 int __netdev_adjacent_dev_insert_link(struct net_device *dev,
 				      struct net_device *upper_dev,
-				      bool master, bool neighbour)
+				      bool master, bool neighbour,
+				      void *private)
 {
 	int ret;
 
@@ -4733,7 +4744,8 @@ int __netdev_adjacent_dev_insert_link(struct net_device *dev,
 	if (ret)
 		return ret;
 
-	ret = __netdev_lower_dev_insert(upper_dev, dev, neighbour);
+	ret = __netdev_lower_dev_insert(upper_dev, dev, master, neighbour,
+					private);
 	if (ret) {
 		__netdev_upper_dev_remove(dev, upper_dev);
 		return ret;
@@ -4745,14 +4757,15 @@ int __netdev_adjacent_dev_insert_link(struct net_device *dev,
 static inline int __netdev_adjacent_dev_link(struct net_device *dev,
 					     struct net_device *udev)
 {
-	return __netdev_adjacent_dev_insert_link(dev, udev, false, false);
+	return __netdev_adjacent_dev_insert_link(dev, udev, false, false, NULL);
 }
 
 static inline int __netdev_adjacent_dev_link_neighbour(struct net_device *dev,
 						       struct net_device *udev,
-						       bool master)
+						       bool master, void *priv)
 {
-	return __netdev_adjacent_dev_insert_link(dev, udev, master, true);
+	return __netdev_adjacent_dev_insert_link(dev, udev, master, true,
+						 priv);
 }
 
 void __netdev_adjacent_dev_unlink(struct net_device *dev,
@@ -4764,7 +4777,8 @@ void __netdev_adjacent_dev_unlink(struct net_device *dev,
 
 
 static int __netdev_upper_dev_link(struct net_device *dev,
-				   struct net_device *upper_dev, bool master)
+				   struct net_device *upper_dev, bool master,
+				   void *private)
 {
 	struct netdev_adjacent *i, *j, *to_i, *to_j;
 	int ret = 0;
@@ -4784,7 +4798,8 @@ static int __netdev_upper_dev_link(struct net_device *dev,
 	if (master && netdev_master_upper_dev_get(dev))
 		return -EBUSY;
 
-	ret = __netdev_adjacent_dev_link_neighbour(dev, upper_dev, master);
+	ret = __netdev_adjacent_dev_link_neighbour(dev, upper_dev, master,
+						   private);
 	if (ret)
 		return ret;
 
@@ -4875,7 +4890,7 @@ rollback_mesh:
 int netdev_upper_dev_link(struct net_device *dev,
 			  struct net_device *upper_dev)
 {
-	return __netdev_upper_dev_link(dev, upper_dev, false);
+	return __netdev_upper_dev_link(dev, upper_dev, false, NULL);
 }
 EXPORT_SYMBOL(netdev_upper_dev_link);
 
@@ -4893,10 +4908,18 @@ EXPORT_SYMBOL(netdev_upper_dev_link);
 int netdev_master_upper_dev_link(struct net_device *dev,
 				 struct net_device *upper_dev)
 {
-	return __netdev_upper_dev_link(dev, upper_dev, true);
+	return __netdev_upper_dev_link(dev, upper_dev, true, NULL);
 }
 EXPORT_SYMBOL(netdev_master_upper_dev_link);
 
+int netdev_master_upper_dev_link_private(struct net_device *dev,
+					 struct net_device *upper_dev,
+					 void *private)
+{
+	return __netdev_upper_dev_link(dev, upper_dev, true, private);
+}
+EXPORT_SYMBOL(netdev_master_upper_dev_link_private);
+
 /**
  * netdev_upper_dev_unlink - Removes a link to upper device
  * @dev: device
@@ -4934,6 +4957,36 @@ void netdev_upper_dev_unlink(struct net_device *dev,
 }
 EXPORT_SYMBOL(netdev_upper_dev_unlink);
 
+void *netdev_lower_dev_get_private_rcu(struct net_device *dev,
+				       struct net_device *lower_dev)
+{
+	struct netdev_adjacent *lower;
+
+	if (!lower_dev)
+		return NULL;
+	lower = __netdev_find_lower_neighbour_rcu(dev, lower_dev);
+	if (!lower)
+		return NULL;
+
+	return lower->private;
+}
+EXPORT_SYMBOL(netdev_lower_dev_get_private_rcu);
+
+void *netdev_lower_dev_get_private(struct net_device *dev,
+				   struct net_device *lower_dev)
+{
+	struct netdev_adjacent *lower;
+
+	if (!lower_dev)
+		return NULL;
+	lower = __netdev_find_lower_neighbour(dev, lower_dev);
+	if (!lower)
+		return NULL;
+
+	return lower->private;
+}
+EXPORT_SYMBOL(netdev_lower_dev_get_private);
+
 static void dev_change_rx_flags(struct net_device *dev, int flags)
 {
 	const struct net_device_ops *ops = dev->netdev_ops;
-- 
1.8.4

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH RFC net-next 04/21] net: expose the master link to sysfs, and remove it from bond
  2013-09-02 21:39 [PATCH RFC net-next 0/21] bonding: use neighbours instead of own lists Veaceslav Falico
                   ` (2 preceding siblings ...)
  2013-09-02 21:39 ` [PATCH RFC net-next 03/21] net: add netdev_adjacent->private and allow to use it Veaceslav Falico
@ 2013-09-02 21:39 ` Veaceslav Falico
  2013-09-02 21:39 ` [PATCH RFC net-next 05/21] vlan: link the upper neighbour only after registering Veaceslav Falico
                   ` (16 subsequent siblings)
  20 siblings, 0 replies; 27+ messages in thread
From: Veaceslav Falico @ 2013-09-02 21:39 UTC (permalink / raw)
  To: netdev
  Cc: Veaceslav Falico, Jay Vosburgh, Andy Gospodarek, David S. Miller,
	Eric Dumazet, Jiri Pirko, Alexander Duyck

Currently, we can have only one master upper neighbour, so it would be
useful to create a symlink to it in the sysfs device directory, the way
that bonding now does it, for every device. Lower devices from
bridge/team/etc will automagically get it, so we could rely on it.

Also, remove the same functionality from bonding.

CC: Jay Vosburgh <fubar@us.ibm.com>
CC: Andy Gospodarek <andy@greyhouse.net>
CC: "David S. Miller" <davem@davemloft.net>
CC: Eric Dumazet <edumazet@google.com>
CC: Jiri Pirko <jiri@resnulli.us>
CC: Alexander Duyck <alexander.h.duyck@intel.com>
Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
---
 drivers/net/bonding/bond_sysfs.c | 12 +-----------
 net/core/dev.c                   |  9 +++++++++
 2 files changed, 10 insertions(+), 11 deletions(-)

diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 0f539de..5715277 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -174,20 +174,11 @@ int bond_create_slave_symlinks(struct net_device *master,
 	char linkname[IFNAMSIZ+7];
 	int ret = 0;
 
-	/* first, create a link from the slave back to the master */
-	ret = sysfs_create_link(&(slave->dev.kobj), &(master->dev.kobj),
-				"master");
-	if (ret)
-		return ret;
-	/* next, create a link from the master to the slave */
+	/* create a link from the master to the slave */
 	sprintf(linkname, "slave_%s", slave->name);
 	ret = sysfs_create_link(&(master->dev.kobj), &(slave->dev.kobj),
 				linkname);
 
-	/* free the master link created earlier in case of error */
-	if (ret)
-		sysfs_remove_link(&(slave->dev.kobj), "master");
-
 	return ret;
 
 }
@@ -197,7 +188,6 @@ void bond_destroy_slave_symlinks(struct net_device *master,
 {
 	char linkname[IFNAMSIZ+7];
 
-	sysfs_remove_link(&(slave->dev.kobj), "master");
 	sprintf(linkname, "slave_%s", slave->name);
 	sysfs_remove_link(&(master->dev.kobj), linkname);
 }
diff --git a/net/core/dev.c b/net/core/dev.c
index fc5c5a1..7eecf35 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4580,6 +4580,7 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev,
 					bool upper, void *private)
 {
 	struct netdev_adjacent *adj, *neigh = NULL;
+	int ret;
 
 	adj = __netdev_find_adj(dev, adj_dev, upper, false);
 
@@ -4636,6 +4637,12 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev,
 
 	/* Ensure that master upper link is always the first item in list. */
 	if (master) {
+		ret = sysfs_create_link(&(dev->dev.kobj), &(adj_dev->dev.kobj), "master");
+		if (ret) {
+			kfree(neigh);
+			kfree(adj);
+			return ret;
+		}
 		if (neigh)
 			list_add_rcu(&neigh->list,
 				     &dev->neighbour_dev_list.upper);
@@ -4716,6 +4723,8 @@ void __netdev_adjacent_dev_remove(struct net_device *dev,
 			 adj_dev->name, upper ? "upper" : "lower", dev->name,
 			 adj_dev->name);
 		list_del_rcu(&neighbour->list);
+		if (neighbour->master && upper)
+			sysfs_remove_link(&(dev->dev.kobj), "master");
 		dev_put(adj_dev);
 		kfree_rcu(neighbour, rcu);
 	}
-- 
1.8.4

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH RFC net-next 05/21] vlan: link the upper neighbour only after registering
  2013-09-02 21:39 [PATCH RFC net-next 0/21] bonding: use neighbours instead of own lists Veaceslav Falico
                   ` (3 preceding siblings ...)
  2013-09-02 21:39 ` [PATCH RFC net-next 04/21] net: expose the master link to sysfs, and remove it from bond Veaceslav Falico
@ 2013-09-02 21:39 ` Veaceslav Falico
  2013-09-02 21:39 ` [PATCH RFC net-next 06/21] net: create sysfs symlinks for neighbour devices Veaceslav Falico
                   ` (15 subsequent siblings)
  20 siblings, 0 replies; 27+ messages in thread
From: Veaceslav Falico @ 2013-09-02 21:39 UTC (permalink / raw)
  To: netdev; +Cc: Veaceslav Falico, Patrick McHardy, David S. Miller

Otherwise users might access it without being fully registered, as per
sysfs - it only inits in register_netdevice(), so is unusable till it is
called.

CC: Patrick McHardy <kaber@trash.net>
CC: "David S. Miller" <davem@davemloft.net>
Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
---
 net/8021q/vlan.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index 61fc573..69b4a35 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -169,13 +169,13 @@ int register_vlan_dev(struct net_device *dev)
 	if (err < 0)
 		goto out_uninit_mvrp;
 
-	err = netdev_upper_dev_link(real_dev, dev);
-	if (err)
-		goto out_uninit_mvrp;
-
 	err = register_netdevice(dev);
 	if (err < 0)
-		goto out_upper_dev_unlink;
+		goto out_uninit_mvrp;
+
+	err = netdev_upper_dev_link(real_dev, dev);
+	if (err)
+		goto out_unregister_netdev;
 
 	/* Account for reference in struct vlan_dev_priv */
 	dev_hold(real_dev);
@@ -191,8 +191,8 @@ int register_vlan_dev(struct net_device *dev)
 
 	return 0;
 
-out_upper_dev_unlink:
-	netdev_upper_dev_unlink(real_dev, dev);
+out_unregister_netdev:
+	unregister_netdevice(dev);
 out_uninit_mvrp:
 	if (grp->nr_vlan_devs == 0)
 		vlan_mvrp_uninit_applicant(real_dev);
-- 
1.8.4

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH RFC net-next 06/21] net: create sysfs symlinks for neighbour devices
  2013-09-02 21:39 [PATCH RFC net-next 0/21] bonding: use neighbours instead of own lists Veaceslav Falico
                   ` (4 preceding siblings ...)
  2013-09-02 21:39 ` [PATCH RFC net-next 05/21] vlan: link the upper neighbour only after registering Veaceslav Falico
@ 2013-09-02 21:39 ` Veaceslav Falico
  2013-09-03  7:48   ` Jiri Pirko
  2013-09-02 21:39 ` [PATCH RFC net-next 07/21] bonding: add bond_has_slaves() and use it Veaceslav Falico
                   ` (14 subsequent siblings)
  20 siblings, 1 reply; 27+ messages in thread
From: Veaceslav Falico @ 2013-09-02 21:39 UTC (permalink / raw)
  To: netdev
  Cc: Veaceslav Falico, Jay Vosburgh, Andy Gospodarek, David S. Miller,
	Eric Dumazet, Jiri Pirko, Alexander Duyck

Also, remove the same functionality from bonding - it will be already done
for any device that links to its lower/upper neighbour.

The links will be created for dev's kobject, and will look like
slave_eth0 for lower device eth0 and upper_bridge0 for upper device
bridge0.

CC: Jay Vosburgh <fubar@us.ibm.com>
CC: Andy Gospodarek <andy@greyhouse.net>
CC: "David S. Miller" <davem@davemloft.net>
CC: Eric Dumazet <edumazet@google.com>
CC: Jiri Pirko <jiri@resnulli.us>
CC: Alexander Duyck <alexander.h.duyck@intel.com>
Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
---
 drivers/net/bonding/bond_main.c  | 11 +----------
 drivers/net/bonding/bond_sysfs.c | 25 -------------------------
 drivers/net/bonding/bonding.h    |  2 --
 net/core/dev.c                   | 29 +++++++++++++++++++++++++++++
 4 files changed, 30 insertions(+), 37 deletions(-)

diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index c50679f..b0b753d 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1635,15 +1635,11 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 
 	read_unlock(&bond->lock);
 
-	res = bond_create_slave_symlinks(bond_dev, slave_dev);
-	if (res)
-		goto err_detach;
-
 	res = netdev_rx_handler_register(slave_dev, bond_handle_frame,
 					 new_slave);
 	if (res) {
 		pr_debug("Error %d calling netdev_rx_handler_register\n", res);
-		goto err_dest_symlinks;
+		goto err_detach;
 	}
 
 	pr_info("%s: enslaving %s as a%s interface with a%s link.\n",
@@ -1655,9 +1651,6 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 	return 0;
 
 /* Undo stages on error */
-err_dest_symlinks:
-	bond_destroy_slave_symlinks(bond_dev, slave_dev);
-
 err_detach:
 	if (!USES_PRIMARY(bond->params.mode))
 		bond_hw_addr_flush(bond_dev, slave_dev);
@@ -1856,8 +1849,6 @@ static int __bond_release_one(struct net_device *bond_dev,
 			bond_dev->name, slave_dev->name, bond_dev->name);
 
 	/* must do this from outside any spinlocks */
-	bond_destroy_slave_symlinks(bond_dev, slave_dev);
-
 	vlan_vids_del_by_dev(slave_dev, bond_dev);
 
 	/* If the mode USES_PRIMARY, then this cases was handled above by
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 5715277..7b962a2 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -168,31 +168,6 @@ static const struct class_attribute class_attr_bonding_masters = {
 	.namespace = bonding_namespace,
 };
 
-int bond_create_slave_symlinks(struct net_device *master,
-			       struct net_device *slave)
-{
-	char linkname[IFNAMSIZ+7];
-	int ret = 0;
-
-	/* create a link from the master to the slave */
-	sprintf(linkname, "slave_%s", slave->name);
-	ret = sysfs_create_link(&(master->dev.kobj), &(slave->dev.kobj),
-				linkname);
-
-	return ret;
-
-}
-
-void bond_destroy_slave_symlinks(struct net_device *master,
-				 struct net_device *slave)
-{
-	char linkname[IFNAMSIZ+7];
-
-	sprintf(linkname, "slave_%s", slave->name);
-	sysfs_remove_link(&(master->dev.kobj), linkname);
-}
-
-
 /*
  * Show the slaves in the current bond.
  */
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 4abc925..f7a167d 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -455,8 +455,6 @@ int bond_create(struct net *net, const char *name);
 int bond_create_sysfs(struct bond_net *net);
 void bond_destroy_sysfs(struct bond_net *net);
 void bond_prepare_sysfs_group(struct bonding *bond);
-int bond_create_slave_symlinks(struct net_device *master, struct net_device *slave);
-void bond_destroy_slave_symlinks(struct net_device *master, struct net_device *slave);
 int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev);
 int bond_release(struct net_device *bond_dev, struct net_device *slave_dev);
 void bond_mii_monitor(struct work_struct *);
diff --git a/net/core/dev.c b/net/core/dev.c
index 7eecf35..1c3e98d 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4580,6 +4580,7 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev,
 					bool upper, void *private)
 {
 	struct netdev_adjacent *adj, *neigh = NULL;
+	char linkname[IFNAMSIZ+7];
 	int ret;
 
 	adj = __netdev_find_adj(dev, adj_dev, upper, false);
@@ -4628,6 +4629,16 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev,
 			 */
 			if (master)
 				neigh->private = private;
+
+			sprintf(linkname, "slave_%s", adj_dev->name);
+			ret = sysfs_create_link(&(dev->dev.kobj),
+						&(adj_dev->dev.kobj),
+						linkname);
+			if (ret) {
+				kfree(neigh);
+				kfree(adj);
+				return ret;
+			}
 			list_add_tail_rcu(&neigh->list,
 					  &dev->neighbour_dev_list.lower);
 		}
@@ -4635,10 +4646,24 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev,
 		return 0;
 	}
 
+	/* it's upper neighbour, we don't care if it's master or not */
+	if (neigh) {
+		sprintf(linkname, "upper_%s", adj_dev->name);
+		ret = sysfs_create_link(&(dev->dev.kobj), &(adj_dev->dev.kobj),
+					linkname);
+		if (ret) {
+			kfree(neigh);
+			kfree(adj);
+			return ret;
+		}
+	}
+
 	/* Ensure that master upper link is always the first item in list. */
 	if (master) {
 		ret = sysfs_create_link(&(dev->dev.kobj), &(adj_dev->dev.kobj), "master");
 		if (ret) {
+			if (neigh)
+				sysfs_remove_link(&(dev->dev.kobj), linkname);
 			kfree(neigh);
 			kfree(adj);
 			return ret;
@@ -4678,6 +4703,7 @@ void __netdev_adjacent_dev_remove(struct net_device *dev,
 				  struct net_device *adj_dev, bool upper)
 {
 	struct netdev_adjacent *adj, *neighbour;
+	char linkname[IFNAMSIZ+7];
 
 	if (upper) {
 		adj = __netdev_find_upper(dev, adj_dev);
@@ -4725,6 +4751,9 @@ void __netdev_adjacent_dev_remove(struct net_device *dev,
 		list_del_rcu(&neighbour->list);
 		if (neighbour->master && upper)
 			sysfs_remove_link(&(dev->dev.kobj), "master");
+		sprintf(linkname, "%s_%s", upper ? "upper" : "slave",
+			adj_dev->name);
+		sysfs_remove_link(&(dev->dev.kobj), linkname);
 		dev_put(adj_dev);
 		kfree_rcu(neighbour, rcu);
 	}
-- 
1.8.4

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH RFC net-next 07/21] bonding: add bond_has_slaves() and use it
  2013-09-02 21:39 [PATCH RFC net-next 0/21] bonding: use neighbours instead of own lists Veaceslav Falico
                   ` (5 preceding siblings ...)
  2013-09-02 21:39 ` [PATCH RFC net-next 06/21] net: create sysfs symlinks for neighbour devices Veaceslav Falico
@ 2013-09-02 21:39 ` Veaceslav Falico
  2013-09-02 21:39 ` [PATCH RFC net-next 08/21] bonding: convert bond_has_slaves() to use the neighbour list Veaceslav Falico
                   ` (13 subsequent siblings)
  20 siblings, 0 replies; 27+ messages in thread
From: Veaceslav Falico @ 2013-09-02 21:39 UTC (permalink / raw)
  To: netdev; +Cc: Veaceslav Falico, Jay Vosburgh, Andy Gospodarek

Currently we verify if we have slaves by checking if bond->slave_list is
empty. Create a define bond_has_slaves() and use it, a bit more readable
and easier to change in the future.

CC: Jay Vosburgh <fubar@us.ibm.com>
CC: Andy Gospodarek <andy@greyhouse.net>
Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
---
 drivers/net/bonding/bond_3ad.c   |  2 +-
 drivers/net/bonding/bond_alb.c   |  8 ++++----
 drivers/net/bonding/bond_main.c  | 32 ++++++++++++++++----------------
 drivers/net/bonding/bond_sysfs.c |  4 ++--
 drivers/net/bonding/bonding.h    |  2 ++
 5 files changed, 25 insertions(+), 23 deletions(-)

diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index 9010265..f0cca88 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -2117,7 +2117,7 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
 	read_lock(&bond->lock);
 
 	//check if there are any slaves
-	if (list_empty(&bond->slave_list))
+	if (!bond_has_slaves(bond))
 		goto re_arm;
 
 	// check if agg_select_timer timer after initialize is timed out
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 0182352..a277465 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -1177,7 +1177,7 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav
 	struct slave *tmp_slave1, *free_mac_slave = NULL;
 	struct slave *has_bond_addr = bond->curr_active_slave;
 
-	if (list_empty(&bond->slave_list)) {
+	if (!bond_has_slaves(bond)) {
 		/* this is the first slave */
 		return 0;
 	}
@@ -1464,7 +1464,7 @@ void bond_alb_monitor(struct work_struct *work)
 
 	read_lock(&bond->lock);
 
-	if (list_empty(&bond->slave_list)) {
+	if (!bond_has_slaves(bond)) {
 		bond_info->tx_rebalance_counter = 0;
 		bond_info->lp_counter = 0;
 		goto re_arm;
@@ -1601,7 +1601,7 @@ int bond_alb_init_slave(struct bonding *bond, struct slave *slave)
  */
 void bond_alb_deinit_slave(struct bonding *bond, struct slave *slave)
 {
-	if (!list_empty(&bond->slave_list))
+	if (bond_has_slaves(bond))
 		alb_change_hw_addr_on_detach(bond, slave);
 
 	tlb_clear_slave(bond, slave, 0);
@@ -1671,7 +1671,7 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave
 	swap_slave = bond->curr_active_slave;
 	rcu_assign_pointer(bond->curr_active_slave, new_slave);
 
-	if (!new_slave || list_empty(&bond->slave_list))
+	if (!new_slave || !bond_has_slaves(bond))
 		return;
 
 	/* set the new curr_active_slave to the bonds mac address
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index b0b753d..b347b3d 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -384,7 +384,7 @@ static int bond_set_carrier(struct bonding *bond)
 {
 	struct slave *slave;
 
-	if (list_empty(&bond->slave_list))
+	if (!bond_has_slaves(bond))
 		goto down;
 
 	if (bond->params.mode == BOND_MODE_8023AD)
@@ -1093,7 +1093,7 @@ static netdev_features_t bond_fix_features(struct net_device *dev,
 
 	read_lock(&bond->lock);
 
-	if (list_empty(&bond->slave_list)) {
+	if (!bond_has_slaves(bond)) {
 		/* Disable adding VLANs to empty bond. But why? --mq */
 		features |= NETIF_F_VLAN_CHALLENGED;
 		goto out;
@@ -1131,7 +1131,7 @@ static void bond_compute_features(struct bonding *bond)
 
 	read_lock(&bond->lock);
 
-	if (list_empty(&bond->slave_list))
+	if (!bond_has_slaves(bond))
 		goto done;
 
 	bond_for_each_slave(bond, slave) {
@@ -1322,7 +1322,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 	 * bond ether type mutual exclusion - don't allow slaves of dissimilar
 	 * ether type (eg ARPHRD_ETHER and ARPHRD_INFINIBAND) share the same bond
 	 */
-	if (list_empty(&bond->slave_list)) {
+	if (!bond_has_slaves(bond)) {
 		if (bond_dev->type != slave_dev->type) {
 			pr_debug("%s: change device type from %d to %d\n",
 				 bond_dev->name,
@@ -1361,7 +1361,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 	}
 
 	if (slave_ops->ndo_set_mac_address == NULL) {
-		if (list_empty(&bond->slave_list)) {
+		if (!bond_has_slaves(bond)) {
 			pr_warning("%s: Warning: The first slave device specified does not support setting the MAC address. Setting fail_over_mac to active.",
 				   bond_dev->name);
 			bond->params.fail_over_mac = BOND_FOM_ACTIVE;
@@ -1377,7 +1377,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 
 	/* If this is the first slave, then we need to set the master's hardware
 	 * address to be the same as the slave's. */
-	if (list_empty(&bond->slave_list) &&
+	if (!bond_has_slaves(bond) &&
 	    bond->dev->addr_assign_type == NET_ADDR_RANDOM)
 		bond_set_dev_addr(bond->dev, slave_dev);
 
@@ -1700,7 +1700,7 @@ err_free:
 err_undo_flags:
 	bond_compute_features(bond);
 	/* Enslave of first slave has failed and we need to fix master's mac */
-	if (list_empty(&bond->slave_list) &&
+	if (!bond_has_slaves(bond) &&
 	    ether_addr_equal(bond_dev->dev_addr, slave_dev->dev_addr))
 		eth_hw_addr_random(bond_dev);
 
@@ -1778,7 +1778,7 @@ static int __bond_release_one(struct net_device *bond_dev,
 
 	if (!all && !bond->params.fail_over_mac) {
 		if (ether_addr_equal(bond_dev->dev_addr, slave->perm_hwaddr) &&
-		    !list_empty(&bond->slave_list))
+		    bond_has_slaves(bond))
 			pr_warn("%s: Warning: the permanent HWaddr of %s - %pM - is still in use by %s. Set the HWaddr of %s to a different address to avoid conflicts.\n",
 				   bond_dev->name, slave_dev->name,
 				   slave->perm_hwaddr,
@@ -1821,7 +1821,7 @@ static int __bond_release_one(struct net_device *bond_dev,
 		write_lock_bh(&bond->lock);
 	}
 
-	if (list_empty(&bond->slave_list)) {
+	if (!bond_has_slaves(bond)) {
 		bond_set_carrier(bond);
 		eth_hw_addr_random(bond_dev);
 
@@ -1837,7 +1837,7 @@ static int __bond_release_one(struct net_device *bond_dev,
 	unblock_netpoll_tx();
 	synchronize_rcu();
 
-	if (list_empty(&bond->slave_list)) {
+	if (!bond_has_slaves(bond)) {
 		call_netdevice_notifiers(NETDEV_CHANGEADDR, bond->dev);
 		call_netdevice_notifiers(NETDEV_RELEASE, bond->dev);
 	}
@@ -1906,7 +1906,7 @@ static int  bond_release_and_destroy(struct net_device *bond_dev,
 	int ret;
 
 	ret = bond_release(bond_dev, slave_dev);
-	if (ret == 0 && list_empty(&bond->slave_list)) {
+	if (ret == 0 && !bond_has_slaves(bond)) {
 		bond_dev->priv_flags |= IFF_DISABLE_NETPOLL;
 		pr_info("%s: destroying bond %s.\n",
 			bond_dev->name, bond_dev->name);
@@ -2218,7 +2218,7 @@ void bond_mii_monitor(struct work_struct *work)
 
 	delay = msecs_to_jiffies(bond->params.miimon);
 
-	if (list_empty(&bond->slave_list))
+	if (!bond_has_slaves(bond))
 		goto re_arm;
 
 	should_notify_peers = bond_should_notify_peers(bond);
@@ -2513,7 +2513,7 @@ void bond_loadbalance_arp_mon(struct work_struct *work)
 
 	read_lock(&bond->lock);
 
-	if (list_empty(&bond->slave_list))
+	if (!bond_has_slaves(bond))
 		goto re_arm;
 
 	oldcurrent = bond->curr_active_slave;
@@ -2833,7 +2833,7 @@ void bond_activebackup_arp_mon(struct work_struct *work)
 
 	delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval);
 
-	if (list_empty(&bond->slave_list))
+	if (!bond_has_slaves(bond))
 		goto re_arm;
 
 	should_notify_peers = bond_should_notify_peers(bond);
@@ -3156,7 +3156,7 @@ static int bond_open(struct net_device *bond_dev)
 
 	/* reset slave->backup and slave->inactive */
 	read_lock(&bond->lock);
-	if (!list_empty(&bond->slave_list)) {
+	if (bond_has_slaves(bond)) {
 		read_lock(&bond->curr_slave_lock);
 		bond_for_each_slave(bond, slave) {
 			if ((bond->params.mode == BOND_MODE_ACTIVEBACKUP)
@@ -3873,7 +3873,7 @@ static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev)
 		return NETDEV_TX_BUSY;
 
 	rcu_read_lock();
-	if (!list_empty(&bond->slave_list))
+	if (bond_has_slaves(bond))
 		ret = __bond_start_xmit(skb, dev);
 	else
 		kfree_skb(skb);
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 7b962a2..8721dcb 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -291,7 +291,7 @@ static ssize_t bonding_store_mode(struct device *d,
 		goto out;
 	}
 
-	if (!list_empty(&bond->slave_list)) {
+	if (bond_has_slaves(bond)) {
 		pr_err("unable to update mode of %s because it has slaves.\n",
 			bond->dev->name);
 		ret = -EPERM;
@@ -473,7 +473,7 @@ static ssize_t bonding_store_fail_over_mac(struct device *d,
 	if (!rtnl_trylock())
 		return restart_syscall();
 
-	if (!list_empty(&bond->slave_list)) {
+	if (bond_has_slaves(bond)) {
 		pr_err("%s: Can't alter fail_over_mac with slaves in bond.\n",
 		       bond->dev->name);
 		ret = -EPERM;
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index f7a167d..5645cd2 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -72,6 +72,8 @@
 	res; })
 
 /* slave list primitives */
+#define bond_has_slaves(bond) !list_empty(&(bond)->slave_list)
+
 #define bond_to_slave(ptr) list_entry(ptr, struct slave, list)
 
 /* IMPORTANT: bond_first/last_slave can return NULL in case of an empty list */
-- 
1.8.4

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH RFC net-next 08/21] bonding: convert bond_has_slaves() to use the neighbour list
  2013-09-02 21:39 [PATCH RFC net-next 0/21] bonding: use neighbours instead of own lists Veaceslav Falico
                   ` (6 preceding siblings ...)
  2013-09-02 21:39 ` [PATCH RFC net-next 07/21] bonding: add bond_has_slaves() and use it Veaceslav Falico
@ 2013-09-02 21:39 ` Veaceslav Falico
  2013-09-02 21:39 ` [PATCH RFC net-next 09/21] bonding: populate neighbour's private on enslave Veaceslav Falico
                   ` (12 subsequent siblings)
  20 siblings, 0 replies; 27+ messages in thread
From: Veaceslav Falico @ 2013-09-02 21:39 UTC (permalink / raw)
  To: netdev; +Cc: Veaceslav Falico, Jay Vosburgh, Andy Gospodarek

The same way as it was used for its own slave_list.

CC: Jay Vosburgh <fubar@us.ibm.com>
CC: Andy Gospodarek <andy@greyhouse.net>
Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
---
 drivers/net/bonding/bonding.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 5645cd2..37055cd 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -72,7 +72,7 @@
 	res; })
 
 /* slave list primitives */
-#define bond_has_slaves(bond) !list_empty(&(bond)->slave_list)
+#define bond_has_slaves(bond) !list_empty(&(bond)->dev->neighbour_dev_list.lower)
 
 #define bond_to_slave(ptr) list_entry(ptr, struct slave, list)
 
-- 
1.8.4

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH RFC net-next 09/21] bonding: populate neighbour's private on enslave
  2013-09-02 21:39 [PATCH RFC net-next 0/21] bonding: use neighbours instead of own lists Veaceslav Falico
                   ` (7 preceding siblings ...)
  2013-09-02 21:39 ` [PATCH RFC net-next 08/21] bonding: convert bond_has_slaves() to use the neighbour list Veaceslav Falico
@ 2013-09-02 21:39 ` Veaceslav Falico
  2013-09-02 21:39 ` [PATCH RFC net-next 10/21] bonding: modify bond_get_slave_by_dev() to use neighbours Veaceslav Falico
                   ` (11 subsequent siblings)
  20 siblings, 0 replies; 27+ messages in thread
From: Veaceslav Falico @ 2013-09-02 21:39 UTC (permalink / raw)
  To: netdev; +Cc: Veaceslav Falico, Jay Vosburgh, Andy Gospodarek

Use the new provided function when attaching the lower slave to populate
its ->private with struct slave *new_slave. Also, move it to the end to
be able to 'find' it only after it was completely initialized, and
deinitialize in the first place on release.

CC: Jay Vosburgh <fubar@us.ibm.com>
CC: Andy Gospodarek <andy@greyhouse.net>
Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
---
 drivers/net/bonding/bond_main.c | 30 ++++++++++++++++--------------
 1 file changed, 16 insertions(+), 14 deletions(-)

diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index b347b3d..427d943 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1242,11 +1242,12 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb)
 }
 
 static int bond_master_upper_dev_link(struct net_device *bond_dev,
-				      struct net_device *slave_dev)
+				      struct net_device *slave_dev,
+				      struct slave *slave)
 {
 	int err;
 
-	err = netdev_master_upper_dev_link(slave_dev, bond_dev);
+	err = netdev_master_upper_dev_link_private(slave_dev, bond_dev, slave);
 	if (err)
 		return err;
 	slave_dev->flags |= IFF_SLAVE;
@@ -1422,17 +1423,11 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 		}
 	}
 
-	res = bond_master_upper_dev_link(bond_dev, slave_dev);
-	if (res) {
-		pr_debug("Error %d calling bond_master_upper_dev_link\n", res);
-		goto err_restore_mac;
-	}
-
 	/* open the slave since the application closed it */
 	res = dev_open(slave_dev);
 	if (res) {
 		pr_debug("Opening slave %s failed\n", slave_dev->name);
-		goto err_unset_master;
+		goto err_restore_mac;
 	}
 
 	new_slave->bond = bond;
@@ -1642,6 +1637,13 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 		goto err_detach;
 	}
 
+	res = bond_master_upper_dev_link(bond_dev, slave_dev, new_slave);
+	if (res) {
+		pr_debug("Error %d calling bond_master_upper_dev_link\n", res);
+		goto err_unregister;
+	}
+
+
 	pr_info("%s: enslaving %s as a%s interface with a%s link.\n",
 		bond_dev->name, slave_dev->name,
 		bond_is_active_slave(new_slave) ? "n active" : " backup",
@@ -1651,6 +1653,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 	return 0;
 
 /* Undo stages on error */
+err_unregister:
+	netdev_rx_handler_unregister(slave_dev);
+
 err_detach:
 	if (!USES_PRIMARY(bond->params.mode))
 		bond_hw_addr_flush(bond_dev, slave_dev);
@@ -1677,9 +1682,6 @@ err_close:
 	slave_dev->priv_flags &= ~IFF_BONDING;
 	dev_close(slave_dev);
 
-err_unset_master:
-	bond_upper_dev_unlink(bond_dev, slave_dev);
-
 err_restore_mac:
 	if (!bond->params.fail_over_mac) {
 		/* XXX TODO - fom follow mode needs to change master's
@@ -1750,6 +1752,8 @@ static int __bond_release_one(struct net_device *bond_dev,
 	}
 
 	write_unlock_bh(&bond->lock);
+
+	bond_upper_dev_unlink(bond_dev, slave_dev);
 	/* unregister rx_handler early so bond_handle_frame wouldn't be called
 	 * for this slave anymore.
 	 */
@@ -1866,8 +1870,6 @@ static int __bond_release_one(struct net_device *bond_dev,
 		bond_hw_addr_flush(bond_dev, slave_dev);
 	}
 
-	bond_upper_dev_unlink(bond_dev, slave_dev);
-
 	slave_disable_netpoll(slave);
 
 	/* close slave before restoring its mac address */
-- 
1.8.4

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH RFC net-next 10/21] bonding: modify bond_get_slave_by_dev() to use neighbours
  2013-09-02 21:39 [PATCH RFC net-next 0/21] bonding: use neighbours instead of own lists Veaceslav Falico
                   ` (8 preceding siblings ...)
  2013-09-02 21:39 ` [PATCH RFC net-next 09/21] bonding: populate neighbour's private on enslave Veaceslav Falico
@ 2013-09-02 21:39 ` Veaceslav Falico
  2013-09-02 21:39 ` [PATCH RFC net-next 11/21] bonding: remove bond_for_each_slave_reverse() Veaceslav Falico
                   ` (10 subsequent siblings)
  20 siblings, 0 replies; 27+ messages in thread
From: Veaceslav Falico @ 2013-09-02 21:39 UTC (permalink / raw)
  To: netdev; +Cc: Veaceslav Falico, Jay Vosburgh, Andy Gospodarek

It should be used under rtnl/bonding lock, so use the non-RCU version.

CC: Jay Vosburgh <fubar@us.ibm.com>
CC: Andy Gospodarek <andy@greyhouse.net>
Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
---
 drivers/net/bonding/bonding.h | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 37055cd..7cb60f9 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -295,13 +295,8 @@ static inline bool bond_vlan_used(struct bonding *bond)
 static inline struct slave *bond_get_slave_by_dev(struct bonding *bond,
 						  struct net_device *slave_dev)
 {
-	struct slave *slave = NULL;
-
-	bond_for_each_slave(bond, slave)
-		if (slave->dev == slave_dev)
-			return slave;
-
-	return NULL;
+	return (struct slave *)netdev_lower_dev_get_private(bond->dev,
+							    slave_dev);
 }
 
 static inline struct bonding *bond_get_bond_by_slave(struct slave *slave)
-- 
1.8.4

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH RFC net-next 11/21] bonding: remove bond_for_each_slave_reverse()
  2013-09-02 21:39 [PATCH RFC net-next 0/21] bonding: use neighbours instead of own lists Veaceslav Falico
                   ` (9 preceding siblings ...)
  2013-09-02 21:39 ` [PATCH RFC net-next 10/21] bonding: modify bond_get_slave_by_dev() to use neighbours Veaceslav Falico
@ 2013-09-02 21:39 ` Veaceslav Falico
  2013-09-02 21:39 ` [PATCH RFC net-next 12/21] net: add for_each iterators through neighbour lower link's private Veaceslav Falico
                   ` (9 subsequent siblings)
  20 siblings, 0 replies; 27+ messages in thread
From: Veaceslav Falico @ 2013-09-02 21:39 UTC (permalink / raw)
  To: netdev; +Cc: Veaceslav Falico, Jay Vosburgh, Andy Gospodarek

We only use it in rollback scenarios and can easily use the standart
bond_for_each_dev() instead.

CC: Jay Vosburgh <fubar@us.ibm.com>
CC: Andy Gospodarek <andy@greyhouse.net>
Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
---
 drivers/net/bonding/bond_alb.c  | 14 ++++++++------
 drivers/net/bonding/bond_main.c | 34 ++++++++++++++++++++++------------
 drivers/net/bonding/bonding.h   | 10 ----------
 3 files changed, 30 insertions(+), 28 deletions(-)

diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index a277465..bda976f 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -1248,9 +1248,9 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav
  */
 static int alb_set_mac_address(struct bonding *bond, void *addr)
 {
-	char tmp_addr[ETH_ALEN];
-	struct slave *slave;
+	struct slave *slave, *rollback_slave;
 	struct sockaddr sa;
+	char tmp_addr[ETH_ALEN];
 	int res;
 
 	if (bond->alb_info.rlb_enabled)
@@ -1276,10 +1276,12 @@ unwind:
 	sa.sa_family = bond->dev->type;
 
 	/* unwind from head to the slave that failed */
-	bond_for_each_slave_continue_reverse(bond, slave) {
-		memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN);
-		dev_set_mac_address(slave->dev, &sa);
-		memcpy(slave->dev->dev_addr, tmp_addr, ETH_ALEN);
+	bond_for_each_slave(bond, rollback_slave) {
+		if (rollback_slave == slave)
+			break;
+		memcpy(tmp_addr, rollback_slave->dev->dev_addr, ETH_ALEN);
+		dev_set_mac_address(rollback_slave->dev, &sa);
+		memcpy(rollback_slave->dev->dev_addr, tmp_addr, ETH_ALEN);
 	}
 
 	return res;
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 427d943..0a4aa0d 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -332,7 +332,7 @@ static int bond_vlan_rx_add_vid(struct net_device *bond_dev,
 				__be16 proto, u16 vid)
 {
 	struct bonding *bond = netdev_priv(bond_dev);
-	struct slave *slave;
+	struct slave *slave, *rollback_slave;
 	int res;
 
 	bond_for_each_slave(bond, slave) {
@@ -344,9 +344,13 @@ static int bond_vlan_rx_add_vid(struct net_device *bond_dev,
 	return 0;
 
 unwind:
-	/* unwind from the slave that failed */
-	bond_for_each_slave_continue_reverse(bond, slave)
-		vlan_vid_del(slave->dev, proto, vid);
+	/* unwind to the slave that failed */
+	bond_for_each_slave(bond, rollback_slave) {
+		if (rollback_slave == slave)
+			break;
+
+		vlan_vid_del(rollback_slave->dev, proto, vid);
+	}
 
 	return res;
 }
@@ -3477,7 +3481,7 @@ static int bond_neigh_setup(struct net_device *dev,
 static int bond_change_mtu(struct net_device *bond_dev, int new_mtu)
 {
 	struct bonding *bond = netdev_priv(bond_dev);
-	struct slave *slave;
+	struct slave *slave, *rollback_slave;
 	int res = 0;
 
 	pr_debug("bond=%p, name=%s, new_mtu=%d\n", bond,
@@ -3526,13 +3530,16 @@ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu)
 
 unwind:
 	/* unwind from head to the slave that failed */
-	bond_for_each_slave_continue_reverse(bond, slave) {
+	bond_for_each_slave(bond, rollback_slave) {
 		int tmp_res;
 
-		tmp_res = dev_set_mtu(slave->dev, bond_dev->mtu);
+		if (rollback_slave == slave);
+			break;
+
+		tmp_res = dev_set_mtu(rollback_slave->dev, bond_dev->mtu);
 		if (tmp_res) {
 			pr_debug("unwind err %d dev %s\n",
-				 tmp_res, slave->dev->name);
+				 tmp_res, rollback_slave->dev->name);
 		}
 	}
 
@@ -3549,8 +3556,8 @@ unwind:
 static int bond_set_mac_address(struct net_device *bond_dev, void *addr)
 {
 	struct bonding *bond = netdev_priv(bond_dev);
+	struct slave *slave, *rollback_slave;
 	struct sockaddr *sa = addr, tmp_sa;
-	struct slave *slave;
 	int res = 0;
 
 	if (bond->params.mode == BOND_MODE_ALB)
@@ -3616,13 +3623,16 @@ unwind:
 	tmp_sa.sa_family = bond_dev->type;
 
 	/* unwind from head to the slave that failed */
-	bond_for_each_slave_continue_reverse(bond, slave) {
+	bond_for_each_slave(bond, rollback_slave) {
 		int tmp_res;
 
-		tmp_res = dev_set_mac_address(slave->dev, &tmp_sa);
+		if (rollback_slave == slave)
+			break;
+
+		tmp_res = dev_set_mac_address(rollback_slave->dev, &tmp_sa);
 		if (tmp_res) {
 			pr_debug("unwind err %d dev %s\n",
-				 tmp_res, slave->dev->name);
+				 tmp_res, rollback_slave->dev->name);
 		}
 	}
 
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 7cb60f9..8c11f96 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -122,16 +122,6 @@
 #define bond_for_each_slave_rcu(bond, pos) \
 	list_for_each_entry_rcu(pos, &(bond)->slave_list, list)
 
-/**
- * bond_for_each_slave_reverse - iterate in reverse from a given position
- * @bond:	the bond holding this list
- * @pos:	slave to continue from
- *
- * Caller must hold bond->lock
- */
-#define bond_for_each_slave_continue_reverse(bond, pos) \
-	list_for_each_entry_continue_reverse(pos, &(bond)->slave_list, list)
-
 #ifdef CONFIG_NET_POLL_CONTROLLER
 extern atomic_t netpoll_block_tx;
 
-- 
1.8.4

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH RFC net-next 12/21] net: add for_each iterators through neighbour lower link's private
  2013-09-02 21:39 [PATCH RFC net-next 0/21] bonding: use neighbours instead of own lists Veaceslav Falico
                   ` (10 preceding siblings ...)
  2013-09-02 21:39 ` [PATCH RFC net-next 11/21] bonding: remove bond_for_each_slave_reverse() Veaceslav Falico
@ 2013-09-02 21:39 ` Veaceslav Falico
  2013-09-02 21:39 ` [PATCH RFC net-next 13/21] bonding: make bond_for_each_slave() use lower neighbour's private Veaceslav Falico
                   ` (8 subsequent siblings)
  20 siblings, 0 replies; 27+ messages in thread
From: Veaceslav Falico @ 2013-09-02 21:39 UTC (permalink / raw)
  To: netdev
  Cc: Veaceslav Falico, David S. Miller, Eric Dumazet, Jiri Pirko,
	Alexander Duyck

Currently we can only iterate through the devices itself, however it'd be
really costy to first get the next device and then search for the link and
get its private - which is a common method to go through slaves of a
device.

Add both RCU and RTNL/other locking variants of iterators.

CC: "David S. Miller" <davem@davemloft.net>
CC: Eric Dumazet <edumazet@google.com>
CC: Jiri Pirko <jiri@resnulli.us>
CC: Alexander Duyck <alexander.h.duyck@intel.com>
Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
---
 include/linux/netdevice.h | 17 ++++++++++++
 net/core/dev.c            | 66 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 83 insertions(+)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index ef1ddee..1a149ef 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2788,6 +2788,23 @@ extern struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev,
 	     updev; \
 	     updev = netdev_upper_get_next_dev_rcu(dev, &(iter)))
 
+extern void *netdev_lower_neigh_get_next_private(struct net_device *dev,
+						 struct list_head **iter);
+extern void *netdev_lower_neigh_get_next_private_rcu(struct net_device *dev,
+						     struct list_head **iter);
+
+#define netdev_for_each_lower_neigh_private(dev, priv, iter) \
+	for (iter = &(dev)->neighbour_dev_list.lower, \
+	     priv = netdev_lower_neigh_get_next_private(dev, &(iter)); \
+	     priv; \
+	     priv = netdev_lower_neigh_get_next_private(dev, &(iter)))
+
+#define netdev_for_each_lower_neigh_private_rcu(dev, priv, iter) \
+	for (iter = &(dev)->neighbour_dev_list.lower, \
+	     priv = netdev_lower_neigh_get_next_private_rcu(dev, &(iter)); \
+	     priv; \
+	     priv = netdev_lower_neigh_get_next_private_rcu(dev, &(iter)))
+
 extern struct net_device *netdev_master_upper_dev_get(struct net_device *dev);
 extern struct net_device *netdev_master_upper_dev_get_rcu(struct net_device *dev);
 extern int netdev_upper_dev_link(struct net_device *dev,
diff --git a/net/core/dev.c b/net/core/dev.c
index 1c3e98d..55f8ac4 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4555,6 +4555,72 @@ struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev,
 }
 EXPORT_SYMBOL(netdev_upper_get_next_dev_rcu);
 
+/* netdev_lower_neigh_get_next_private - Get the next ->private from the
+ *					 lower neighbour list
+ * @dev: device
+ * @iter: list_head ** of the current position
+ *
+ * Gets the next netdev_adjacent->private from the dev's lower neighbour
+ * list, starting from iter position. The caller must hold either hold the
+ * RTNL lock or its own locking that guarantees that the neighbour lower
+ * list will remain unchainged. If iter is NULL - return the first private.
+ */
+void *netdev_lower_neigh_get_next_private(struct net_device *dev,
+					  struct list_head **iter)
+{
+	struct netdev_adjacent *lower;
+
+	if (iter)
+		lower = list_entry((*iter)->next, struct netdev_adjacent,
+				   list);
+	else
+		lower = list_entry(dev->neighbour_dev_list.lower.next,
+				   struct netdev_adjacent, list);
+
+	if (&lower->list == &dev->neighbour_dev_list.lower)
+		return NULL;
+
+	if (iter)
+		*iter = &lower->list;
+
+	return lower->private;
+}
+EXPORT_SYMBOL(netdev_lower_neigh_get_next_private);
+
+/* netdev_lower_neigh_get_next_private_rcu - Get the next ->private from the
+ *					     lower neighbour list, RCU
+ *					     variant
+ * @dev: device
+ * @iter: list_head ** of the current position
+ *
+ * Gets the next netdev_adjacent->private from the dev's lower neighbour
+ * list, starting from iter position. The caller must hold RCU read lock.
+ * If iter is NULL - returns the first private.
+ */
+void *netdev_lower_neigh_get_next_private_rcu(struct net_device *dev,
+					      struct list_head **iter)
+{
+	struct netdev_adjacent *lower;
+
+	WARN_ON_ONCE(!rcu_read_lock_held());
+
+	if (iter)
+		lower = list_entry_rcu((*iter)->next, struct netdev_adjacent,
+				       list);
+	else
+		lower = list_entry_rcu(dev->neighbour_dev_list.lower.next,
+				       struct netdev_adjacent, list);
+
+	if (&lower->list == &dev->neighbour_dev_list.lower)
+		return NULL;
+
+	if (iter)
+		*iter = &lower->list;
+
+	return lower->private;
+}
+EXPORT_SYMBOL(netdev_lower_neigh_get_next_private_rcu);
+
 /**
  * netdev_master_upper_dev_get_rcu - Get master upper device
  * @dev: device
-- 
1.8.4

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH RFC net-next 13/21] bonding: make bond_for_each_slave() use lower neighbour's private
  2013-09-02 21:39 [PATCH RFC net-next 0/21] bonding: use neighbours instead of own lists Veaceslav Falico
                   ` (11 preceding siblings ...)
  2013-09-02 21:39 ` [PATCH RFC net-next 12/21] net: add for_each iterators through neighbour lower link's private Veaceslav Falico
@ 2013-09-02 21:39 ` Veaceslav Falico
  2013-09-02 21:39 ` [PATCH RFC net-next 14/21] net: add netdev_for_each_lower_neigh_private_continue() Veaceslav Falico
                   ` (7 subsequent siblings)
  20 siblings, 0 replies; 27+ messages in thread
From: Veaceslav Falico @ 2013-09-02 21:39 UTC (permalink / raw)
  To: netdev; +Cc: Veaceslav Falico, Jay Vosburgh, Andy Gospodarek

It needs a list_head *iter, so add it wherever needed. Use both non-rcu and
rcu variants.

CC: Jay Vosburgh <fubar@us.ibm.com>
CC: Andy Gospodarek <andy@greyhouse.net>
Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
---
 drivers/net/bonding/bond_3ad.c    |  8 ++--
 drivers/net/bonding/bond_alb.c    | 18 ++++----
 drivers/net/bonding/bond_main.c   | 88 +++++++++++++++++++++++++--------------
 drivers/net/bonding/bond_procfs.c |  5 ++-
 drivers/net/bonding/bond_sysfs.c  | 23 ++++++----
 drivers/net/bonding/bonding.h     | 12 +++---
 6 files changed, 98 insertions(+), 56 deletions(-)

diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index f0cca88..7430cbb 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -2419,6 +2419,7 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
 {
 	struct slave *slave, *start_at;
 	struct bonding *bond = netdev_priv(dev);
+	struct list_head *iter;
 	int slave_agg_no;
 	int slaves_in_agg;
 	int agg_id;
@@ -2444,7 +2445,7 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
 
 	slave_agg_no = bond->xmit_hash_policy(skb, slaves_in_agg);
 
-	bond_for_each_slave(bond, slave) {
+	bond_for_each_slave(bond, slave, iter) {
 		struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator;
 
 		if (agg && (agg->aggregator_identifier == agg_id)) {
@@ -2514,14 +2515,15 @@ int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
  */
 void bond_3ad_update_lacp_rate(struct bonding *bond)
 {
-	struct slave *slave;
 	struct port *port = NULL;
+	struct list_head *iter;
+	struct slave *slave;
 	int lacp_fast;
 
 	write_lock_bh(&bond->lock);
 	lacp_fast = bond->params.lacp_fast;
 
-	bond_for_each_slave(bond, slave) {
+	bond_for_each_slave(bond, slave, iter) {
 		port = &(SLAVE_AD_INFO(slave).port);
 		if (port->slave == NULL)
 			continue;
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index bda976f..738eeae 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -223,13 +223,14 @@ static long long compute_gap(struct slave *slave)
 static struct slave *tlb_get_least_loaded_slave(struct bonding *bond)
 {
 	struct slave *slave, *least_loaded;
+	struct list_head *iter;
 	long long max_gap;
 
 	least_loaded = NULL;
 	max_gap = LLONG_MIN;
 
 	/* Find the slave with the largest gap */
-	bond_for_each_slave(bond, slave) {
+	bond_for_each_slave(bond, slave, iter) {
 		if (SLAVE_IS_OK(slave)) {
 			long long gap = compute_gap(slave);
 
@@ -1174,8 +1175,9 @@ static void alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *sla
  */
 static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slave *slave)
 {
-	struct slave *tmp_slave1, *free_mac_slave = NULL;
 	struct slave *has_bond_addr = bond->curr_active_slave;
+	struct slave *tmp_slave1, *free_mac_slave = NULL;
+	struct list_head *iter;
 
 	if (!bond_has_slaves(bond)) {
 		/* this is the first slave */
@@ -1198,7 +1200,7 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav
 	/* The slave's address is equal to the address of the bond.
 	 * Search for a spare address in the bond for this slave.
 	 */
-	bond_for_each_slave(bond, tmp_slave1) {
+	bond_for_each_slave(bond, tmp_slave1, iter) {
 		if (!bond_slave_has_mac(bond, tmp_slave1->perm_hwaddr)) {
 			/* no slave has tmp_slave1's perm addr
 			 * as its curr addr
@@ -1249,6 +1251,7 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav
 static int alb_set_mac_address(struct bonding *bond, void *addr)
 {
 	struct slave *slave, *rollback_slave;
+	struct list_head *iter;
 	struct sockaddr sa;
 	char tmp_addr[ETH_ALEN];
 	int res;
@@ -1256,7 +1259,7 @@ static int alb_set_mac_address(struct bonding *bond, void *addr)
 	if (bond->alb_info.rlb_enabled)
 		return 0;
 
-	bond_for_each_slave(bond, slave) {
+	bond_for_each_slave(bond, slave, iter) {
 		/* save net_device's current hw address */
 		memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN);
 
@@ -1276,7 +1279,7 @@ unwind:
 	sa.sa_family = bond->dev->type;
 
 	/* unwind from head to the slave that failed */
-	bond_for_each_slave(bond, rollback_slave) {
+	bond_for_each_slave(bond, rollback_slave, iter) {
 		if (rollback_slave == slave)
 			break;
 		memcpy(tmp_addr, rollback_slave->dev->dev_addr, ETH_ALEN);
@@ -1462,6 +1465,7 @@ void bond_alb_monitor(struct work_struct *work)
 	struct bonding *bond = container_of(work, struct bonding,
 					    alb_work.work);
 	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
+	struct list_head *iter;
 	struct slave *slave;
 
 	read_lock(&bond->lock);
@@ -1484,7 +1488,7 @@ void bond_alb_monitor(struct work_struct *work)
 		 */
 		read_lock(&bond->curr_slave_lock);
 
-		bond_for_each_slave(bond, slave)
+		bond_for_each_slave(bond, slave, iter)
 			alb_send_learning_packets(slave, slave->dev->dev_addr);
 
 		read_unlock(&bond->curr_slave_lock);
@@ -1497,7 +1501,7 @@ void bond_alb_monitor(struct work_struct *work)
 
 		read_lock(&bond->curr_slave_lock);
 
-		bond_for_each_slave(bond, slave) {
+		bond_for_each_slave(bond, slave, iter) {
 			tlb_clear_slave(bond, slave, 1);
 			if (slave == bond->curr_active_slave) {
 				SLAVE_TLB_INFO(slave).load =
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 0a4aa0d..297b910 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -333,9 +333,10 @@ static int bond_vlan_rx_add_vid(struct net_device *bond_dev,
 {
 	struct bonding *bond = netdev_priv(bond_dev);
 	struct slave *slave, *rollback_slave;
+	struct list_head *iter;
 	int res;
 
-	bond_for_each_slave(bond, slave) {
+	bond_for_each_slave(bond, slave, iter) {
 		res = vlan_vid_add(slave->dev, proto, vid);
 		if (res)
 			goto unwind;
@@ -345,7 +346,7 @@ static int bond_vlan_rx_add_vid(struct net_device *bond_dev,
 
 unwind:
 	/* unwind to the slave that failed */
-	bond_for_each_slave(bond, rollback_slave) {
+	bond_for_each_slave(bond, rollback_slave, iter) {
 		if (rollback_slave == slave)
 			break;
 
@@ -364,9 +365,10 @@ static int bond_vlan_rx_kill_vid(struct net_device *bond_dev,
 				 __be16 proto, u16 vid)
 {
 	struct bonding *bond = netdev_priv(bond_dev);
+	struct list_head *iter;
 	struct slave *slave;
 
-	bond_for_each_slave(bond, slave)
+	bond_for_each_slave(bond, slave, iter)
 		vlan_vid_del(slave->dev, proto, vid);
 
 	if (bond_is_lb(bond))
@@ -386,6 +388,7 @@ static int bond_vlan_rx_kill_vid(struct net_device *bond_dev,
  */
 static int bond_set_carrier(struct bonding *bond)
 {
+	struct list_head *iter;
 	struct slave *slave;
 
 	if (!bond_has_slaves(bond))
@@ -394,7 +397,7 @@ static int bond_set_carrier(struct bonding *bond)
 	if (bond->params.mode == BOND_MODE_8023AD)
 		return bond_3ad_set_carrier(bond);
 
-	bond_for_each_slave(bond, slave) {
+	bond_for_each_slave(bond, slave, iter) {
 		if (slave->link == BOND_LINK_UP) {
 			if (!netif_carrier_ok(bond->dev)) {
 				netif_carrier_on(bond->dev);
@@ -526,7 +529,9 @@ static int bond_check_dev_link(struct bonding *bond,
  */
 static int bond_set_promiscuity(struct bonding *bond, int inc)
 {
+	struct list_head *iter;
 	int err = 0;
+
 	if (USES_PRIMARY(bond->params.mode)) {
 		/* write lock already acquired */
 		if (bond->curr_active_slave) {
@@ -536,7 +541,7 @@ static int bond_set_promiscuity(struct bonding *bond, int inc)
 	} else {
 		struct slave *slave;
 
-		bond_for_each_slave(bond, slave) {
+		bond_for_each_slave(bond, slave, iter) {
 			err = dev_set_promiscuity(slave->dev, inc);
 			if (err)
 				return err;
@@ -550,7 +555,9 @@ static int bond_set_promiscuity(struct bonding *bond, int inc)
  */
 static int bond_set_allmulti(struct bonding *bond, int inc)
 {
+	struct list_head *iter;
 	int err = 0;
+
 	if (USES_PRIMARY(bond->params.mode)) {
 		/* write lock already acquired */
 		if (bond->curr_active_slave) {
@@ -560,7 +567,7 @@ static int bond_set_allmulti(struct bonding *bond, int inc)
 	} else {
 		struct slave *slave;
 
-		bond_for_each_slave(bond, slave) {
+		bond_for_each_slave(bond, slave, iter) {
 			err = dev_set_allmulti(slave->dev, inc);
 			if (err)
 				return err;
@@ -1051,9 +1058,10 @@ static void bond_poll_controller(struct net_device *bond_dev)
 static void bond_netpoll_cleanup(struct net_device *bond_dev)
 {
 	struct bonding *bond = netdev_priv(bond_dev);
+	struct list_head *iter;
 	struct slave *slave;
 
-	bond_for_each_slave(bond, slave)
+	bond_for_each_slave(bond, slave, iter)
 		if (IS_UP(slave->dev))
 			slave_disable_netpoll(slave);
 }
@@ -1061,10 +1069,11 @@ static void bond_netpoll_cleanup(struct net_device *bond_dev)
 static int bond_netpoll_setup(struct net_device *dev, struct netpoll_info *ni, gfp_t gfp)
 {
 	struct bonding *bond = netdev_priv(dev);
+	struct list_head *iter;
 	struct slave *slave;
 	int err = 0;
 
-	bond_for_each_slave(bond, slave) {
+	bond_for_each_slave(bond, slave, iter) {
 		err = slave_enable_netpoll(slave);
 		if (err) {
 			bond_netpoll_cleanup(dev);
@@ -1091,8 +1100,9 @@ static void bond_netpoll_cleanup(struct net_device *bond_dev)
 static netdev_features_t bond_fix_features(struct net_device *dev,
 	netdev_features_t features)
 {
-	struct slave *slave;
 	struct bonding *bond = netdev_priv(dev);
+	struct list_head *iter;
+	struct slave *slave;
 	netdev_features_t mask;
 
 	read_lock(&bond->lock);
@@ -1107,7 +1117,7 @@ static netdev_features_t bond_fix_features(struct net_device *dev,
 	features &= ~NETIF_F_ONE_FOR_ALL;
 	features |= NETIF_F_ALL_FOR_ALL;
 
-	bond_for_each_slave(bond, slave) {
+	bond_for_each_slave(bond, slave, iter) {
 		features = netdev_increment_features(features,
 						     slave->dev->features,
 						     mask);
@@ -1125,9 +1135,10 @@ out:
 
 static void bond_compute_features(struct bonding *bond)
 {
-	struct slave *slave;
-	struct net_device *bond_dev = bond->dev;
 	netdev_features_t vlan_features = BOND_VLAN_FEATURES;
+	struct net_device *bond_dev = bond->dev;
+	struct list_head *iter;
+	struct slave *slave;
 	unsigned short max_hard_header_len = ETH_HLEN;
 	unsigned int gso_max_size = GSO_MAX_SIZE;
 	u16 gso_max_segs = GSO_MAX_SEGS;
@@ -1138,7 +1149,7 @@ static void bond_compute_features(struct bonding *bond)
 	if (!bond_has_slaves(bond))
 		goto done;
 
-	bond_for_each_slave(bond, slave) {
+	bond_for_each_slave(bond, slave, iter) {
 		vlan_features = netdev_increment_features(vlan_features,
 			slave->dev->vlan_features, BOND_VLAN_FEATURES);
 
@@ -1993,11 +2004,12 @@ static int bond_info_query(struct net_device *bond_dev, struct ifbond *info)
 static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *info)
 {
 	struct bonding *bond = netdev_priv(bond_dev);
+	struct list_head *iter;
 	int i = 0, res = -ENODEV;
 	struct slave *slave;
 
 	read_lock(&bond->lock);
-	bond_for_each_slave(bond, slave) {
+	bond_for_each_slave(bond, slave, iter) {
 		if (i++ == (int)info->slave_id) {
 			res = 0;
 			strcpy(info->slave_name, slave->dev->name);
@@ -2018,12 +2030,13 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in
 static int bond_miimon_inspect(struct bonding *bond)
 {
 	int link_state, commit = 0;
+	struct list_head *iter;
 	struct slave *slave;
 	bool ignore_updelay;
 
 	ignore_updelay = !bond->curr_active_slave ? true : false;
 
-	bond_for_each_slave(bond, slave) {
+	bond_for_each_slave(bond, slave, iter) {
 		slave->new_link = BOND_LINK_NOCHANGE;
 
 		link_state = bond_check_dev_link(bond, slave->dev, 0);
@@ -2117,9 +2130,10 @@ static int bond_miimon_inspect(struct bonding *bond)
 
 static void bond_miimon_commit(struct bonding *bond)
 {
+	struct list_head *iter;
 	struct slave *slave;
 
-	bond_for_each_slave(bond, slave) {
+	bond_for_each_slave(bond, slave, iter) {
 		switch (slave->new_link) {
 		case BOND_LINK_NOCHANGE:
 			continue;
@@ -2515,6 +2529,7 @@ void bond_loadbalance_arp_mon(struct work_struct *work)
 	struct bonding *bond = container_of(work, struct bonding,
 					    arp_work.work);
 	struct slave *slave, *oldcurrent;
+	struct list_head *iter;
 	int do_failover = 0;
 
 	read_lock(&bond->lock);
@@ -2531,7 +2546,7 @@ void bond_loadbalance_arp_mon(struct work_struct *work)
 	 * TODO: what about up/down delay in arp mode? it wasn't here before
 	 *       so it can wait
 	 */
-	bond_for_each_slave(bond, slave) {
+	bond_for_each_slave(bond, slave, iter) {
 		unsigned long trans_start = dev_trans_start(slave->dev);
 
 		if (slave->link != BOND_LINK_UP) {
@@ -2622,10 +2637,11 @@ re_arm:
 static int bond_ab_arp_inspect(struct bonding *bond)
 {
 	unsigned long trans_start, last_rx;
+	struct list_head *iter;
 	struct slave *slave;
 	int commit = 0;
 
-	bond_for_each_slave(bond, slave) {
+	bond_for_each_slave(bond, slave, iter) {
 		slave->new_link = BOND_LINK_NOCHANGE;
 		last_rx = slave_last_rx(bond, slave);
 
@@ -2692,9 +2708,10 @@ static int bond_ab_arp_inspect(struct bonding *bond)
 static void bond_ab_arp_commit(struct bonding *bond)
 {
 	unsigned long trans_start;
+	struct list_head *iter;
 	struct slave *slave;
 
-	bond_for_each_slave(bond, slave) {
+	bond_for_each_slave(bond, slave, iter) {
 		switch (slave->new_link) {
 		case BOND_LINK_NOCHANGE:
 			continue;
@@ -3158,13 +3175,14 @@ static void bond_work_cancel_all(struct bonding *bond)
 static int bond_open(struct net_device *bond_dev)
 {
 	struct bonding *bond = netdev_priv(bond_dev);
+	struct list_head *iter;
 	struct slave *slave;
 
 	/* reset slave->backup and slave->inactive */
 	read_lock(&bond->lock);
 	if (bond_has_slaves(bond)) {
 		read_lock(&bond->curr_slave_lock);
-		bond_for_each_slave(bond, slave) {
+		bond_for_each_slave(bond, slave, iter) {
 			if ((bond->params.mode == BOND_MODE_ACTIVEBACKUP)
 				&& (slave != bond->curr_active_slave)) {
 				bond_set_slave_inactive_flags(slave);
@@ -3231,12 +3249,13 @@ static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev,
 {
 	struct bonding *bond = netdev_priv(bond_dev);
 	struct rtnl_link_stats64 temp;
+	struct list_head *iter;
 	struct slave *slave;
 
 	memset(stats, 0, sizeof(*stats));
 
 	read_lock_bh(&bond->lock);
-	bond_for_each_slave(bond, slave) {
+	bond_for_each_slave(bond, slave, iter) {
 		const struct rtnl_link_stats64 *sstats =
 			dev_get_stats(slave->dev, &temp);
 
@@ -3403,6 +3422,7 @@ static void bond_change_rx_flags(struct net_device *bond_dev, int change)
 static void bond_set_rx_mode(struct net_device *bond_dev)
 {
 	struct bonding *bond = netdev_priv(bond_dev);
+	struct list_head *iter;
 	struct slave *slave;
 
 	ASSERT_RTNL();
@@ -3414,7 +3434,7 @@ static void bond_set_rx_mode(struct net_device *bond_dev)
 			dev_mc_sync(slave->dev, bond_dev);
 		}
 	} else {
-		bond_for_each_slave(bond, slave) {
+		bond_for_each_slave(bond, slave, iter) {
 			dev_uc_sync_multiple(slave->dev, bond_dev);
 			dev_mc_sync_multiple(slave->dev, bond_dev);
 		}
@@ -3482,6 +3502,7 @@ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu)
 {
 	struct bonding *bond = netdev_priv(bond_dev);
 	struct slave *slave, *rollback_slave;
+	struct list_head *iter;
 	int res = 0;
 
 	pr_debug("bond=%p, name=%s, new_mtu=%d\n", bond,
@@ -3502,7 +3523,7 @@ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu)
 	 * call to the base driver.
 	 */
 
-	bond_for_each_slave(bond, slave) {
+	bond_for_each_slave(bond, slave, iter) {
 		pr_debug("s %p s->p %p c_m %p\n",
 			 slave,
 			 bond_prev_slave(bond, slave),
@@ -3530,7 +3551,7 @@ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu)
 
 unwind:
 	/* unwind from head to the slave that failed */
-	bond_for_each_slave(bond, rollback_slave) {
+	bond_for_each_slave(bond, rollback_slave, iter) {
 		int tmp_res;
 
 		if (rollback_slave == slave);
@@ -3558,6 +3579,7 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr)
 	struct bonding *bond = netdev_priv(bond_dev);
 	struct slave *slave, *rollback_slave;
 	struct sockaddr *sa = addr, tmp_sa;
+	struct list_head *iter;
 	int res = 0;
 
 	if (bond->params.mode == BOND_MODE_ALB)
@@ -3591,7 +3613,7 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr)
 	 * call to the base driver.
 	 */
 
-	bond_for_each_slave(bond, slave) {
+	bond_for_each_slave(bond, slave, iter) {
 		const struct net_device_ops *slave_ops = slave->dev->netdev_ops;
 		pr_debug("slave %p %s\n", slave, slave->dev->name);
 
@@ -3623,7 +3645,7 @@ unwind:
 	tmp_sa.sa_family = bond_dev->type;
 
 	/* unwind from head to the slave that failed */
-	bond_for_each_slave(bond, rollback_slave) {
+	bond_for_each_slave(bond, rollback_slave, iter) {
 		int tmp_res;
 
 		if (rollback_slave == slave)
@@ -3651,11 +3673,12 @@ unwind:
  */
 void bond_xmit_slave_id(struct bonding *bond, struct sk_buff *skb, int slave_id)
 {
+	struct list_head *iter;
 	struct slave *slave;
 	int i = slave_id;
 
 	/* Here we start from the slave with slave_id */
-	bond_for_each_slave_rcu(bond, slave) {
+	bond_for_each_slave_rcu(bond, slave, iter) {
 		if (--i < 0) {
 			if (slave_can_tx(slave)) {
 				bond_dev_queue_xmit(bond, skb, slave->dev);
@@ -3666,7 +3689,7 @@ void bond_xmit_slave_id(struct bonding *bond, struct sk_buff *skb, int slave_id)
 
 	/* Here we start from the first slave up to slave_id */
 	i = slave_id;
-	bond_for_each_slave_rcu(bond, slave) {
+	bond_for_each_slave_rcu(bond, slave, iter) {
 		if (--i < 0)
 			break;
 		if (slave_can_tx(slave)) {
@@ -3743,8 +3766,9 @@ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev)
 {
 	struct bonding *bond = netdev_priv(bond_dev);
 	struct slave *slave = NULL;
+	struct list_head *iter;
 
-	bond_for_each_slave_rcu(bond, slave) {
+	bond_for_each_slave_rcu(bond, slave, iter) {
 		if (bond_is_last_slave(bond, slave))
 			break;
 		if (IS_UP(slave->dev) && slave->link == BOND_LINK_UP) {
@@ -3793,13 +3817,14 @@ static inline int bond_slave_override(struct bonding *bond,
 {
 	struct slave *slave = NULL;
 	struct slave *check_slave;
+	struct list_head *iter;
 	int res = 1;
 
 	if (!skb->queue_mapping)
 		return 1;
 
 	/* Find out if any slaves have the same mapping as this skb. */
-	bond_for_each_slave_rcu(bond, check_slave) {
+	bond_for_each_slave_rcu(bond, check_slave, iter) {
 		if (check_slave->queue_id == skb->queue_mapping) {
 			slave = check_slave;
 			break;
@@ -3931,6 +3956,7 @@ static int bond_ethtool_get_settings(struct net_device *bond_dev,
 {
 	struct bonding *bond = netdev_priv(bond_dev);
 	unsigned long speed = 0;
+	struct list_head *iter;
 	struct slave *slave;
 
 	ecmd->duplex = DUPLEX_UNKNOWN;
@@ -3942,7 +3968,7 @@ static int bond_ethtool_get_settings(struct net_device *bond_dev,
 	 * this is an accurate maximum.
 	 */
 	read_lock(&bond->lock);
-	bond_for_each_slave(bond, slave) {
+	bond_for_each_slave(bond, slave, iter) {
 		if (SLAVE_IS_OK(slave)) {
 			if (slave->speed != SPEED_UNKNOWN)
 				speed += slave->speed;
diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c
index 20a6ee2..7af5646 100644
--- a/drivers/net/bonding/bond_procfs.c
+++ b/drivers/net/bonding/bond_procfs.c
@@ -10,8 +10,9 @@ static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos)
 	__acquires(&bond->lock)
 {
 	struct bonding *bond = seq->private;
-	loff_t off = 0;
+	struct list_head *iter;
 	struct slave *slave;
+	loff_t off = 0;
 
 	/* make sure the bond won't be taken away */
 	rcu_read_lock();
@@ -20,7 +21,7 @@ static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos)
 	if (*pos == 0)
 		return SEQ_START_TOKEN;
 
-	bond_for_each_slave(bond, slave)
+	bond_for_each_slave(bond, slave, iter)
 		if (++off == *pos)
 			return slave;
 
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 8721dcb..b4ae9f5 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -175,11 +175,12 @@ static ssize_t bonding_show_slaves(struct device *d,
 				   struct device_attribute *attr, char *buf)
 {
 	struct bonding *bond = to_bond(d);
+	struct list_head *iter;
 	struct slave *slave;
 	int res = 0;
 
 	read_lock(&bond->lock);
-	bond_for_each_slave(bond, slave) {
+	bond_for_each_slave(bond, slave, iter) {
 		if (res > (PAGE_SIZE - IFNAMSIZ)) {
 			/* not enough space for another interface name */
 			if ((PAGE_SIZE - res) > 10)
@@ -602,6 +603,7 @@ static ssize_t bonding_store_arp_targets(struct device *d,
 					 const char *buf, size_t count)
 {
 	struct bonding *bond = to_bond(d);
+	struct list_head *iter;
 	struct slave *slave;
 	__be32 newtarget, *targets;
 	unsigned long *targets_rx;
@@ -634,7 +636,7 @@ static ssize_t bonding_store_arp_targets(struct device *d,
 			 &newtarget);
 		/* not to race with bond_arp_rcv */
 		write_lock_bh(&bond->lock);
-		bond_for_each_slave(bond, slave)
+		bond_for_each_slave(bond, slave, iter)
 			slave->target_last_arp_rx[ind] = jiffies;
 		targets[ind] = newtarget;
 		write_unlock_bh(&bond->lock);
@@ -660,7 +662,7 @@ static ssize_t bonding_store_arp_targets(struct device *d,
 			&newtarget);
 
 		write_lock_bh(&bond->lock);
-		bond_for_each_slave(bond, slave) {
+		bond_for_each_slave(bond, slave, iter) {
 			targets_rx = slave->target_last_arp_rx;
 			j = ind;
 			for (; (j < BOND_MAX_ARP_TARGETS-1) && targets[j+1]; j++)
@@ -1052,6 +1054,7 @@ static ssize_t bonding_store_primary(struct device *d,
 				     const char *buf, size_t count)
 {
 	struct bonding *bond = to_bond(d);
+	struct list_head *iter;
 	char ifname[IFNAMSIZ];
 	struct slave *slave;
 
@@ -1079,7 +1082,7 @@ static ssize_t bonding_store_primary(struct device *d,
 		goto out;
 	}
 
-	bond_for_each_slave(bond, slave) {
+	bond_for_each_slave(bond, slave, iter) {
 		if (strncmp(slave->dev->name, ifname, IFNAMSIZ) == 0) {
 			pr_info("%s: Setting %s as primary slave.\n",
 				bond->dev->name, slave->dev->name);
@@ -1227,6 +1230,7 @@ static ssize_t bonding_store_active_slave(struct device *d,
 {
 	struct slave *slave, *old_active, *new_active;
 	struct bonding *bond = to_bond(d);
+	struct list_head *iter;
 	char ifname[IFNAMSIZ];
 
 	if (!rtnl_trylock())
@@ -1254,7 +1258,7 @@ static ssize_t bonding_store_active_slave(struct device *d,
 		goto out;
 	}
 
-	bond_for_each_slave(bond, slave) {
+	bond_for_each_slave(bond, slave, iter) {
 		if (strncmp(slave->dev->name, ifname, IFNAMSIZ) == 0) {
 			old_active = bond->curr_active_slave;
 			new_active = slave;
@@ -1434,6 +1438,7 @@ static ssize_t bonding_show_queue_id(struct device *d,
 				     char *buf)
 {
 	struct bonding *bond = to_bond(d);
+	struct list_head *iter;
 	struct slave *slave;
 	int res = 0;
 
@@ -1441,7 +1446,7 @@ static ssize_t bonding_show_queue_id(struct device *d,
 		return restart_syscall();
 
 	read_lock(&bond->lock);
-	bond_for_each_slave(bond, slave) {
+	bond_for_each_slave(bond, slave, iter) {
 		if (res > (PAGE_SIZE - IFNAMSIZ - 6)) {
 			/* not enough space for another interface_name:queue_id pair */
 			if ((PAGE_SIZE - res) > 10)
@@ -1470,6 +1475,7 @@ static ssize_t bonding_store_queue_id(struct device *d,
 {
 	struct slave *slave, *update_slave;
 	struct bonding *bond = to_bond(d);
+	struct list_head *iter;
 	u16 qid;
 	int ret = count;
 	char *delim;
@@ -1506,7 +1512,7 @@ static ssize_t bonding_store_queue_id(struct device *d,
 
 	/* Search for thes slave and check for duplicate qids */
 	update_slave = NULL;
-	bond_for_each_slave(bond, slave) {
+	bond_for_each_slave(bond, slave, iter) {
 		if (sdev == slave->dev)
 			/*
 			 * We don't need to check the matching
@@ -1560,6 +1566,7 @@ static ssize_t bonding_store_slaves_active(struct device *d,
 {
 	struct bonding *bond = to_bond(d);
 	int new_value, ret = count;
+	struct list_head *iter;
 	struct slave *slave;
 
 	if (sscanf(buf, "%d", &new_value) != 1) {
@@ -1582,7 +1589,7 @@ static ssize_t bonding_store_slaves_active(struct device *d,
 	}
 
 	read_lock(&bond->lock);
-	bond_for_each_slave(bond, slave) {
+	bond_for_each_slave(bond, slave, iter) {
 		if (!bond_is_active_slave(slave)) {
 			if (new_value)
 				slave->inactive = 0;
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 8c11f96..b6dc9db 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -112,15 +112,16 @@
  * bond_for_each_slave - iterate over all slaves
  * @bond:	the bond holding this list
  * @pos:	current slave
+ * @iter:	list_head * iterator
  *
  * Caller must hold bond->lock
  */
-#define bond_for_each_slave(bond, pos) \
-	list_for_each_entry(pos, &(bond)->slave_list, list)
+#define bond_for_each_slave(bond, pos, iter) \
+	netdev_for_each_lower_neigh_private((bond)->dev, pos, iter)
 
 /* Caller must have rcu_read_lock */
-#define bond_for_each_slave_rcu(bond, pos) \
-	list_for_each_entry_rcu(pos, &(bond)->slave_list, list)
+#define bond_for_each_slave_rcu(bond, pos, iter) \
+	netdev_for_each_lower_neigh_private_rcu((bond)->dev, pos, iter)
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
 extern atomic_t netpoll_block_tx;
@@ -493,9 +494,10 @@ static inline void bond_destroy_proc_dir(struct bond_net *bn)
 static inline struct slave *bond_slave_has_mac(struct bonding *bond,
 					       const u8 *mac)
 {
+	struct list_head *iter;
 	struct slave *tmp;
 
-	bond_for_each_slave(bond, tmp)
+	bond_for_each_slave(bond, tmp, iter)
 		if (ether_addr_equal_64bits(mac, tmp->dev->dev_addr))
 			return tmp;
 
-- 
1.8.4

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH RFC net-next 14/21] net: add netdev_for_each_lower_neigh_private_continue()
  2013-09-02 21:39 [PATCH RFC net-next 0/21] bonding: use neighbours instead of own lists Veaceslav Falico
                   ` (12 preceding siblings ...)
  2013-09-02 21:39 ` [PATCH RFC net-next 13/21] bonding: make bond_for_each_slave() use lower neighbour's private Veaceslav Falico
@ 2013-09-02 21:39 ` Veaceslav Falico
  2013-09-02 21:39 ` [PATCH RFC net-next 15/21] bonding: use neighbour list for bond_for_each_slave_continue() Veaceslav Falico
                   ` (6 subsequent siblings)
  20 siblings, 0 replies; 27+ messages in thread
From: Veaceslav Falico @ 2013-09-02 21:39 UTC (permalink / raw)
  To: netdev
  Cc: Veaceslav Falico, David S. Miller, Eric Dumazet, Jiri Pirko,
	Alexander Duyck

This macro allows going through the neighbour lower list private's from a
specific position and till it doesn't hit the same position again.

For that, two functions are needed:

netdev_lower_neigh_set_iter_per_private(dev, iter, from_priv) - which
searches for from_priv and, if found, sets the iter to the correct
position, returning from_priv.

netdev_lower_neigh_get_next_private_to(dev, iter, from_priv) - gets the
next ->private (and skips the list head), or if the next private equals
from_priv - returns NULL. Also returns NULL if the ->private is NULL, to
catch the case if the list doesn't have any elements.

CC: "David S. Miller" <davem@davemloft.net>
CC: Eric Dumazet <edumazet@google.com>
CC: Jiri Pirko <jiri@resnulli.us>
CC: Alexander Duyck <alexander.h.duyck@intel.com>
Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
---
 include/linux/netdevice.h | 14 +++++++++++
 net/core/dev.c            | 62 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 76 insertions(+)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 1a149ef..20afdf98 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2788,6 +2788,20 @@ extern struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev,
 	     updev; \
 	     updev = netdev_upper_get_next_dev_rcu(dev, &(iter)))
 
+extern void *netdev_lower_neigh_set_iter_per_private(struct net_device *dev,
+						     struct list_head **iter,
+						     void *private);
+extern void *netdev_lower_neigh_get_next_private_to(struct net_device *dev,
+						    struct list_head **iter,
+						    void *to);
+
+#define netdev_for_each_lower_neigh_private_continue(dev, priv, from_priv, iter) \
+	for (priv = netdev_lower_neigh_set_iter_per_private(dev, &(iter), \
+							    from_priv);   \
+	     priv; \
+	     priv = netdev_lower_neigh_get_next_private_to(dev, &(iter),  \
+							   from_priv))
+
 extern void *netdev_lower_neigh_get_next_private(struct net_device *dev,
 						 struct list_head **iter);
 extern void *netdev_lower_neigh_get_next_private_rcu(struct net_device *dev,
diff --git a/net/core/dev.c b/net/core/dev.c
index 55f8ac4..1b9862b 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4555,6 +4555,68 @@ struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev,
 }
 EXPORT_SYMBOL(netdev_upper_get_next_dev_rcu);
 
+/* netdev_lower_neigh_set_iter_per_private - Set the iter to reflect the
+ *					     position of the ->private
+ * @dev: device
+ * @iter: iter to be set
+ * @private: private to be found
+ *
+ * Iterates through lower neighbours, searching for private. When found,
+ * sets the iter to the ->list. Returns private or NULL if not found. User
+ * must hold RTNL lock or make sure that the list isn't modified.
+ */
+void *netdev_lower_neigh_set_iter_per_private(struct net_device *dev,
+					      struct list_head **iter,
+					      void *private)
+{
+	struct netdev_adjacent *lower;
+
+	list_for_each_entry(lower, &dev->neighbour_dev_list.lower, list)
+		if (lower->private == private)
+			break;
+
+	if (&lower->list == &dev->neighbour_dev_list.lower)
+		return NULL;
+
+	*iter = &lower->list;
+
+	return private;
+}
+EXPORT_SYMBOL(netdev_lower_neigh_set_iter_per_private);
+
+/* netdev_lower_neigh_get_next_private_to - Get the next ->private from the
+ *					    lower neighbour list, stop at to
+ * @dev: device
+ * @iter: list_head ** of the current position
+ * @to: if private == to then stop
+ *
+ * Gets the next netdev_adjacent->private from the dev's lower neighbour
+ * list, starting from iter position. The caller must hold either hold the
+ * RTNL lock or its own locking that guarantees that the neighbour lower
+ * list will remain unchainged. Stops when private == to or when it hits a
+ * NULL private.
+ */
+void *netdev_lower_neigh_get_next_private_to(struct net_device *dev,
+					     struct list_head **iter,
+					     void *to)
+{
+	struct netdev_adjacent *lower;
+
+	lower = list_entry((*iter)->next, struct netdev_adjacent, list);
+
+	if (&lower->list == &dev->neighbour_dev_list.lower)
+		lower = list_entry(lower->list.next, struct netdev_adjacent,
+				   list);
+
+	if (lower->private == to || !lower->private)
+		return NULL;
+
+	*iter = &lower->list;
+
+	return lower->private;
+}
+EXPORT_SYMBOL(netdev_lower_neigh_get_next_private_to);
+
 /* netdev_lower_neigh_get_next_private - Get the next ->private from the
  *					 lower neighbour list
  * @dev: device
-- 
1.8.4

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH RFC net-next 15/21] bonding: use neighbour list for bond_for_each_slave_continue()
  2013-09-02 21:39 [PATCH RFC net-next 0/21] bonding: use neighbours instead of own lists Veaceslav Falico
                   ` (13 preceding siblings ...)
  2013-09-02 21:39 ` [PATCH RFC net-next 14/21] net: add netdev_for_each_lower_neigh_private_continue() Veaceslav Falico
@ 2013-09-02 21:39 ` Veaceslav Falico
  2013-09-02 21:39 ` [PATCH RFC net-next 16/21] net: add a possibility to get private from netdev_adjacent->list Veaceslav Falico
                   ` (5 subsequent siblings)
  20 siblings, 0 replies; 27+ messages in thread
From: Veaceslav Falico @ 2013-09-02 21:39 UTC (permalink / raw)
  To: netdev; +Cc: Veaceslav Falico, Jay Vosburgh, Andy Gospodarek

Use netdev_for_each_lower_neigh_private_continue() macro to iterate through
bonding slaves. It needs a struct list_head *, so add where needed.

CC: Jay Vosburgh <fubar@us.ibm.com>
CC: Andy Gospodarek <andy@greyhouse.net>
Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
---
 drivers/net/bonding/bond_3ad.c  | 3 +--
 drivers/net/bonding/bond_alb.c  | 4 ++--
 drivers/net/bonding/bond_main.c | 8 ++++----
 drivers/net/bonding/bonding.h   | 7 +++----
 4 files changed, 10 insertions(+), 12 deletions(-)

diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index 7430cbb..325ce90 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -2423,7 +2423,6 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
 	int slave_agg_no;
 	int slaves_in_agg;
 	int agg_id;
-	int i;
 	struct ad_info ad_info;
 	int res = 1;
 
@@ -2463,7 +2462,7 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
 
 	start_at = slave;
 
-	bond_for_each_slave_from(bond, slave, i, start_at) {
+	bond_for_each_slave_from(bond, slave, iter, start_at) {
 		int slave_agg_id = 0;
 		struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator;
 
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 738eeae..9633ca2 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -384,7 +384,7 @@ static struct slave *rlb_next_rx_slave(struct bonding *bond)
 {
 	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
 	struct slave *rx_slave, *slave, *start_at;
-	int i = 0;
+	struct list_head *iter;
 
 	if (bond_info->next_rx_slave)
 		start_at = bond_info->next_rx_slave;
@@ -393,7 +393,7 @@ static struct slave *rlb_next_rx_slave(struct bonding *bond)
 
 	rx_slave = NULL;
 
-	bond_for_each_slave_from(bond, slave, i, start_at) {
+	bond_for_each_slave_from(bond, slave, iter, start_at) {
 		if (SLAVE_IS_OK(slave)) {
 			if (!rx_slave) {
 				rx_slave = slave;
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 297b910..59814c9 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -792,8 +792,8 @@ static struct slave *bond_find_best_slave(struct bonding *bond)
 {
 	struct slave *new_active, *old_active;
 	struct slave *bestslave = NULL;
+	struct list_head *iter;
 	int mintime = bond->params.updelay;
-	int i;
 
 	new_active = bond->curr_active_slave;
 
@@ -812,7 +812,7 @@ static struct slave *bond_find_best_slave(struct bonding *bond)
 	/* remember where to stop iterating over the slaves */
 	old_active = new_active;
 
-	bond_for_each_slave_from(bond, new_active, i, old_active) {
+	bond_for_each_slave_from(bond, new_active, iter, old_active) {
 		if (new_active->link == BOND_LINK_UP) {
 			return new_active;
 		} else if (new_active->link == BOND_LINK_BACK &&
@@ -2783,7 +2783,7 @@ do_failover:
 static void bond_ab_arp_probe(struct bonding *bond)
 {
 	struct slave *slave, *next_slave;
-	int i;
+	struct list_head *iter;
 
 	read_lock(&bond->curr_slave_lock);
 
@@ -2815,7 +2815,7 @@ static void bond_ab_arp_probe(struct bonding *bond)
 
 	/* search for next candidate */
 	next_slave = bond_next_slave(bond, bond->current_arp_slave);
-	bond_for_each_slave_from(bond, slave, i, next_slave) {
+	bond_for_each_slave_from(bond, slave, iter, next_slave) {
 		if (IS_UP(slave->dev)) {
 			slave->link = BOND_LINK_BACK;
 			bond_set_slave_active_flags(slave);
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index b6dc9db..583077d 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -99,14 +99,13 @@
  * bond_for_each_slave_from - iterate the slaves list from a starting point
  * @bond:	the bond holding this list.
  * @pos:	current slave.
- * @cnt:	counter for max number of moves
+ * @iter:	list_head * iterator
  * @start:	starting point.
  *
  * Caller must hold bond->lock
  */
-#define bond_for_each_slave_from(bond, pos, cnt, start) \
-	for (cnt = 0, pos = start; pos && cnt < (bond)->slave_cnt; \
-	     cnt++, pos = bond_next_slave(bond, pos))
+#define bond_for_each_slave_from(bond, pos, iter, start) \
+	netdev_for_each_lower_neigh_private_continue((bond)->dev, pos, start, iter)
 
 /**
  * bond_for_each_slave - iterate over all slaves
-- 
1.8.4

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH RFC net-next 16/21] net: add a possibility to get private from netdev_adjacent->list
  2013-09-02 21:39 [PATCH RFC net-next 0/21] bonding: use neighbours instead of own lists Veaceslav Falico
                   ` (14 preceding siblings ...)
  2013-09-02 21:39 ` [PATCH RFC net-next 15/21] bonding: use neighbour list for bond_for_each_slave_continue() Veaceslav Falico
@ 2013-09-02 21:39 ` Veaceslav Falico
  2013-09-02 21:39 ` [PATCH RFC net-next 17/21] bonding: convert first/last slave logic to use neighbours Veaceslav Falico
                   ` (4 subsequent siblings)
  20 siblings, 0 replies; 27+ messages in thread
From: Veaceslav Falico @ 2013-09-02 21:39 UTC (permalink / raw)
  To: netdev
  Cc: Veaceslav Falico, David S. Miller, Eric Dumazet, Jiri Pirko,
	Alexander Duyck

It will be useful to get first/last element.

CC: "David S. Miller" <davem@davemloft.net>
CC: Eric Dumazet <edumazet@google.com>
CC: Jiri Pirko <jiri@resnulli.us>
CC: Alexander Duyck <alexander.h.duyck@intel.com>
Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
---
 include/linux/netdevice.h |  1 +
 net/core/dev.c            | 10 ++++++++++
 2 files changed, 11 insertions(+)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 20afdf98..bde2244 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2819,6 +2819,7 @@ extern void *netdev_lower_neigh_get_next_private_rcu(struct net_device *dev,
 	     priv; \
 	     priv = netdev_lower_neigh_get_next_private_rcu(dev, &(iter)))
 
+extern void *netdev_adjacent_get_private(struct list_head *adj_list);
 extern struct net_device *netdev_master_upper_dev_get(struct net_device *dev);
 extern struct net_device *netdev_master_upper_dev_get_rcu(struct net_device *dev);
 extern int netdev_upper_dev_link(struct net_device *dev,
diff --git a/net/core/dev.c b/net/core/dev.c
index 1b9862b..6df11a0 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4530,6 +4530,16 @@ struct net_device *netdev_master_upper_dev_get(struct net_device *dev)
 }
 EXPORT_SYMBOL(netdev_master_upper_dev_get);
 
+void *netdev_adjacent_get_private(struct list_head *adj_list)
+{
+	struct netdev_adjacent *adj;
+
+	adj = list_entry(adj_list, struct netdev_adjacent, list);
+
+	return adj->private;
+}
+EXPORT_SYMBOL(netdev_adjacent_get_private);
+
 /* netdev_upper_get_next_dev_rcu - Get the next dev from upper list
  * @dev: device
  * @iter: list_head ** of the current position
-- 
1.8.4

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH RFC net-next 17/21] bonding: convert first/last slave logic to use neighbours
  2013-09-02 21:39 [PATCH RFC net-next 0/21] bonding: use neighbours instead of own lists Veaceslav Falico
                   ` (15 preceding siblings ...)
  2013-09-02 21:39 ` [PATCH RFC net-next 16/21] net: add a possibility to get private from netdev_adjacent->list Veaceslav Falico
@ 2013-09-02 21:39 ` Veaceslav Falico
  2013-09-02 21:39 ` [PATCH RFC net-next 18/21] net: add a function to get the next/prev private Veaceslav Falico
                   ` (3 subsequent siblings)
  20 siblings, 0 replies; 27+ messages in thread
From: Veaceslav Falico @ 2013-09-02 21:39 UTC (permalink / raw)
  To: netdev; +Cc: Veaceslav Falico, Jay Vosburgh, Andy Gospodarek

For that, use netdev_adjacent_get_private(list_head) on bond's lower
neighbour list members.

CC: Jay Vosburgh <fubar@us.ibm.com>
CC: Andy Gospodarek <andy@greyhouse.net>
Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
---
 drivers/net/bonding/bonding.h | 17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 583077d..6731281 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -72,19 +72,24 @@
 	res; })
 
 /* slave list primitives */
-#define bond_has_slaves(bond) !list_empty(&(bond)->dev->neighbour_dev_list.lower)
+#define bond_slave_list(bond) (&(bond)->dev->neighbour_dev_list.lower)
+
+#define bond_has_slaves(bond) !list_empty(bond_slave_list(bond))
 
 #define bond_to_slave(ptr) list_entry(ptr, struct slave, list)
 
 /* IMPORTANT: bond_first/last_slave can return NULL in case of an empty list */
 #define bond_first_slave(bond) \
-	list_first_entry_or_null(&(bond)->slave_list, struct slave, list)
+	(bond_has_slaves(bond) ? \
+		netdev_adjacent_get_private(bond_slave_list(bond)->next) : \
+		NULL)
 #define bond_last_slave(bond) \
-	(list_empty(&(bond)->slave_list) ? NULL : \
-					   bond_to_slave((bond)->slave_list.prev))
+	(bond_has_slaves(bond) ? \
+		netdev_adjacent_get_private(bond_slave_list(bond)->prev) : \
+		NULL)
 
-#define bond_is_first_slave(bond, pos) ((pos)->list.prev == &(bond)->slave_list)
-#define bond_is_last_slave(bond, pos) ((pos)->list.next == &(bond)->slave_list)
+#define bond_is_first_slave(bond, pos) (pos == bond_first_slave(bond))
+#define bond_is_last_slave(bond, pos) (pos == bond_last_slave(bond))
 
 /* Since bond_first/last_slave can return NULL, these can return NULL too */
 #define bond_next_slave(bond, pos) \
-- 
1.8.4

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH RFC net-next 18/21] net: add a function to get the next/prev private
  2013-09-02 21:39 [PATCH RFC net-next 0/21] bonding: use neighbours instead of own lists Veaceslav Falico
                   ` (16 preceding siblings ...)
  2013-09-02 21:39 ` [PATCH RFC net-next 17/21] bonding: convert first/last slave logic to use neighbours Veaceslav Falico
@ 2013-09-02 21:39 ` Veaceslav Falico
  2013-09-03  8:10   ` Jiri Pirko
  2013-09-02 21:39 ` [PATCH RFC net-next 19/21] bonding: use neighbours for bond_next/prev_slave() Veaceslav Falico
                   ` (2 subsequent siblings)
  20 siblings, 1 reply; 27+ messages in thread
From: Veaceslav Falico @ 2013-09-02 21:39 UTC (permalink / raw)
  To: netdev
  Cc: Veaceslav Falico, David S. Miller, Eric Dumazet, Jiri Pirko,
	Alexander Duyck

The boolean flag specifies which direction to go.

CC: "David S. Miller" <davem@davemloft.net>
CC: Eric Dumazet <edumazet@google.com>
CC: Jiri Pirko <jiri@resnulli.us>
CC: Alexander Duyck <alexander.h.duyck@intel.com>
Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
---
 include/linux/netdevice.h |  2 ++
 net/core/dev.c            | 24 ++++++++++++++++++++++++
 2 files changed, 26 insertions(+)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index bde2244..a112ccc 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2835,6 +2835,8 @@ extern void *netdev_lower_dev_get_private_rcu(struct net_device *dev,
 					      struct net_device *lower_dev);
 extern void *netdev_lower_dev_get_private(struct net_device *dev,
 					  struct net_device *lower_dev);
+extern void *netdev_lower_dev_get_next_private(struct net_device *dev,
+					       void *private, bool prev);
 extern int skb_checksum_help(struct sk_buff *skb);
 extern struct sk_buff *__skb_gso_segment(struct sk_buff *skb,
 	netdev_features_t features, bool tx_path);
diff --git a/net/core/dev.c b/net/core/dev.c
index 6df11a0..c694059 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -5163,6 +5163,30 @@ void *netdev_lower_dev_get_private(struct net_device *dev,
 }
 EXPORT_SYMBOL(netdev_lower_dev_get_private);
 
+extern void *netdev_lower_dev_get_next_private(struct net_device *dev,
+					       void *private, bool prev)
+{
+	struct netdev_adjacent *lower;
+
+	list_for_each_entry(lower, &dev->neighbour_dev_list.lower, list)
+		if (lower->private == private)
+			break;
+
+	if (&lower->list == &dev->neighbour_dev_list.lower)
+		return NULL;
+
+	lower = prev ? list_entry(lower->list.prev, struct netdev_adjacent, list) :
+		       list_entry(lower->list.next, struct netdev_adjacent, list);
+	if (&lower->list != &dev->neighbour_dev_list.lower)
+		return lower->private;
+
+	lower = prev ? list_entry(lower->list.prev, struct netdev_adjacent, list) :
+		       list_entry(lower->list.next, struct netdev_adjacent, list);
+
+	return lower->private;
+}
+EXPORT_SYMBOL(netdev_lower_dev_get_next_private);
+
 static void dev_change_rx_flags(struct net_device *dev, int flags)
 {
 	const struct net_device_ops *ops = dev->netdev_ops;
-- 
1.8.4

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH RFC net-next 19/21] bonding: use neighbours for bond_next/prev_slave()
  2013-09-02 21:39 [PATCH RFC net-next 0/21] bonding: use neighbours instead of own lists Veaceslav Falico
                   ` (17 preceding siblings ...)
  2013-09-02 21:39 ` [PATCH RFC net-next 18/21] net: add a function to get the next/prev private Veaceslav Falico
@ 2013-09-02 21:39 ` Veaceslav Falico
  2013-09-02 21:39 ` [PATCH RFC net-next 20/21] bonding: use bond_for_each_slave() in bond_uninit() Veaceslav Falico
  2013-09-02 21:39 ` [PATCH RFC net-next 21/21] bonding: remove slave lists Veaceslav Falico
  20 siblings, 0 replies; 27+ messages in thread
From: Veaceslav Falico @ 2013-09-02 21:39 UTC (permalink / raw)
  To: netdev; +Cc: Veaceslav Falico, Jay Vosburgh, Andy Gospodarek

Use netdev_lower_dev_get_next_private(), it will return NULL in case the
list is empty, so no need to verify.

CC: Jay Vosburgh <fubar@us.ibm.com>
CC: Andy Gospodarek <andy@greyhouse.net>
Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
---
 drivers/net/bonding/bonding.h | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 6731281..b8047f3 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -76,8 +76,6 @@
 
 #define bond_has_slaves(bond) !list_empty(bond_slave_list(bond))
 
-#define bond_to_slave(ptr) list_entry(ptr, struct slave, list)
-
 /* IMPORTANT: bond_first/last_slave can return NULL in case of an empty list */
 #define bond_first_slave(bond) \
 	(bond_has_slaves(bond) ? \
@@ -93,12 +91,10 @@
 
 /* Since bond_first/last_slave can return NULL, these can return NULL too */
 #define bond_next_slave(bond, pos) \
-	(bond_is_last_slave(bond, pos) ? bond_first_slave(bond) : \
-					 bond_to_slave((pos)->list.next))
+	netdev_lower_dev_get_next_private((bond)->dev, pos, false)
 
 #define bond_prev_slave(bond, pos) \
-	(bond_is_first_slave(bond, pos) ? bond_last_slave(bond) : \
-					  bond_to_slave((pos)->list.prev))
+	netdev_lower_dev_get_next_private((bond)->dev, pos, true)
 
 /**
  * bond_for_each_slave_from - iterate the slaves list from a starting point
-- 
1.8.4

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH RFC net-next 20/21] bonding: use bond_for_each_slave() in bond_uninit()
  2013-09-02 21:39 [PATCH RFC net-next 0/21] bonding: use neighbours instead of own lists Veaceslav Falico
                   ` (18 preceding siblings ...)
  2013-09-02 21:39 ` [PATCH RFC net-next 19/21] bonding: use neighbours for bond_next/prev_slave() Veaceslav Falico
@ 2013-09-02 21:39 ` Veaceslav Falico
  2013-09-02 21:39 ` [PATCH RFC net-next 21/21] bonding: remove slave lists Veaceslav Falico
  20 siblings, 0 replies; 27+ messages in thread
From: Veaceslav Falico @ 2013-09-02 21:39 UTC (permalink / raw)
  To: netdev; +Cc: Veaceslav Falico, Jay Vosburgh, Andy Gospodarek

We're safe agains removal there, cause we use neighbours primitives.

CC: Jay Vosburgh <fubar@us.ibm.com>
CC: Andy Gospodarek <andy@greyhouse.net>
Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
---
 drivers/net/bonding/bond_main.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 59814c9..ce1b0fb 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -4099,12 +4099,13 @@ static void bond_setup(struct net_device *bond_dev)
 static void bond_uninit(struct net_device *bond_dev)
 {
 	struct bonding *bond = netdev_priv(bond_dev);
-	struct slave *slave, *tmp_slave;
+	struct list_head *iter;
+	struct slave *slave;
 
 	bond_netpoll_cleanup(bond_dev);
 
 	/* Release the bonded slaves */
-	list_for_each_entry_safe(slave, tmp_slave, &bond->slave_list, list)
+	bond_for_each_slave(bond, slave, iter)
 		__bond_release_one(bond_dev, slave->dev, true);
 	pr_info("%s: released all slaves\n", bond_dev->name);
 
-- 
1.8.4

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH RFC net-next 21/21] bonding: remove slave lists
  2013-09-02 21:39 [PATCH RFC net-next 0/21] bonding: use neighbours instead of own lists Veaceslav Falico
                   ` (19 preceding siblings ...)
  2013-09-02 21:39 ` [PATCH RFC net-next 20/21] bonding: use bond_for_each_slave() in bond_uninit() Veaceslav Falico
@ 2013-09-02 21:39 ` Veaceslav Falico
  20 siblings, 0 replies; 27+ messages in thread
From: Veaceslav Falico @ 2013-09-02 21:39 UTC (permalink / raw)
  To: netdev; +Cc: Veaceslav Falico, Jay Vosburgh, Andy Gospodarek

And all the initialization.

CC: Jay Vosburgh <fubar@us.ibm.com>
CC: Andy Gospodarek <andy@greyhouse.net>
Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
---
 drivers/net/bonding/bond_main.c | 4 ----
 drivers/net/bonding/bonding.h   | 2 --
 2 files changed, 6 deletions(-)

diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index ce1b0fb..9c24bab 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -992,7 +992,6 @@ void bond_select_active_slave(struct bonding *bond)
  */
 static void bond_attach_slave(struct bonding *bond, struct slave *new_slave)
 {
-	list_add_tail_rcu(&new_slave->list, &bond->slave_list);
 	bond->slave_cnt++;
 }
 
@@ -1008,7 +1007,6 @@ static void bond_attach_slave(struct bonding *bond, struct slave *new_slave)
  */
 static void bond_detach_slave(struct bonding *bond, struct slave *slave)
 {
-	list_del_rcu(&slave->list);
 	bond->slave_cnt--;
 }
 
@@ -1402,7 +1400,6 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 		res = -ENOMEM;
 		goto err_undo_flags;
 	}
-	INIT_LIST_HEAD(&new_slave->list);
 	/*
 	 * Set the new_slave's queue_id to be zero.  Queue ID mapping
 	 * is set via sysfs or module option if desired.
@@ -4043,7 +4040,6 @@ static void bond_setup(struct net_device *bond_dev)
 	/* initialize rwlocks */
 	rwlock_init(&bond->lock);
 	rwlock_init(&bond->curr_slave_lock);
-	INIT_LIST_HEAD(&bond->slave_list);
 	bond->params = bonding_defaults;
 
 	/* Initialize pointers */
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index b8047f3..57b95d2 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -180,7 +180,6 @@ struct bond_parm_tbl {
 
 struct slave {
 	struct net_device *dev; /* first - useful for panic debug */
-	struct list_head list;
 	struct bonding *bond; /* our master */
 	int    delay;
 	unsigned long jiffies;
@@ -220,7 +219,6 @@ struct slave {
  */
 struct bonding {
 	struct   net_device *dev; /* first - useful for panic debug */
-	struct   list_head slave_list;
 	struct   slave *curr_active_slave;
 	struct   slave *current_arp_slave;
 	struct   slave *primary_slave;
-- 
1.8.4

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [PATCH RFC net-next 06/21] net: create sysfs symlinks for neighbour devices
  2013-09-02 21:39 ` [PATCH RFC net-next 06/21] net: create sysfs symlinks for neighbour devices Veaceslav Falico
@ 2013-09-03  7:48   ` Jiri Pirko
  2013-09-03  8:05     ` Veaceslav Falico
  0 siblings, 1 reply; 27+ messages in thread
From: Jiri Pirko @ 2013-09-03  7:48 UTC (permalink / raw)
  To: Veaceslav Falico
  Cc: netdev, Jay Vosburgh, Andy Gospodarek, David S. Miller,
	Eric Dumazet, Alexander Duyck

Mon, Sep 02, 2013 at 11:39:10PM CEST, vfalico@redhat.com wrote:
>Also, remove the same functionality from bonding - it will be already done
>for any device that links to its lower/upper neighbour.
>
>The links will be created for dev's kobject, and will look like
>slave_eth0 for lower device eth0 and upper_bridge0 for upper device
>bridge0.

The pair should be either slave/master or lower/upper. It's undesirable
to mix these two. Maybe for compatibility reasons we should leave
current bonding sysfs files and create proper new generic ones?

I think there should be directories under netdev dir like:
/sys/class/net/em1-
                  |-upper-
                         |-bond0(link)
                         |-vlanx(link)
/sys/class/net/bond0-
                    |-lower-
                           |-em1(link)
                           |-em2(link)
           

>
>CC: Jay Vosburgh <fubar@us.ibm.com>
>CC: Andy Gospodarek <andy@greyhouse.net>
>CC: "David S. Miller" <davem@davemloft.net>
>CC: Eric Dumazet <edumazet@google.com>
>CC: Jiri Pirko <jiri@resnulli.us>
>CC: Alexander Duyck <alexander.h.duyck@intel.com>
>Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
>---
> drivers/net/bonding/bond_main.c  | 11 +----------
> drivers/net/bonding/bond_sysfs.c | 25 -------------------------
> drivers/net/bonding/bonding.h    |  2 --
> net/core/dev.c                   | 29 +++++++++++++++++++++++++++++
> 4 files changed, 30 insertions(+), 37 deletions(-)
>
>diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
>index c50679f..b0b753d 100644
>--- a/drivers/net/bonding/bond_main.c
>+++ b/drivers/net/bonding/bond_main.c
>@@ -1635,15 +1635,11 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
> 
> 	read_unlock(&bond->lock);
> 
>-	res = bond_create_slave_symlinks(bond_dev, slave_dev);
>-	if (res)
>-		goto err_detach;
>-
> 	res = netdev_rx_handler_register(slave_dev, bond_handle_frame,
> 					 new_slave);
> 	if (res) {
> 		pr_debug("Error %d calling netdev_rx_handler_register\n", res);
>-		goto err_dest_symlinks;
>+		goto err_detach;
> 	}
> 
> 	pr_info("%s: enslaving %s as a%s interface with a%s link.\n",
>@@ -1655,9 +1651,6 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
> 	return 0;
> 
> /* Undo stages on error */
>-err_dest_symlinks:
>-	bond_destroy_slave_symlinks(bond_dev, slave_dev);
>-
> err_detach:
> 	if (!USES_PRIMARY(bond->params.mode))
> 		bond_hw_addr_flush(bond_dev, slave_dev);
>@@ -1856,8 +1849,6 @@ static int __bond_release_one(struct net_device *bond_dev,
> 			bond_dev->name, slave_dev->name, bond_dev->name);
> 
> 	/* must do this from outside any spinlocks */
>-	bond_destroy_slave_symlinks(bond_dev, slave_dev);
>-
> 	vlan_vids_del_by_dev(slave_dev, bond_dev);
> 
> 	/* If the mode USES_PRIMARY, then this cases was handled above by
>diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
>index 5715277..7b962a2 100644
>--- a/drivers/net/bonding/bond_sysfs.c
>+++ b/drivers/net/bonding/bond_sysfs.c
>@@ -168,31 +168,6 @@ static const struct class_attribute class_attr_bonding_masters = {
> 	.namespace = bonding_namespace,
> };
> 
>-int bond_create_slave_symlinks(struct net_device *master,
>-			       struct net_device *slave)
>-{
>-	char linkname[IFNAMSIZ+7];
>-	int ret = 0;
>-
>-	/* create a link from the master to the slave */
>-	sprintf(linkname, "slave_%s", slave->name);
>-	ret = sysfs_create_link(&(master->dev.kobj), &(slave->dev.kobj),
>-				linkname);
>-
>-	return ret;
>-
>-}
>-
>-void bond_destroy_slave_symlinks(struct net_device *master,
>-				 struct net_device *slave)
>-{
>-	char linkname[IFNAMSIZ+7];
>-
>-	sprintf(linkname, "slave_%s", slave->name);
>-	sysfs_remove_link(&(master->dev.kobj), linkname);
>-}
>-
>-
> /*
>  * Show the slaves in the current bond.
>  */
>diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
>index 4abc925..f7a167d 100644
>--- a/drivers/net/bonding/bonding.h
>+++ b/drivers/net/bonding/bonding.h
>@@ -455,8 +455,6 @@ int bond_create(struct net *net, const char *name);
> int bond_create_sysfs(struct bond_net *net);
> void bond_destroy_sysfs(struct bond_net *net);
> void bond_prepare_sysfs_group(struct bonding *bond);
>-int bond_create_slave_symlinks(struct net_device *master, struct net_device *slave);
>-void bond_destroy_slave_symlinks(struct net_device *master, struct net_device *slave);
> int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev);
> int bond_release(struct net_device *bond_dev, struct net_device *slave_dev);
> void bond_mii_monitor(struct work_struct *);
>diff --git a/net/core/dev.c b/net/core/dev.c
>index 7eecf35..1c3e98d 100644
>--- a/net/core/dev.c
>+++ b/net/core/dev.c
>@@ -4580,6 +4580,7 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev,
> 					bool upper, void *private)
> {
> 	struct netdev_adjacent *adj, *neigh = NULL;
>+	char linkname[IFNAMSIZ+7];
> 	int ret;
> 
> 	adj = __netdev_find_adj(dev, adj_dev, upper, false);
>@@ -4628,6 +4629,16 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev,
> 			 */
> 			if (master)
> 				neigh->private = private;
>+
>+			sprintf(linkname, "slave_%s", adj_dev->name);
>+			ret = sysfs_create_link(&(dev->dev.kobj),
>+						&(adj_dev->dev.kobj),
>+						linkname);
>+			if (ret) {
>+				kfree(neigh);
>+				kfree(adj);
>+				return ret;
>+			}
> 			list_add_tail_rcu(&neigh->list,
> 					  &dev->neighbour_dev_list.lower);
> 		}
>@@ -4635,10 +4646,24 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev,
> 		return 0;
> 	}
> 
>+	/* it's upper neighbour, we don't care if it's master or not */
>+	if (neigh) {
>+		sprintf(linkname, "upper_%s", adj_dev->name);
>+		ret = sysfs_create_link(&(dev->dev.kobj), &(adj_dev->dev.kobj),
>+					linkname);
>+		if (ret) {
>+			kfree(neigh);
>+			kfree(adj);
>+			return ret;
>+		}
>+	}
>+
> 	/* Ensure that master upper link is always the first item in list. */
> 	if (master) {
> 		ret = sysfs_create_link(&(dev->dev.kobj), &(adj_dev->dev.kobj), "master");
> 		if (ret) {
>+			if (neigh)
>+				sysfs_remove_link(&(dev->dev.kobj), linkname);
> 			kfree(neigh);
> 			kfree(adj);
> 			return ret;
>@@ -4678,6 +4703,7 @@ void __netdev_adjacent_dev_remove(struct net_device *dev,
> 				  struct net_device *adj_dev, bool upper)
> {
> 	struct netdev_adjacent *adj, *neighbour;
>+	char linkname[IFNAMSIZ+7];
> 
> 	if (upper) {
> 		adj = __netdev_find_upper(dev, adj_dev);
>@@ -4725,6 +4751,9 @@ void __netdev_adjacent_dev_remove(struct net_device *dev,
> 		list_del_rcu(&neighbour->list);
> 		if (neighbour->master && upper)
> 			sysfs_remove_link(&(dev->dev.kobj), "master");
>+		sprintf(linkname, "%s_%s", upper ? "upper" : "slave",
>+			adj_dev->name);
>+		sysfs_remove_link(&(dev->dev.kobj), linkname);
> 		dev_put(adj_dev);
> 		kfree_rcu(neighbour, rcu);
> 	}
>-- 
>1.8.4
>

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH RFC net-next 06/21] net: create sysfs symlinks for neighbour devices
  2013-09-03  7:48   ` Jiri Pirko
@ 2013-09-03  8:05     ` Veaceslav Falico
  0 siblings, 0 replies; 27+ messages in thread
From: Veaceslav Falico @ 2013-09-03  8:05 UTC (permalink / raw)
  To: Jiri Pirko
  Cc: netdev, Jay Vosburgh, Andy Gospodarek, David S. Miller,
	Eric Dumazet, Alexander Duyck

On Tue, Sep 03, 2013 at 09:48:53AM +0200, Jiri Pirko wrote:
>Mon, Sep 02, 2013 at 11:39:10PM CEST, vfalico@redhat.com wrote:
>>Also, remove the same functionality from bonding - it will be already done
>>for any device that links to its lower/upper neighbour.
>>
>>The links will be created for dev's kobject, and will look like
>>slave_eth0 for lower device eth0 and upper_bridge0 for upper device
>>bridge0.
>
>The pair should be either slave/master or lower/upper. It's undesirable
>to mix these two. Maybe for compatibility reasons we should leave
>current bonding sysfs files and create proper new generic ones?

I completely agree with the slave/master vs lower/upper logic, and you've
correctly understood why I've chosen this path.

I'm ok with any approach, but it looks weird. I've googled a bit and saw
that people use the slave_eth0...

So dunno what's best option here, really.

>
>I think there should be directories under netdev dir like:
>/sys/class/net/em1-
>                  |-upper-
>                         |-bond0(link)
>                         |-vlanx(link)
>/sys/class/net/bond0-
>                    |-lower-
>                           |-em1(link)
>                           |-em2(link)
>
>
>>
>>CC: Jay Vosburgh <fubar@us.ibm.com>
>>CC: Andy Gospodarek <andy@greyhouse.net>
>>CC: "David S. Miller" <davem@davemloft.net>
>>CC: Eric Dumazet <edumazet@google.com>
>>CC: Jiri Pirko <jiri@resnulli.us>
>>CC: Alexander Duyck <alexander.h.duyck@intel.com>
>>Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
>>---
>> drivers/net/bonding/bond_main.c  | 11 +----------
>> drivers/net/bonding/bond_sysfs.c | 25 -------------------------
>> drivers/net/bonding/bonding.h    |  2 --
>> net/core/dev.c                   | 29 +++++++++++++++++++++++++++++
>> 4 files changed, 30 insertions(+), 37 deletions(-)
>>
>>diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
>>index c50679f..b0b753d 100644
>>--- a/drivers/net/bonding/bond_main.c
>>+++ b/drivers/net/bonding/bond_main.c
>>@@ -1635,15 +1635,11 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
>>
>> 	read_unlock(&bond->lock);
>>
>>-	res = bond_create_slave_symlinks(bond_dev, slave_dev);
>>-	if (res)
>>-		goto err_detach;
>>-
>> 	res = netdev_rx_handler_register(slave_dev, bond_handle_frame,
>> 					 new_slave);
>> 	if (res) {
>> 		pr_debug("Error %d calling netdev_rx_handler_register\n", res);
>>-		goto err_dest_symlinks;
>>+		goto err_detach;
>> 	}
>>
>> 	pr_info("%s: enslaving %s as a%s interface with a%s link.\n",
>>@@ -1655,9 +1651,6 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
>> 	return 0;
>>
>> /* Undo stages on error */
>>-err_dest_symlinks:
>>-	bond_destroy_slave_symlinks(bond_dev, slave_dev);
>>-
>> err_detach:
>> 	if (!USES_PRIMARY(bond->params.mode))
>> 		bond_hw_addr_flush(bond_dev, slave_dev);
>>@@ -1856,8 +1849,6 @@ static int __bond_release_one(struct net_device *bond_dev,
>> 			bond_dev->name, slave_dev->name, bond_dev->name);
>>
>> 	/* must do this from outside any spinlocks */
>>-	bond_destroy_slave_symlinks(bond_dev, slave_dev);
>>-
>> 	vlan_vids_del_by_dev(slave_dev, bond_dev);
>>
>> 	/* If the mode USES_PRIMARY, then this cases was handled above by
>>diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
>>index 5715277..7b962a2 100644
>>--- a/drivers/net/bonding/bond_sysfs.c
>>+++ b/drivers/net/bonding/bond_sysfs.c
>>@@ -168,31 +168,6 @@ static const struct class_attribute class_attr_bonding_masters = {
>> 	.namespace = bonding_namespace,
>> };
>>
>>-int bond_create_slave_symlinks(struct net_device *master,
>>-			       struct net_device *slave)
>>-{
>>-	char linkname[IFNAMSIZ+7];
>>-	int ret = 0;
>>-
>>-	/* create a link from the master to the slave */
>>-	sprintf(linkname, "slave_%s", slave->name);
>>-	ret = sysfs_create_link(&(master->dev.kobj), &(slave->dev.kobj),
>>-				linkname);
>>-
>>-	return ret;
>>-
>>-}
>>-
>>-void bond_destroy_slave_symlinks(struct net_device *master,
>>-				 struct net_device *slave)
>>-{
>>-	char linkname[IFNAMSIZ+7];
>>-
>>-	sprintf(linkname, "slave_%s", slave->name);
>>-	sysfs_remove_link(&(master->dev.kobj), linkname);
>>-}
>>-
>>-
>> /*
>>  * Show the slaves in the current bond.
>>  */
>>diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
>>index 4abc925..f7a167d 100644
>>--- a/drivers/net/bonding/bonding.h
>>+++ b/drivers/net/bonding/bonding.h
>>@@ -455,8 +455,6 @@ int bond_create(struct net *net, const char *name);
>> int bond_create_sysfs(struct bond_net *net);
>> void bond_destroy_sysfs(struct bond_net *net);
>> void bond_prepare_sysfs_group(struct bonding *bond);
>>-int bond_create_slave_symlinks(struct net_device *master, struct net_device *slave);
>>-void bond_destroy_slave_symlinks(struct net_device *master, struct net_device *slave);
>> int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev);
>> int bond_release(struct net_device *bond_dev, struct net_device *slave_dev);
>> void bond_mii_monitor(struct work_struct *);
>>diff --git a/net/core/dev.c b/net/core/dev.c
>>index 7eecf35..1c3e98d 100644
>>--- a/net/core/dev.c
>>+++ b/net/core/dev.c
>>@@ -4580,6 +4580,7 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev,
>> 					bool upper, void *private)
>> {
>> 	struct netdev_adjacent *adj, *neigh = NULL;
>>+	char linkname[IFNAMSIZ+7];
>> 	int ret;
>>
>> 	adj = __netdev_find_adj(dev, adj_dev, upper, false);
>>@@ -4628,6 +4629,16 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev,
>> 			 */
>> 			if (master)
>> 				neigh->private = private;
>>+
>>+			sprintf(linkname, "slave_%s", adj_dev->name);
>>+			ret = sysfs_create_link(&(dev->dev.kobj),
>>+						&(adj_dev->dev.kobj),
>>+						linkname);
>>+			if (ret) {
>>+				kfree(neigh);
>>+				kfree(adj);
>>+				return ret;
>>+			}
>> 			list_add_tail_rcu(&neigh->list,
>> 					  &dev->neighbour_dev_list.lower);
>> 		}
>>@@ -4635,10 +4646,24 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev,
>> 		return 0;
>> 	}
>>
>>+	/* it's upper neighbour, we don't care if it's master or not */
>>+	if (neigh) {
>>+		sprintf(linkname, "upper_%s", adj_dev->name);
>>+		ret = sysfs_create_link(&(dev->dev.kobj), &(adj_dev->dev.kobj),
>>+					linkname);
>>+		if (ret) {
>>+			kfree(neigh);
>>+			kfree(adj);
>>+			return ret;
>>+		}
>>+	}
>>+
>> 	/* Ensure that master upper link is always the first item in list. */
>> 	if (master) {
>> 		ret = sysfs_create_link(&(dev->dev.kobj), &(adj_dev->dev.kobj), "master");
>> 		if (ret) {
>>+			if (neigh)
>>+				sysfs_remove_link(&(dev->dev.kobj), linkname);
>> 			kfree(neigh);
>> 			kfree(adj);
>> 			return ret;
>>@@ -4678,6 +4703,7 @@ void __netdev_adjacent_dev_remove(struct net_device *dev,
>> 				  struct net_device *adj_dev, bool upper)
>> {
>> 	struct netdev_adjacent *adj, *neighbour;
>>+	char linkname[IFNAMSIZ+7];
>>
>> 	if (upper) {
>> 		adj = __netdev_find_upper(dev, adj_dev);
>>@@ -4725,6 +4751,9 @@ void __netdev_adjacent_dev_remove(struct net_device *dev,
>> 		list_del_rcu(&neighbour->list);
>> 		if (neighbour->master && upper)
>> 			sysfs_remove_link(&(dev->dev.kobj), "master");
>>+		sprintf(linkname, "%s_%s", upper ? "upper" : "slave",
>>+			adj_dev->name);
>>+		sysfs_remove_link(&(dev->dev.kobj), linkname);
>> 		dev_put(adj_dev);
>> 		kfree_rcu(neighbour, rcu);
>> 	}
>>--
>>1.8.4
>>

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH RFC net-next 18/21] net: add a function to get the next/prev private
  2013-09-02 21:39 ` [PATCH RFC net-next 18/21] net: add a function to get the next/prev private Veaceslav Falico
@ 2013-09-03  8:10   ` Jiri Pirko
  0 siblings, 0 replies; 27+ messages in thread
From: Jiri Pirko @ 2013-09-03  8:10 UTC (permalink / raw)
  To: Veaceslav Falico; +Cc: netdev, David S. Miller, Eric Dumazet, Alexander Duyck

Mon, Sep 02, 2013 at 11:39:22PM CEST, vfalico@redhat.com wrote:
>The boolean flag specifies which direction to go.
>
>CC: "David S. Miller" <davem@davemloft.net>
>CC: Eric Dumazet <edumazet@google.com>
>CC: Jiri Pirko <jiri@resnulli.us>
>CC: Alexander Duyck <alexander.h.duyck@intel.com>
>Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
>---
> include/linux/netdevice.h |  2 ++
> net/core/dev.c            | 24 ++++++++++++++++++++++++
> 2 files changed, 26 insertions(+)
>
>diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
>index bde2244..a112ccc 100644
>--- a/include/linux/netdevice.h
>+++ b/include/linux/netdevice.h
>@@ -2835,6 +2835,8 @@ extern void *netdev_lower_dev_get_private_rcu(struct net_device *dev,
> 					      struct net_device *lower_dev);
> extern void *netdev_lower_dev_get_private(struct net_device *dev,
> 					  struct net_device *lower_dev);
>+extern void *netdev_lower_dev_get_next_private(struct net_device *dev,
>+					       void *private, bool prev);
> extern int skb_checksum_help(struct sk_buff *skb);
> extern struct sk_buff *__skb_gso_segment(struct sk_buff *skb,
> 	netdev_features_t features, bool tx_path);
>diff --git a/net/core/dev.c b/net/core/dev.c
>index 6df11a0..c694059 100644
>--- a/net/core/dev.c
>+++ b/net/core/dev.c
>@@ -5163,6 +5163,30 @@ void *netdev_lower_dev_get_private(struct net_device *dev,
> }
> EXPORT_SYMBOL(netdev_lower_dev_get_private);
> 
>+extern void *netdev_lower_dev_get_next_private(struct net_device *dev,
>+					       void *private, bool prev)

                                                             ^^^^^^^^^^^
				Please rather do this in 2 functions
				Next should return next, not previous...

>+{
>+	struct netdev_adjacent *lower;
>+
>+	list_for_each_entry(lower, &dev->neighbour_dev_list.lower, list)
>+		if (lower->private == private)
>+			break;
>+
>+	if (&lower->list == &dev->neighbour_dev_list.lower)
>+		return NULL;
>+
>+	lower = prev ? list_entry(lower->list.prev, struct netdev_adjacent, list) :
>+		       list_entry(lower->list.next, struct netdev_adjacent, list);
>+	if (&lower->list != &dev->neighbour_dev_list.lower)
>+		return lower->private;
>+
>+	lower = prev ? list_entry(lower->list.prev, struct netdev_adjacent, list) :
>+		       list_entry(lower->list.next, struct netdev_adjacent, list);
>+
>+	return lower->private;
>+}
>+EXPORT_SYMBOL(netdev_lower_dev_get_next_private);
>+
> static void dev_change_rx_flags(struct net_device *dev, int flags)
> {
> 	const struct net_device_ops *ops = dev->netdev_ops;
>-- 
>1.8.4
>

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH RFC net-next 01/21] net: add neighbour_dev_list to save only neighbours
  2013-09-02 21:39 ` [PATCH RFC net-next 01/21] net: add neighbour_dev_list to save only neighbours Veaceslav Falico
@ 2013-09-03  8:29   ` Jiri Pirko
  2013-09-03  8:34     ` Veaceslav Falico
  0 siblings, 1 reply; 27+ messages in thread
From: Jiri Pirko @ 2013-09-03  8:29 UTC (permalink / raw)
  To: Veaceslav Falico
  Cc: netdev, David S. Miller, Eric Dumazet, Alexander Duyck, Cong Wang

Mon, Sep 02, 2013 at 11:39:05PM CEST, vfalico@redhat.com wrote:
>Currently, we distinguish neighbours (first-level linked devices) from
>non-neighbours by the neighbour bool in the netdev_adjacent. This could be
>quite time-consuming in case we would like to traverse *only* through
>neighbours - cause we'd have to traverse through all devices and check for
>this flag, and in a (quite common) scenario where we have lots of vlans on
>top of bridge, which is on top of a bond - the bonding would have to go
>through all those vlans to get its upper neighbour linked devices.
>
>This situation is really unpleasant, cause there are already a lot of cases
>when a device with slaves needs to go through them in hot path.
>
>To fix this, introduce a new upper/lower device lists structure -
>neighbour_dev_list, which contains only the neighbours. It works always in
>pair with the all_device_list structure (renamed from upper/lower_dev_list),
>i.e. both of them contain the same links, only that all_dev_list contains
>also non-neighbour device links. It's really a small change visible,
>currently, only for __netdev_adjacent_dev_insert/remove(), and doesn't
>change the main linked logic at all.
>
>Also, add some comments a fix a name collision in
>netdev_for_each_upper_dev_rcu().
>
>CC: "David S. Miller" <davem@davemloft.net>
>CC: Eric Dumazet <edumazet@google.com>
>CC: Jiri Pirko <jiri@resnulli.us>
>CC: Alexander Duyck <alexander.h.duyck@intel.com>
>CC: Cong Wang <amwang@redhat.com>
>Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
>---
> include/linux/netdevice.h |  24 ++++---
> net/core/dev.c            | 157 ++++++++++++++++++++++++++++++++++------------
> 2 files changed, 134 insertions(+), 47 deletions(-)
>
>diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
>index 3ad49b8..df50548 100644
>--- a/include/linux/netdevice.h
>+++ b/include/linux/netdevice.h
>@@ -1124,8 +1124,18 @@ struct net_device {
> 	struct list_head	dev_list;
> 	struct list_head	napi_list;
> 	struct list_head	unreg_list;
>-	struct list_head	upper_dev_list; /* List of upper devices */
>-	struct list_head	lower_dev_list;
>+
>+	/* directly linked devices, like slaves for bonding */
>+	struct {
>+		struct list_head upper;
>+		struct list_head lower;
>+	} neighbour_dev_list ;
>+
>+	/* all linked devices, *including* neighbours */
>+	struct {
>+		struct list_head upper;
>+		struct list_head lower;
>+	} all_dev_list ;


I think there is need for some naming consistency for functions and
macros handling these lists.

I propose:
dev_list (drop the "neighbour") and all_dev_list

and exported functions and macros called like:
netdev_lower_get_next_priv()
netdev_lower_for_each_priv()
netdev_all_upper_get_next_rcu()
etc...

> 
> 
> 	/* currently active device features */
>@@ -2772,11 +2782,11 @@ extern struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev,
> 							struct list_head **iter);
> 
> /* iterate through upper list, must be called under RCU read lock */
>-#define netdev_for_each_upper_dev_rcu(dev, upper, iter) \
>-	for (iter = &(dev)->upper_dev_list, \
>-	     upper = netdev_upper_get_next_dev_rcu(dev, &(iter)); \
>-	     upper; \
>-	     upper = netdev_upper_get_next_dev_rcu(dev, &(iter)))
>+#define netdev_for_each_upper_dev_rcu(dev, updev, iter) \
>+	for (iter = &(dev)->all_dev_list.upper, \
>+	     updev= netdev_upper_get_next_dev_rcu(dev, &(iter)); \
>+	     updev; \
>+	     updev = netdev_upper_get_next_dev_rcu(dev, &(iter)))
> 
> extern struct net_device *netdev_master_upper_dev_get(struct net_device *dev);
> extern struct net_device *netdev_master_upper_dev_get_rcu(struct net_device *dev);
>diff --git a/net/core/dev.c b/net/core/dev.c
>index 743620e..9e4eb40 100644
>--- a/net/core/dev.c
>+++ b/net/core/dev.c
>@@ -4373,9 +4373,6 @@ struct netdev_adjacent {
> 	/* upper master flag, there can only be one master device per list */
> 	bool master;
> 
>-	/* indicates that this dev is our first-level lower/upper device */
>-	bool neighbour;
>-
> 	/* counter for the number of times this device was added to us */
> 	u16 ref_nr;
> 
>@@ -4385,12 +4382,17 @@ struct netdev_adjacent {
> 
> static struct netdev_adjacent *__netdev_find_adj(struct net_device *dev,
> 						 struct net_device *adj_dev,
>-						 bool upper)
>+						 bool upper, bool neighbour)
> {
> 	struct netdev_adjacent *adj;
> 	struct list_head *dev_list;
> 
>-	dev_list = upper ? &dev->upper_dev_list : &dev->lower_dev_list;
>+	if (neighbour)
>+		dev_list = upper ? &dev->neighbour_dev_list.upper :
>+				   &dev->neighbour_dev_list.lower;
>+	else
>+		dev_list = upper ? &dev->all_dev_list.upper :
>+				   &dev->all_dev_list.lower;
> 
> 	list_for_each_entry(adj, dev_list, list) {
> 		if (adj->dev == adj_dev)
>@@ -4402,13 +4404,25 @@ static struct netdev_adjacent *__netdev_find_adj(struct net_device *dev,
> static inline struct netdev_adjacent *__netdev_find_upper(struct net_device *dev,
> 							  struct net_device *udev)
> {
>-	return __netdev_find_adj(dev, udev, true);
>+	return __netdev_find_adj(dev, udev, true, false);
> }
> 
> static inline struct netdev_adjacent *__netdev_find_lower(struct net_device *dev,
> 							  struct net_device *ldev)
> {
>-	return __netdev_find_adj(dev, ldev, false);
>+	return __netdev_find_adj(dev, ldev, false, false);
>+}
>+
>+static inline struct netdev_adjacent *__netdev_find_upper_neighbour(struct net_device *dev,
>+								    struct net_device *udev)
>+{
>+	return __netdev_find_adj(dev, udev, true, true);
>+}
>+
>+static inline struct netdev_adjacent *__netdev_find_lower_neighbour(struct net_device *dev,
>+								    struct net_device *ldev)
>+{
>+	return __netdev_find_adj(dev, ldev, false, true);
> }
> 
> /**
>@@ -4440,7 +4454,7 @@ bool netdev_has_any_upper_dev(struct net_device *dev)
> {
> 	ASSERT_RTNL();
> 
>-	return !list_empty(&dev->upper_dev_list);
>+	return !list_empty(&dev->all_dev_list.upper);
> }
> EXPORT_SYMBOL(netdev_has_any_upper_dev);
> 
>@@ -4457,10 +4471,10 @@ struct net_device *netdev_master_upper_dev_get(struct net_device *dev)
> 
> 	ASSERT_RTNL();
> 
>-	if (list_empty(&dev->upper_dev_list))
>+	if (list_empty(&dev->neighbour_dev_list.upper))
> 		return NULL;
> 
>-	upper = list_first_entry(&dev->upper_dev_list,
>+	upper = list_first_entry(&dev->neighbour_dev_list.upper,
> 				 struct netdev_adjacent, list);
> 	if (likely(upper->master))
> 		return upper->dev;
>@@ -4484,7 +4498,7 @@ struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev,
> 
> 	upper = list_entry_rcu((*iter)->next, struct netdev_adjacent, list);
> 
>-	if (&upper->list == &dev->upper_dev_list)
>+	if (&upper->list == &dev->all_dev_list.upper)
> 		return NULL;
> 
> 	*iter = &upper->list;
>@@ -4504,7 +4518,7 @@ struct net_device *netdev_master_upper_dev_get_rcu(struct net_device *dev)
> {
> 	struct netdev_adjacent *upper;
> 
>-	upper = list_first_or_null_rcu(&dev->upper_dev_list,
>+	upper = list_first_or_null_rcu(&dev->neighbour_dev_list.upper,
> 				       struct netdev_adjacent, list);
> 	if (upper && likely(upper->master))
> 		return upper->dev;
>@@ -4517,11 +4531,12 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev,
> 					bool neighbour, bool master,
> 					bool upper)
> {
>-	struct netdev_adjacent *adj;
>+	struct netdev_adjacent *adj, *neigh = NULL;
> 
>-	adj = __netdev_find_adj(dev, adj_dev, upper);
>+	adj = __netdev_find_adj(dev, adj_dev, upper, false);
> 
> 	if (adj) {
>+		/* we cannot insert a neighbour device twice */
> 		BUG_ON(neighbour);
> 		adj->ref_nr++;
> 		return 0;
>@@ -4533,24 +4548,50 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev,
> 
> 	adj->dev = adj_dev;
> 	adj->master = master;
>-	adj->neighbour = neighbour;
> 	adj->ref_nr = 1;
>-
> 	dev_hold(adj_dev);
>+
>+	if (neighbour) {
>+		neigh = kmalloc(sizeof(*neigh), GFP_KERNEL);
>+		if (!neigh) {
>+			kfree(adj);
>+			return -ENOMEM;
>+		}
>+		neigh->dev = adj_dev;
>+		neigh->master = master;
>+		neigh->ref_nr = 1;
>+		dev_hold(adj_dev);
>+	}
>+
> 	pr_debug("dev_hold for %s, because of %s link added from %s to %s\n",
> 		 adj_dev->name, upper ? "upper" : "lower", dev->name,
> 		 adj_dev->name);
>+	if (neigh)
>+		pr_debug("dev_hold for %s, because of %s link added from %s"
>+			 " to %s (neighbour)\n",
>+			 adj_dev->name, upper ? "upper" : "lower", dev->name,
>+			 adj_dev->name);
> 
> 	if (!upper) {
>-		list_add_tail_rcu(&adj->list, &dev->lower_dev_list);
>+		if (neigh)
>+			list_add_tail_rcu(&neigh->list,
>+					  &dev->neighbour_dev_list.lower);
>+		list_add_tail_rcu(&adj->list, &dev->all_dev_list.lower);
> 		return 0;
> 	}
> 
> 	/* Ensure that master upper link is always the first item in list. */
>-	if (master)
>-		list_add_rcu(&adj->list, &dev->upper_dev_list);
>-	else
>-		list_add_tail_rcu(&adj->list, &dev->upper_dev_list);
>+	if (master) {
>+		if (neigh)
>+			list_add_rcu(&neigh->list,
>+				     &dev->neighbour_dev_list.upper);
>+		list_add_rcu(&adj->list, &dev->all_dev_list.upper);
>+	} else {
>+		if (neigh)
>+			list_add_tail_rcu(&neigh->list,
>+					  &dev->neighbour_dev_list.upper);
>+		list_add_tail_rcu(&adj->list, &dev->all_dev_list.upper);
>+	}
> 
> 	return 0;
> }
>@@ -4574,17 +4615,36 @@ static inline int __netdev_lower_dev_insert(struct net_device *dev,
> void __netdev_adjacent_dev_remove(struct net_device *dev,
> 				  struct net_device *adj_dev, bool upper)
> {
>-	struct netdev_adjacent *adj;
>+	struct netdev_adjacent *adj, *neighbour;
> 
>-	if (upper)
>+	if (upper) {
> 		adj = __netdev_find_upper(dev, adj_dev);
>-	else
>+		neighbour = __netdev_find_upper_neighbour(dev, adj_dev);
>+	} else {
> 		adj = __netdev_find_lower(dev, adj_dev);
>+		neighbour = __netdev_find_lower_neighbour(dev, adj_dev);
>+	}
> 
>-	if (!adj)
>+	if (!adj) {
>+		pr_err("tried to remove %s device %s from %s\n",
>+		       upper ? "upper" : "lower", dev->name, adj_dev->name);
> 		BUG();
>+	}
> 
> 	if (adj->ref_nr > 1) {
>+		pr_debug("rec_cnt-- for link to %s, because of %s link removed"
>+			 " from %s to %s, remains %d\n",
>+			 adj_dev->name, upper ? "upper" : "lower", dev->name,
>+			 adj_dev->name, adj->ref_nr-1);
>+		if (neighbour) {
>+			pr_debug("rec_cnt-- for link to %s, because of %s link"
>+				 " removed from %s to %s, remain %d (neigh)\n",
>+				 adj_dev->name, upper ? "upper" : "lower",
>+				 dev->name, adj_dev->name,
>+				 neighbour->ref_nr-1);
>+			BUG_ON(adj->ref_nr != neighbour->ref_nr);
>+			neighbour->ref_nr--;
>+		}
> 		adj->ref_nr--;
> 		return;
> 	}
>@@ -4595,6 +4655,15 @@ void __netdev_adjacent_dev_remove(struct net_device *dev,
> 		 adj_dev->name);
> 	dev_put(adj_dev);
> 	kfree_rcu(adj, rcu);
>+	if (neighbour) {
>+		pr_debug("dev_put for %s, because of %s link removed from %s"
>+			 " to %s (neighbour)\n",
>+			 adj_dev->name, upper ? "upper" : "lower", dev->name,
>+			 adj_dev->name);
>+		list_del_rcu(&neighbour->list);
>+		dev_put(adj_dev);
>+		kfree_rcu(neighbour, rcu);
>+	}
> }
> 
> static inline void __netdev_upper_dev_remove(struct net_device *dev,
>@@ -4675,12 +4744,14 @@ static int __netdev_upper_dev_link(struct net_device *dev,
> 		return ret;
> 
> 	/* Now that we linked these devs, make all the upper_dev's
>-	 * upper_dev_list visible to every dev's lower_dev_list and vice
>+	 * all_dev_list.upper visible to every dev's all_dev_list.lower an
> 	 * versa, and don't forget the devices itself. All of these
> 	 * links are non-neighbours.
> 	 */
>-	list_for_each_entry(i, &dev->lower_dev_list, list) {
>-		list_for_each_entry(j, &upper_dev->upper_dev_list, list) {
>+	list_for_each_entry(i, &dev->all_dev_list.lower, list) {
>+		list_for_each_entry(j, &upper_dev->all_dev_list.upper, list) {
>+			pr_debug("Interlinking %s with %s, non-neighbour\n",
>+				 i->dev->name, j->dev->name);
> 			ret = __netdev_adjacent_dev_link(i->dev, j->dev);
> 			if (ret)
> 				goto rollback_mesh;
>@@ -4688,14 +4759,18 @@ static int __netdev_upper_dev_link(struct net_device *dev,
> 	}
> 
> 	/* add dev to every upper_dev's upper device */
>-	list_for_each_entry(i, &upper_dev->upper_dev_list, list) {
>+	list_for_each_entry(i, &upper_dev->all_dev_list.upper, list) {
>+		pr_debug("linking %s's upper device %s with %s\n", upper_dev->name,
>+			 i->dev->name, dev->name);
> 		ret = __netdev_adjacent_dev_link(dev, i->dev);
> 		if (ret)
> 			goto rollback_upper_mesh;
> 	}
> 
> 	/* add upper_dev to every dev's lower device */
>-	list_for_each_entry(i, &dev->lower_dev_list, list) {
>+	list_for_each_entry(i, &dev->all_dev_list.lower, list) {
>+		pr_debug("linking %s's lower device %s with %s\n", dev->name,
>+			 i->dev->name, upper_dev->name);
> 		ret = __netdev_adjacent_dev_link(i->dev, upper_dev);
> 		if (ret)
> 			goto rollback_lower_mesh;
>@@ -4706,7 +4781,7 @@ static int __netdev_upper_dev_link(struct net_device *dev,
> 
> rollback_lower_mesh:
> 	to_i = i;
>-	list_for_each_entry(i, &dev->lower_dev_list, list) {
>+	list_for_each_entry(i, &dev->all_dev_list.lower, list) {
> 		if (i == to_i)
> 			break;
> 		__netdev_adjacent_dev_unlink(i->dev, upper_dev);
>@@ -4716,7 +4791,7 @@ rollback_lower_mesh:
> 
> rollback_upper_mesh:
> 	to_i = i;
>-	list_for_each_entry(i, &upper_dev->upper_dev_list, list) {
>+	list_for_each_entry(i, &upper_dev->all_dev_list.upper, list) {
> 		if (i == to_i)
> 			break;
> 		__netdev_adjacent_dev_unlink(dev, i->dev);
>@@ -4727,8 +4802,8 @@ rollback_upper_mesh:
> rollback_mesh:
> 	to_i = i;
> 	to_j = j;
>-	list_for_each_entry(i, &dev->lower_dev_list, list) {
>-		list_for_each_entry(j, &upper_dev->upper_dev_list, list) {
>+	list_for_each_entry(i, &dev->all_dev_list.lower, list) {
>+		list_for_each_entry(j, &upper_dev->all_dev_list.upper, list) {
> 			if (i == to_i && j == to_j)
> 				break;
> 			__netdev_adjacent_dev_unlink(i->dev, j->dev);
>@@ -4797,17 +4872,17 @@ void netdev_upper_dev_unlink(struct net_device *dev,
> 	 * devices from all upper_dev's upper devices and vice
> 	 * versa, to maintain the graph relationship.
> 	 */
>-	list_for_each_entry(i, &dev->lower_dev_list, list)
>-		list_for_each_entry(j, &upper_dev->upper_dev_list, list)
>+	list_for_each_entry(i, &dev->all_dev_list.lower, list)
>+		list_for_each_entry(j, &upper_dev->all_dev_list.upper, list)
> 			__netdev_adjacent_dev_unlink(i->dev, j->dev);
> 
> 	/* remove also the devices itself from lower/upper device
> 	 * list
> 	 */
>-	list_for_each_entry(i, &dev->lower_dev_list, list)
>+	list_for_each_entry(i, &dev->all_dev_list.lower, list)
> 		__netdev_adjacent_dev_unlink(i->dev, upper_dev);
> 
>-	list_for_each_entry(i, &upper_dev->upper_dev_list, list)
>+	list_for_each_entry(i, &upper_dev->all_dev_list.upper, list)
> 		__netdev_adjacent_dev_unlink(dev, i->dev);
> 
> 	call_netdevice_notifiers(NETDEV_CHANGEUPPER, dev);
>@@ -6069,8 +6144,10 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
> 	INIT_LIST_HEAD(&dev->napi_list);
> 	INIT_LIST_HEAD(&dev->unreg_list);
> 	INIT_LIST_HEAD(&dev->link_watch_list);
>-	INIT_LIST_HEAD(&dev->upper_dev_list);
>-	INIT_LIST_HEAD(&dev->lower_dev_list);
>+	INIT_LIST_HEAD(&dev->neighbour_dev_list.upper);
>+	INIT_LIST_HEAD(&dev->neighbour_dev_list.lower);
>+	INIT_LIST_HEAD(&dev->all_dev_list.upper);
>+	INIT_LIST_HEAD(&dev->all_dev_list.lower);
> 	dev->priv_flags = IFF_XMIT_DST_RELEASE;
> 	setup(dev);
> 
>-- 
>1.8.4
>

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH RFC net-next 01/21] net: add neighbour_dev_list to save only neighbours
  2013-09-03  8:29   ` Jiri Pirko
@ 2013-09-03  8:34     ` Veaceslav Falico
  0 siblings, 0 replies; 27+ messages in thread
From: Veaceslav Falico @ 2013-09-03  8:34 UTC (permalink / raw)
  To: Jiri Pirko
  Cc: netdev, David S. Miller, Eric Dumazet, Alexander Duyck, Cong Wang

On Tue, Sep 03, 2013 at 10:29:43AM +0200, Jiri Pirko wrote:
>Mon, Sep 02, 2013 at 11:39:05PM CEST, vfalico@redhat.com wrote:
...snip...
>>-	struct list_head	upper_dev_list; /* List of upper devices */
>>-	struct list_head	lower_dev_list;
>>+
>>+	/* directly linked devices, like slaves for bonding */
>>+	struct {
>>+		struct list_head upper;
>>+		struct list_head lower;
>>+	} neighbour_dev_list ;
>>+
>>+	/* all linked devices, *including* neighbours */
>>+	struct {
>>+		struct list_head upper;
>>+		struct list_head lower;
>>+	} all_dev_list ;
>
>
>I think there is need for some naming consistency for functions and
>macros handling these lists.
>
>I propose:
>dev_list (drop the "neighbour") and all_dev_list

Agreed.

>
>and exported functions and macros called like:
>netdev_lower_get_next_priv()
>netdev_lower_for_each_priv()
>netdev_all_upper_get_next_rcu()
>etc...

Yep, will try to convert and see how it goes.

Thanks a lot!

^ permalink raw reply	[flat|nested] 27+ messages in thread

end of thread, other threads:[~2013-09-03  8:35 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-09-02 21:39 [PATCH RFC net-next 0/21] bonding: use neighbours instead of own lists Veaceslav Falico
2013-09-02 21:39 ` [PATCH RFC net-next 01/21] net: add neighbour_dev_list to save only neighbours Veaceslav Falico
2013-09-03  8:29   ` Jiri Pirko
2013-09-03  8:34     ` Veaceslav Falico
2013-09-02 21:39 ` [PATCH RFC net-next 02/21] net: add RCU variant to search for netdev_adjacent link Veaceslav Falico
2013-09-02 21:39 ` [PATCH RFC net-next 03/21] net: add netdev_adjacent->private and allow to use it Veaceslav Falico
2013-09-02 21:39 ` [PATCH RFC net-next 04/21] net: expose the master link to sysfs, and remove it from bond Veaceslav Falico
2013-09-02 21:39 ` [PATCH RFC net-next 05/21] vlan: link the upper neighbour only after registering Veaceslav Falico
2013-09-02 21:39 ` [PATCH RFC net-next 06/21] net: create sysfs symlinks for neighbour devices Veaceslav Falico
2013-09-03  7:48   ` Jiri Pirko
2013-09-03  8:05     ` Veaceslav Falico
2013-09-02 21:39 ` [PATCH RFC net-next 07/21] bonding: add bond_has_slaves() and use it Veaceslav Falico
2013-09-02 21:39 ` [PATCH RFC net-next 08/21] bonding: convert bond_has_slaves() to use the neighbour list Veaceslav Falico
2013-09-02 21:39 ` [PATCH RFC net-next 09/21] bonding: populate neighbour's private on enslave Veaceslav Falico
2013-09-02 21:39 ` [PATCH RFC net-next 10/21] bonding: modify bond_get_slave_by_dev() to use neighbours Veaceslav Falico
2013-09-02 21:39 ` [PATCH RFC net-next 11/21] bonding: remove bond_for_each_slave_reverse() Veaceslav Falico
2013-09-02 21:39 ` [PATCH RFC net-next 12/21] net: add for_each iterators through neighbour lower link's private Veaceslav Falico
2013-09-02 21:39 ` [PATCH RFC net-next 13/21] bonding: make bond_for_each_slave() use lower neighbour's private Veaceslav Falico
2013-09-02 21:39 ` [PATCH RFC net-next 14/21] net: add netdev_for_each_lower_neigh_private_continue() Veaceslav Falico
2013-09-02 21:39 ` [PATCH RFC net-next 15/21] bonding: use neighbour list for bond_for_each_slave_continue() Veaceslav Falico
2013-09-02 21:39 ` [PATCH RFC net-next 16/21] net: add a possibility to get private from netdev_adjacent->list Veaceslav Falico
2013-09-02 21:39 ` [PATCH RFC net-next 17/21] bonding: convert first/last slave logic to use neighbours Veaceslav Falico
2013-09-02 21:39 ` [PATCH RFC net-next 18/21] net: add a function to get the next/prev private Veaceslav Falico
2013-09-03  8:10   ` Jiri Pirko
2013-09-02 21:39 ` [PATCH RFC net-next 19/21] bonding: use neighbours for bond_next/prev_slave() Veaceslav Falico
2013-09-02 21:39 ` [PATCH RFC net-next 20/21] bonding: use bond_for_each_slave() in bond_uninit() Veaceslav Falico
2013-09-02 21:39 ` [PATCH RFC net-next 21/21] bonding: remove slave lists Veaceslav Falico

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.