netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/7] bonding: 7 fixes for 2.6.24
@ 2008-01-18  0:24 Jay Vosburgh
  2008-01-18  0:24 ` [PATCH 1/7] bonding: fix locking in sysfs primary/active selection Jay Vosburgh
  2008-01-21  1:15 ` [PATCH 0/7] bonding: 7 fixes for 2.6.24 David Miller
  0 siblings, 2 replies; 14+ messages in thread
From: Jay Vosburgh @ 2008-01-18  0:24 UTC (permalink / raw)
  To: netdev; +Cc: Jeff Garzik, David Miller, Andy Gospodarek, Andrew Morton

	Following are seven patches to fix locking problems,
silence locking-related warnings and resolve one recent regression
in the current 2.6.24-rc.

	The first three patches are reposts, the rest are new.

	patch 1: fix locking in sysfs primary/active selection

	Call core network functions with expected locks to
eliminate potential deadlock and silence warnings.

	patch 2: fix ASSERT_RTNL that produces spurious warnings

	Relocate ASSERT_RTNL to remove a false warning; after patch,
ASSERT is located in code that holds only RTNL (additional locks were
causing the ASSERT to trip)

	patch 3: fix locking during alb failover and slave removal

	Fix all call paths into alb_fasten_mac_swap to hold only RTNL.
Eliminates potential deadlock and silences warnings.

	patch 4: release slaves when master removed via sysfs

	Insure that all slaves are removed when bond is destroyed via
sysfs.

	patch 5: Fix up parameter parsing

	Recent changes broke parameter parsing; this fixes things.

	patch 6: Fix lock ordering for rtnl and bonding_rwsem

	Resolves some lockdep warnings related to ordering between
rtnl and bonding_rwsem.

	patch 7: Don't hold lock when calling rtnl_unlock

	Since rtnl_unlock can sleep, don't hold any other locks when
calling it.

	Patches are against the current netdev-2.6#upstream branch.

	Please apply for 2.6.24.

	-J

---
	-Jay Vosburgh, IBM Linux Technology Center, fubar@us.ibm.com

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

* [PATCH 1/7] bonding: fix locking in sysfs primary/active selection
  2008-01-18  0:24 [PATCH 0/7] bonding: 7 fixes for 2.6.24 Jay Vosburgh
@ 2008-01-18  0:24 ` Jay Vosburgh
  2008-01-18  0:24   ` [PATCH 2/7] bonding: fix ASSERT_RTNL that produces spurious warnings Jay Vosburgh
  2008-01-18 19:39   ` [PATCH 1/7] bonding: fix locking in sysfs primary/active selection Jeff Garzik
  2008-01-21  1:15 ` [PATCH 0/7] bonding: 7 fixes for 2.6.24 David Miller
  1 sibling, 2 replies; 14+ messages in thread
From: Jay Vosburgh @ 2008-01-18  0:24 UTC (permalink / raw)
  To: netdev
  Cc: Jeff Garzik, David Miller, Andy Gospodarek, Andrew Morton,
	Jay Vosburgh

	Fix the functions that store the primary and active slave
options via sysfs to hold the correct locks in the correct order.

	The bond_change_active_slave and bond_select_active_slave
functions both require rtnl, bond->lock for read and curr_slave_lock for
write_bh, and no other locks.  This is so that the lower level
mode-specific functions (notably for balance-alb mode) can release locks
down to just rtnl in order to call, e.g., dev_set_mac_address with the
locks it expects (rtnl only).

Signed-off-by: Jay Vosburgh <fubar@us.ibm.com>
Signed-off-by: Andy Gospodarek <andy@greyhouse.net>
---
 drivers/net/bonding/bond_sysfs.c |   15 ++++++++++-----
 1 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 11b76b3..28a2d80 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -1075,7 +1075,10 @@ static ssize_t bonding_store_primary(struct device *d,
 	struct slave *slave;
 	struct bonding *bond = to_bond(d);
 
-	write_lock_bh(&bond->lock);
+	rtnl_lock();
+	read_lock(&bond->lock);
+	write_lock_bh(&bond->curr_slave_lock);
+
 	if (!USES_PRIMARY(bond->params.mode)) {
 		printk(KERN_INFO DRV_NAME
 		       ": %s: Unable to set primary slave; %s is in mode %d\n",
@@ -1109,8 +1112,8 @@ static ssize_t bonding_store_primary(struct device *d,
 		}
 	}
 out:
-	write_unlock_bh(&bond->lock);
-
+	write_unlock_bh(&bond->curr_slave_lock);
+	read_unlock(&bond->lock);
 	rtnl_unlock();
 
 	return count;
@@ -1190,7 +1193,8 @@ static ssize_t bonding_store_active_slave(struct device *d,
 	struct bonding *bond = to_bond(d);
 
 	rtnl_lock();
-	write_lock_bh(&bond->lock);
+	read_lock(&bond->lock);
+	write_lock_bh(&bond->curr_slave_lock);
 
 	if (!USES_PRIMARY(bond->params.mode)) {
 		printk(KERN_INFO DRV_NAME
@@ -1247,7 +1251,8 @@ static ssize_t bonding_store_active_slave(struct device *d,
 		}
 	}
 out:
-	write_unlock_bh(&bond->lock);
+	write_unlock_bh(&bond->curr_slave_lock);
+	read_unlock(&bond->lock);
 	rtnl_unlock();
 
 	return count;
-- 
1.5.3.4.206.g58ba4-dirty


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

* [PATCH 2/7] bonding: fix ASSERT_RTNL that produces spurious warnings
  2008-01-18  0:24 ` [PATCH 1/7] bonding: fix locking in sysfs primary/active selection Jay Vosburgh
@ 2008-01-18  0:24   ` Jay Vosburgh
  2008-01-18  0:24     ` [PATCH 3/7] bonding: fix locking during alb failover and slave removal Jay Vosburgh
  2008-01-18 19:39   ` [PATCH 1/7] bonding: fix locking in sysfs primary/active selection Jeff Garzik
  1 sibling, 1 reply; 14+ messages in thread
From: Jay Vosburgh @ 2008-01-18  0:24 UTC (permalink / raw)
  To: netdev
  Cc: Jeff Garzik, David Miller, Andy Gospodarek, Andrew Morton,
	Jay Vosburgh

	Move an ASSERT_RTNL down to where we should hold only RTNL;
the existing check produces spurious warnings because we hold additional
locks at _bh, tripping a debug warning in spin_lock_mutex().

Signed-off-by: Jay Vosburgh <fubar@us.ibm.com>
---
 drivers/net/bonding/bond_alb.c |    5 ++---
 1 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 25b8dbf..9b55a12 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -1601,9 +1601,6 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave
 	struct slave *swap_slave;
 	int i;
 
-	if (new_slave)
-		ASSERT_RTNL();
-
 	if (bond->curr_active_slave == new_slave) {
 		return;
 	}
@@ -1649,6 +1646,8 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave
 	write_unlock_bh(&bond->curr_slave_lock);
 	read_unlock(&bond->lock);
 
+	ASSERT_RTNL();
+
 	/* curr_active_slave must be set before calling alb_swap_mac_addr */
 	if (swap_slave) {
 		/* swap mac address */
-- 
1.5.3.4.206.g58ba4-dirty


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

* [PATCH 3/7] bonding: fix locking during alb failover and slave removal
  2008-01-18  0:24   ` [PATCH 2/7] bonding: fix ASSERT_RTNL that produces spurious warnings Jay Vosburgh
@ 2008-01-18  0:24     ` Jay Vosburgh
  2008-01-18  0:25       ` [PATCH 4/7] bonding: release slaves when master removed via sysfs Jay Vosburgh
  0 siblings, 1 reply; 14+ messages in thread
From: Jay Vosburgh @ 2008-01-18  0:24 UTC (permalink / raw)
  To: netdev
  Cc: Jeff Garzik, David Miller, Andy Gospodarek, Andrew Morton,
	Jay Vosburgh

	alb_fasten_mac_swap (actually rlb_teach_disabled_mac_on_primary)
requries RTNL and no other locks.  This could cause dev_set_promiscuity
and/or dev_set_mac_address to be called with improper locking.

	Changed callers to hold only RTNL during calls to alb_fasten_mac_swap
or functions calling it.  Updated header comments in affected functions to
reflect proper reality of locking requirements.

Signed-off-by: Jay Vosburgh <fubar@us.ibm.com>
---
 drivers/net/bonding/bond_alb.c  |   18 ++++++++++++------
 drivers/net/bonding/bond_main.c |   14 ++++++++------
 2 files changed, 20 insertions(+), 12 deletions(-)

diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 9b55a12..b57bc94 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -979,7 +979,7 @@ static void alb_swap_mac_addr(struct bonding *bond, struct slave *slave1, struct
 /*
  * Send learning packets after MAC address swap.
  *
- * Called with RTNL and bond->lock held for read.
+ * Called with RTNL and no other locks
  */
 static void alb_fasten_mac_swap(struct bonding *bond, struct slave *slave1,
 				struct slave *slave2)
@@ -987,6 +987,8 @@ static void alb_fasten_mac_swap(struct bonding *bond, struct slave *slave1,
 	int slaves_state_differ = (SLAVE_IS_OK(slave1) != SLAVE_IS_OK(slave2));
 	struct slave *disabled_slave = NULL;
 
+	ASSERT_RTNL();
+
 	/* fasten the change in the switch */
 	if (SLAVE_IS_OK(slave1)) {
 		alb_send_learning_packets(slave1, slave1->dev->dev_addr);
@@ -1031,7 +1033,7 @@ static void alb_fasten_mac_swap(struct bonding *bond, struct slave *slave1,
  * a slave that has @slave's permanet address as its current address.
  * We'll make sure that that slave no longer uses @slave's permanent address.
  *
- * Caller must hold bond lock
+ * Caller must hold RTNL and no other locks
  */
 static void alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *slave)
 {
@@ -1542,7 +1544,12 @@ int bond_alb_init_slave(struct bonding *bond, struct slave *slave)
 	return 0;
 }
 
-/* Caller must hold bond lock for write */
+/*
+ * Remove slave from tlb and rlb hash tables, and fix up MAC addresses
+ * if necessary.
+ *
+ * Caller must hold RTNL and no other locks
+ */
 void bond_alb_deinit_slave(struct bonding *bond, struct slave *slave)
 {
 	if (bond->slave_cnt > 1) {
@@ -1658,12 +1665,11 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave
 				       bond->alb_info.rlb_enabled);
 	}
 
-	read_lock(&bond->lock);
-
 	if (swap_slave) {
 		alb_fasten_mac_swap(bond, swap_slave, new_slave);
+		read_lock(&bond->lock);
 	} else {
-		/* fasten bond mac on new current slave */
+		read_lock(&bond->lock);
 		alb_send_learning_packets(new_slave, bond->dev->dev_addr);
 	}
 
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index b0b2603..77d004d 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1746,7 +1746,9 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
 		 * has been cleared (if our_slave == old_current),
 		 * but before a new active slave is selected.
 		 */
+		write_unlock_bh(&bond->lock);
 		bond_alb_deinit_slave(bond, slave);
+		write_lock_bh(&bond->lock);
 	}
 
 	if (oldcurrent == slave) {
@@ -1905,6 +1907,12 @@ static int bond_release_all(struct net_device *bond_dev)
 		slave_dev = slave->dev;
 		bond_detach_slave(bond, slave);
 
+		/* now that the slave is detached, unlock and perform
+		 * all the undo steps that should not be called from
+		 * within a lock.
+		 */
+		write_unlock_bh(&bond->lock);
+
 		if ((bond->params.mode == BOND_MODE_TLB) ||
 		    (bond->params.mode == BOND_MODE_ALB)) {
 			/* must be called only after the slave
@@ -1915,12 +1923,6 @@ static int bond_release_all(struct net_device *bond_dev)
 
 		bond_compute_features(bond);
 
-		/* now that the slave is detached, unlock and perform
-		 * all the undo steps that should not be called from
-		 * within a lock.
-		 */
-		write_unlock_bh(&bond->lock);
-
 		bond_destroy_slave_symlinks(bond_dev, slave_dev);
 		bond_del_vlans_from_slave(bond, slave_dev);
 
-- 
1.5.3.4.206.g58ba4-dirty


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

* [PATCH 4/7] bonding: release slaves when master removed via sysfs
  2008-01-18  0:24     ` [PATCH 3/7] bonding: fix locking during alb failover and slave removal Jay Vosburgh
@ 2008-01-18  0:25       ` Jay Vosburgh
  2008-01-18  0:25         ` [PATCH 5/7] bonding: Fix up parameter parsing Jay Vosburgh
  0 siblings, 1 reply; 14+ messages in thread
From: Jay Vosburgh @ 2008-01-18  0:25 UTC (permalink / raw)
  To: netdev
  Cc: Jeff Garzik, David Miller, Andy Gospodarek, Andrew Morton,
	Jay Vosburgh

	Add a call to bond_release_all in the bonding netdev event
handler for the master.  This releases the slaves for the case of, e.g.,
"echo -bond0 > /sys/class/net/bonding_masters", which otherwise will spin
forever waiting for references to be released.

Signed-off-by: Jay Vosburgh <fubar@us.ibm.com>
---
 drivers/net/bonding/bond_main.c |    4 +---
 1 files changed, 1 insertions(+), 3 deletions(-)

diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 77d004d..3ede0a2 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -3401,9 +3401,7 @@ static int bond_master_netdev_event(unsigned long event, struct net_device *bond
 	case NETDEV_CHANGENAME:
 		return bond_event_changename(event_bond);
 	case NETDEV_UNREGISTER:
-		/*
-		 * TODO: remove a bond from the list?
-		 */
+		bond_release_all(event_bond->dev);
 		break;
 	default:
 		break;
-- 
1.5.3.4.206.g58ba4-dirty


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

* [PATCH 5/7] bonding: Fix up parameter parsing
  2008-01-18  0:25       ` [PATCH 4/7] bonding: release slaves when master removed via sysfs Jay Vosburgh
@ 2008-01-18  0:25         ` Jay Vosburgh
  2008-01-18  0:25           ` [PATCH 6/7] bonding: fix lock ordering for rtnl and bonding_rwsem Jay Vosburgh
  0 siblings, 1 reply; 14+ messages in thread
From: Jay Vosburgh @ 2008-01-18  0:25 UTC (permalink / raw)
  To: netdev
  Cc: Jeff Garzik, David Miller, Andy Gospodarek, Andrew Morton,
	Jay Vosburgh

	A recent change to add an additional hash policy modified
bond_parse_parm, but it now does not correctly match parameters passed in
via sysfs.

	Rewrote bond_parse_parm to handle (a) parameter matches that
are substrings of one another and (b) user input with whitespace (e.g.,
sysfs input often has a trailing newline).

Signed-off-by: Jay Vosburgh <fubar@us.ibm.com>
---
 drivers/net/bonding/bond_main.c  |   23 ++++++++++++++++-------
 drivers/net/bonding/bond_sysfs.c |    8 ++++----
 drivers/net/bonding/bonding.h    |    4 +++-
 3 files changed, 23 insertions(+), 12 deletions(-)

diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 3ede0a2..379c5d8 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -4540,18 +4540,27 @@ static void bond_free_all(void)
 
 /*
  * Convert string input module parms.  Accept either the
- * number of the mode or its string name.
+ * number of the mode or its string name.  A bit complicated because
+ * some mode names are substrings of other names, and calls from sysfs
+ * may have whitespace in the name (trailing newlines, for example).
  */
-int bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl)
+int bond_parse_parm(const char *buf, struct bond_parm_tbl *tbl)
 {
-	int i;
+	int mode = -1, i, rv;
+	char modestr[BOND_MAX_MODENAME_LEN + 1] = { 0, };
+
+	rv = sscanf(buf, "%d", &mode);
+	if (!rv) {
+		rv = sscanf(buf, "%20s", modestr);
+		if (!rv)
+			return -1;
+	}
 
 	for (i = 0; tbl[i].modename; i++) {
-		if ((isdigit(*mode_arg) &&
-		     tbl[i].mode == simple_strtol(mode_arg, NULL, 0)) ||
-		    (strcmp(mode_arg, tbl[i].modename) == 0)) {
+		if (mode == tbl[i].mode)
+			return tbl[i].mode;
+		if (strcmp(modestr, tbl[i].modename) == 0)
 			return tbl[i].mode;
-		}
 	}
 
 	return -1;
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 28a2d80..bff4f2b 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -423,7 +423,7 @@ static ssize_t bonding_store_mode(struct device *d,
 		goto out;
 	}
 
-	new_value = bond_parse_parm((char *)buf, bond_mode_tbl);
+	new_value = bond_parse_parm(buf, bond_mode_tbl);
 	if (new_value < 0)  {
 		printk(KERN_ERR DRV_NAME
 		       ": %s: Ignoring invalid mode value %.*s.\n",
@@ -478,7 +478,7 @@ static ssize_t bonding_store_xmit_hash(struct device *d,
 		goto out;
 	}
 
-	new_value = bond_parse_parm((char *)buf, xmit_hashtype_tbl);
+	new_value = bond_parse_parm(buf, xmit_hashtype_tbl);
 	if (new_value < 0)  {
 		printk(KERN_ERR DRV_NAME
 		       ": %s: Ignoring invalid xmit hash policy value %.*s.\n",
@@ -518,7 +518,7 @@ static ssize_t bonding_store_arp_validate(struct device *d,
 	int new_value;
 	struct bonding *bond = to_bond(d);
 
-	new_value = bond_parse_parm((char *)buf, arp_validate_tbl);
+	new_value = bond_parse_parm(buf, arp_validate_tbl);
 	if (new_value < 0) {
 		printk(KERN_ERR DRV_NAME
 		       ": %s: Ignoring invalid arp_validate value %s\n",
@@ -941,7 +941,7 @@ static ssize_t bonding_store_lacp(struct device *d,
 		goto out;
 	}
 
-	new_value = bond_parse_parm((char *)buf, bond_lacp_tbl);
+	new_value = bond_parse_parm(buf, bond_lacp_tbl);
 
 	if ((new_value == 1) || (new_value == 0)) {
 		bond->params.lacp_fast = new_value;
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index e1e4734..6d83be4 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -141,6 +141,8 @@ struct bond_parm_tbl {
 	int mode;
 };
 
+#define BOND_MAX_MODENAME_LEN 20
+
 struct vlan_entry {
 	struct list_head vlan_list;
 	__be32 vlan_ip;
@@ -314,7 +316,7 @@ void bond_mii_monitor(struct work_struct *);
 void bond_loadbalance_arp_mon(struct work_struct *);
 void bond_activebackup_arp_mon(struct work_struct *);
 void bond_set_mode_ops(struct bonding *bond, int mode);
-int bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl);
+int bond_parse_parm(const char *mode_arg, struct bond_parm_tbl *tbl);
 void bond_select_active_slave(struct bonding *bond);
 void bond_change_active_slave(struct bonding *bond, struct slave *new_active);
 void bond_register_arp(struct bonding *);
-- 
1.5.3.4.206.g58ba4-dirty


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

* [PATCH 6/7] bonding: fix lock ordering for rtnl and bonding_rwsem
  2008-01-18  0:25         ` [PATCH 5/7] bonding: Fix up parameter parsing Jay Vosburgh
@ 2008-01-18  0:25           ` Jay Vosburgh
  2008-01-18  0:25             ` [PATCH 7/7] bonding: Don't hold lock when calling rtnl_unlock Jay Vosburgh
  2008-01-18  0:38             ` [PATCH 6/7] bonding: fix lock ordering for rtnl and bonding_rwsem Andrew Morton
  0 siblings, 2 replies; 14+ messages in thread
From: Jay Vosburgh @ 2008-01-18  0:25 UTC (permalink / raw)
  To: netdev
  Cc: Jeff Garzik, David Miller, Andy Gospodarek, Andrew Morton,
	Jay Vosburgh

Fix the handling of rtnl and the bonding_rwsem to always be acquired
in a consistent order (rtnl, then bonding_rwsem).

The existing code sometimes acquired them in this order, and sometimes
in the opposite order, which opens a window for deadlock between ifenslave
and sysfs.

Signed-off-by: Jay Vosburgh <fubar@us.ibm.com>
---
 drivers/net/bonding/bond_main.c  |   19 ++++++++++++++++
 drivers/net/bonding/bond_sysfs.c |   43 ++++++++++++++-----------------------
 2 files changed, 35 insertions(+), 27 deletions(-)

diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 379c5d8..2c6da49 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -4874,9 +4874,22 @@ static struct lock_class_key bonding_netdev_xmit_lock_key;
 int bond_create(char *name, struct bond_params *params, struct bonding **newbond)
 {
 	struct net_device *bond_dev;
+	struct bonding *bond, *nxt;
 	int res;
 
 	rtnl_lock();
+	down_write(&bonding_rwsem);
+
+	/* Check to see if the bond already exists. */
+	list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list)
+		if (strnicmp(bond->dev->name, name, IFNAMSIZ) == 0) {
+			printk(KERN_ERR DRV_NAME
+			       ": cannot add bond %s; it already exists\n",
+			       name);
+			res = -EPERM;
+			goto out_rtnl;
+		}
+
 	bond_dev = alloc_netdev(sizeof(struct bonding), name ? name : "",
 				ether_setup);
 	if (!bond_dev) {
@@ -4915,10 +4928,12 @@ int bond_create(char *name, struct bond_params *params, struct bonding **newbond
 
 	netif_carrier_off(bond_dev);
 
+	up_write(&bonding_rwsem);
 	rtnl_unlock(); /* allows sysfs registration of net device */
 	res = bond_create_sysfs_entry(bond_dev->priv);
 	if (res < 0) {
 		rtnl_lock();
+		down_write(&bonding_rwsem);
 		goto out_bond;
 	}
 
@@ -4929,6 +4944,7 @@ out_bond:
 out_netdev:
 	free_netdev(bond_dev);
 out_rtnl:
+	up_write(&bonding_rwsem);
 	rtnl_unlock();
 	return res;
 }
@@ -4949,6 +4965,9 @@ static int __init bonding_init(void)
 #ifdef CONFIG_PROC_FS
 	bond_create_proc_dir();
 #endif
+
+	init_rwsem(&bonding_rwsem);
+
 	for (i = 0; i < max_bonds; i++) {
 		res = bond_create(NULL, &bonding_defaults, NULL);
 		if (res)
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index bff4f2b..90a1f31 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -109,11 +109,10 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t
 {
 	char command[IFNAMSIZ + 1] = {0, };
 	char *ifname;
-	int res = count;
+	int rv, res = count;
 	struct bonding *bond;
 	struct bonding *nxt;
 
-	down_write(&(bonding_rwsem));
 	sscanf(buffer, "%16s", command); /* IFNAMSIZ*/
 	ifname = command + 1;
 	if ((strlen(command) <= 1) ||
@@ -121,39 +120,28 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t
 		goto err_no_cmd;
 
 	if (command[0] == '+') {
-
-		/* Check to see if the bond already exists. */
-		list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list)
-			if (strnicmp(bond->dev->name, ifname, IFNAMSIZ) == 0) {
-				printk(KERN_ERR DRV_NAME
-					": cannot add bond %s; it already exists\n",
-					ifname);
-				res = -EPERM;
-				goto out;
-			}
-
 		printk(KERN_INFO DRV_NAME
 			": %s is being created...\n", ifname);
-		if (bond_create(ifname, &bonding_defaults, &bond)) {
-			printk(KERN_INFO DRV_NAME
-			": %s interface already exists. Bond creation failed.\n",
-			ifname);
-			res = -EPERM;
+		rv = bond_create(ifname, &bonding_defaults, &bond);
+		if (rv) {
+			printk(KERN_INFO DRV_NAME ": Bond creation failed.\n");
+			res = rv;
 		}
 		goto out;
 	}
 
 	if (command[0] == '-') {
+		rtnl_lock();
+		down_write(&bonding_rwsem);
+
 		list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list)
 			if (strnicmp(bond->dev->name, ifname, IFNAMSIZ) == 0) {
-				rtnl_lock();
 				/* check the ref count on the bond's kobject.
 				 * If it's > expected, then there's a file open,
 				 * and we have to fail.
 				 */
 				if (atomic_read(&bond->dev->dev.kobj.kref.refcount)
 							> expected_refcount){
-					rtnl_unlock();
 					printk(KERN_INFO DRV_NAME
 						": Unable remove bond %s due to open references.\n",
 						ifname);
@@ -164,6 +152,7 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t
 					": %s is being deleted...\n",
 					bond->dev->name);
 				bond_destroy(bond);
+				up_write(&bonding_rwsem);
 				rtnl_unlock();
 				goto out;
 			}
@@ -171,6 +160,8 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t
 		printk(KERN_ERR DRV_NAME
 			": unable to delete non-existent bond %s\n", ifname);
 		res = -ENODEV;
+		up_write(&bonding_rwsem);
+		rtnl_unlock();
 		goto out;
 	}
 
@@ -183,7 +174,6 @@ err_no_cmd:
 	 * get called forever, which is bad.
 	 */
 out:
-	up_write(&(bonding_rwsem));
 	return res;
 }
 /* class attribute for bond_masters file.  This ends up in /sys/class/net */
@@ -271,6 +261,9 @@ static ssize_t bonding_store_slaves(struct device *d,
 
 	/* Note:  We can't hold bond->lock here, as bond_create grabs it. */
 
+	rtnl_lock();
+	down_write(&(bonding_rwsem));
+
 	sscanf(buffer, "%16s", command); /* IFNAMSIZ*/
 	ifname = command + 1;
 	if ((strlen(command) <= 1) ||
@@ -336,12 +329,10 @@ static ssize_t bonding_store_slaves(struct device *d,
 				dev->mtu = bond->dev->mtu;
 			}
 		}
-		rtnl_lock();
 		res = bond_enslave(bond->dev, dev);
 		bond_for_each_slave(bond, slave, i)
 			if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0)
 				slave->original_mtu = original_mtu;
-		rtnl_unlock();
 		if (res) {
 			ret = res;
 		}
@@ -359,12 +350,10 @@ static ssize_t bonding_store_slaves(struct device *d,
 		if (dev) {
 			printk(KERN_INFO DRV_NAME ": %s: Removing slave %s\n",
 				bond->dev->name, dev->name);
-			rtnl_lock();
 			if (bond->setup_by_slave)
 				res = bond_release_and_destroy(bond->dev, dev);
 			else
 				res = bond_release(bond->dev, dev);
-			rtnl_unlock();
 			if (res) {
 				ret = res;
 				goto out;
@@ -389,6 +378,8 @@ err_no_cmd:
 	ret = -EPERM;
 
 out:
+	up_write(&(bonding_rwsem));
+	rtnl_unlock();
 	return ret;
 }
 
@@ -1423,8 +1414,6 @@ int bond_create_sysfs(void)
 	int ret = 0;
 	struct bonding *firstbond;
 
-	init_rwsem(&bonding_rwsem);
-
 	/* get the netdev class pointer */
 	firstbond = container_of(bond_dev_list.next, struct bonding, bond_list);
 	if (!firstbond)
-- 
1.5.3.4.206.g58ba4-dirty


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

* [PATCH 7/7] bonding: Don't hold lock when calling rtnl_unlock
  2008-01-18  0:25           ` [PATCH 6/7] bonding: fix lock ordering for rtnl and bonding_rwsem Jay Vosburgh
@ 2008-01-18  0:25             ` Jay Vosburgh
  2008-01-18  0:38             ` [PATCH 6/7] bonding: fix lock ordering for rtnl and bonding_rwsem Andrew Morton
  1 sibling, 0 replies; 14+ messages in thread
From: Jay Vosburgh @ 2008-01-18  0:25 UTC (permalink / raw)
  To: netdev
  Cc: Jeff Garzik, David Miller, Andy Gospodarek, Andrew Morton,
	Jay Vosburgh

Change bond_mii_monitor to not hold any locks when calling rtnl_unlock,
as rtnl_unlock can sleep (when acquring another mutex in netdev_run_todo).

Bug reported by Makito SHIOKAWA <mshiokawa@miraclelinux.com>, who
included a different patch.

Signed-off-by: Jay Vosburgh <fubar@us.ibm.com>
---
 drivers/net/bonding/bond_main.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 2c6da49..49a1982 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -2386,7 +2386,9 @@ void bond_mii_monitor(struct work_struct *work)
 		rtnl_lock();
 		read_lock(&bond->lock);
 		__bond_mii_monitor(bond, 1);
-		rtnl_unlock();
+		read_unlock(&bond->lock);
+		rtnl_unlock();	/* might sleep, hold no other locks */
+		read_lock(&bond->lock);
 	}
 
 	delay = ((bond->params.miimon * HZ) / 1000) ? : 1;
-- 
1.5.3.4.206.g58ba4-dirty


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

* Re: [PATCH 6/7] bonding: fix lock ordering for rtnl and bonding_rwsem
  2008-01-18  0:25           ` [PATCH 6/7] bonding: fix lock ordering for rtnl and bonding_rwsem Jay Vosburgh
  2008-01-18  0:25             ` [PATCH 7/7] bonding: Don't hold lock when calling rtnl_unlock Jay Vosburgh
@ 2008-01-18  0:38             ` Andrew Morton
  1 sibling, 0 replies; 14+ messages in thread
From: Andrew Morton @ 2008-01-18  0:38 UTC (permalink / raw)
  To: Jay Vosburgh; +Cc: netdev, jgarzik, davem, andy, fubar

On Thu, 17 Jan 2008 16:25:02 -0800
Jay Vosburgh <fubar@us.ibm.com> wrote:

> Fix the handling of rtnl and the bonding_rwsem to always be acquired
> in a consistent order (rtnl, then bonding_rwsem).
> 
> The existing code sometimes acquired them in this order, and sometimes
> in the opposite order, which opens a window for deadlock between ifenslave
> and sysfs.
> 
> ...
>
>  int bond_create(char *name, struct bond_params *params, struct bonding **newbond)
>  {
>  	struct net_device *bond_dev;
> +	struct bonding *bond, *nxt;
>  	int res;
>  
>  	rtnl_lock();
> +	down_write(&bonding_rwsem);
> +
> +	/* Check to see if the bond already exists. */
> +	list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list)

this could (should) use list_for_each_entry().

> +		if (strnicmp(bond->dev->name, name, IFNAMSIZ) == 0) {
> +			printk(KERN_ERR DRV_NAME
> +			       ": cannot add bond %s; it already exists\n",
> +			       name);
> +			res = -EPERM;
> +			goto out_rtnl;
> +		}
> +
>  	bond_dev = alloc_netdev(sizeof(struct bonding), name ? name : "",
>  				ether_setup);
>  	if (!bond_dev) {
> @@ -4915,10 +4928,12 @@ int bond_create(char *name, struct bond_params *params, struct bonding **newbond
>  
>  	netif_carrier_off(bond_dev);
>  
> +	up_write(&bonding_rwsem);
>  	rtnl_unlock(); /* allows sysfs registration of net device */
>  	res = bond_create_sysfs_entry(bond_dev->priv);
>  	if (res < 0) {
>  		rtnl_lock();
> +		down_write(&bonding_rwsem);
>  		goto out_bond;
>  	}
>  
> @@ -4929,6 +4944,7 @@ out_bond:
>  out_netdev:
>  	free_netdev(bond_dev);
>  out_rtnl:
> +	up_write(&bonding_rwsem);
>  	rtnl_unlock();
>  	return res;
>  }
> @@ -4949,6 +4965,9 @@ static int __init bonding_init(void)
>  #ifdef CONFIG_PROC_FS
>  	bond_create_proc_dir();
>  #endif
> +
> +	init_rwsem(&bonding_rwsem);

It would be better to initialise this at compile time with DECLARE_RWSEM().


But neither of those things need to be done for 2.6.24.


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

* Re: [PATCH 1/7] bonding: fix locking in sysfs primary/active selection
  2008-01-18  0:24 ` [PATCH 1/7] bonding: fix locking in sysfs primary/active selection Jay Vosburgh
  2008-01-18  0:24   ` [PATCH 2/7] bonding: fix ASSERT_RTNL that produces spurious warnings Jay Vosburgh
@ 2008-01-18 19:39   ` Jeff Garzik
  1 sibling, 0 replies; 14+ messages in thread
From: Jeff Garzik @ 2008-01-18 19:39 UTC (permalink / raw)
  To: Jay Vosburgh; +Cc: netdev, David Miller, Andy Gospodarek, Andrew Morton

Jay Vosburgh wrote:
> 	Fix the functions that store the primary and active slave
> options via sysfs to hold the correct locks in the correct order.
> 
> 	The bond_change_active_slave and bond_select_active_slave
> functions both require rtnl, bond->lock for read and curr_slave_lock for
> write_bh, and no other locks.  This is so that the lower level
> mode-specific functions (notably for balance-alb mode) can release locks
> down to just rtnl in order to call, e.g., dev_set_mac_address with the
> locks it expects (rtnl only).
> 
> Signed-off-by: Jay Vosburgh <fubar@us.ibm.com>
> Signed-off-by: Andy Gospodarek <andy@greyhouse.net>
> ---
>  drivers/net/bonding/bond_sysfs.c |   15 ++++++++++-----
>  1 files changed, 10 insertions(+), 5 deletions(-)

applied 1-7



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

* Re: [PATCH 0/7] bonding: 7 fixes for 2.6.24
  2008-01-18  0:24 [PATCH 0/7] bonding: 7 fixes for 2.6.24 Jay Vosburgh
  2008-01-18  0:24 ` [PATCH 1/7] bonding: fix locking in sysfs primary/active selection Jay Vosburgh
@ 2008-01-21  1:15 ` David Miller
  2008-01-21  1:36   ` Andrew Morton
  2008-01-21  1:57   ` Jeff Garzik
  1 sibling, 2 replies; 14+ messages in thread
From: David Miller @ 2008-01-21  1:15 UTC (permalink / raw)
  To: fubar; +Cc: netdev, jgarzik, andy, akpm

From: Jay Vosburgh <fubar@us.ibm.com>
Date: Thu, 17 Jan 2008 16:24:56 -0800

> 	Following are seven patches to fix locking problems,
> silence locking-related warnings and resolve one recent regression
> in the current 2.6.24-rc.

Jeff, are you going to merge this stuff in?

I'll drop that rtnl_lock() one-liner if so...

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

* Re: [PATCH 0/7] bonding: 7 fixes for 2.6.24
  2008-01-21  1:15 ` [PATCH 0/7] bonding: 7 fixes for 2.6.24 David Miller
@ 2008-01-21  1:36   ` Andrew Morton
  2008-01-21  3:58     ` David Miller
  2008-01-21  1:57   ` Jeff Garzik
  1 sibling, 1 reply; 14+ messages in thread
From: Andrew Morton @ 2008-01-21  1:36 UTC (permalink / raw)
  To: David Miller; +Cc: fubar, netdev, jgarzik, andy

On Sun, 20 Jan 2008 17:15:38 -0800 (PST) David Miller <davem@davemloft.net> wrote:

> From: Jay Vosburgh <fubar@us.ibm.com>
> Date: Thu, 17 Jan 2008 16:24:56 -0800
> 
> > 	Following are seven patches to fix locking problems,
> > silence locking-related warnings and resolve one recent regression
> > in the current 2.6.24-rc.
> 
> Jeff, are you going to merge this stuff in?
> 
> I'll drop that rtnl_lock() one-liner if so...

It's all in mainline.  The one-liner should be unneeded.

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

* Re: [PATCH 0/7] bonding: 7 fixes for 2.6.24
  2008-01-21  1:15 ` [PATCH 0/7] bonding: 7 fixes for 2.6.24 David Miller
  2008-01-21  1:36   ` Andrew Morton
@ 2008-01-21  1:57   ` Jeff Garzik
  1 sibling, 0 replies; 14+ messages in thread
From: Jeff Garzik @ 2008-01-21  1:57 UTC (permalink / raw)
  To: David Miller; +Cc: fubar, netdev, andy, akpm

David Miller wrote:
> From: Jay Vosburgh <fubar@us.ibm.com>
> Date: Thu, 17 Jan 2008 16:24:56 -0800
> 
>> 	Following are seven patches to fix locking problems,
>> silence locking-related warnings and resolve one recent regression
>> in the current 2.6.24-rc.
> 
> Jeff, are you going to merge this stuff in?
> 
> I'll drop that rtnl_lock() one-liner if so...

Linus has this series in linux-2.6.git, even...

	Jeff




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

* Re: [PATCH 0/7] bonding: 7 fixes for 2.6.24
  2008-01-21  1:36   ` Andrew Morton
@ 2008-01-21  3:58     ` David Miller
  0 siblings, 0 replies; 14+ messages in thread
From: David Miller @ 2008-01-21  3:58 UTC (permalink / raw)
  To: akpm; +Cc: fubar, netdev, jgarzik, andy

From: Andrew Morton <akpm@linux-foundation.org>
Date: Sun, 20 Jan 2008 17:36:44 -0800

> On Sun, 20 Jan 2008 17:15:38 -0800 (PST) David Miller <davem@davemloft.net> wrote:
> 
> > From: Jay Vosburgh <fubar@us.ibm.com>
> > Date: Thu, 17 Jan 2008 16:24:56 -0800
> > 
> > > 	Following are seven patches to fix locking problems,
> > > silence locking-related warnings and resolve one recent regression
> > > in the current 2.6.24-rc.
> > 
> > Jeff, are you going to merge this stuff in?
> > 
> > I'll drop that rtnl_lock() one-liner if so...
> 
> It's all in mainline.  The one-liner should be unneeded.

Excellent.

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

end of thread, other threads:[~2008-01-21  3:58 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-01-18  0:24 [PATCH 0/7] bonding: 7 fixes for 2.6.24 Jay Vosburgh
2008-01-18  0:24 ` [PATCH 1/7] bonding: fix locking in sysfs primary/active selection Jay Vosburgh
2008-01-18  0:24   ` [PATCH 2/7] bonding: fix ASSERT_RTNL that produces spurious warnings Jay Vosburgh
2008-01-18  0:24     ` [PATCH 3/7] bonding: fix locking during alb failover and slave removal Jay Vosburgh
2008-01-18  0:25       ` [PATCH 4/7] bonding: release slaves when master removed via sysfs Jay Vosburgh
2008-01-18  0:25         ` [PATCH 5/7] bonding: Fix up parameter parsing Jay Vosburgh
2008-01-18  0:25           ` [PATCH 6/7] bonding: fix lock ordering for rtnl and bonding_rwsem Jay Vosburgh
2008-01-18  0:25             ` [PATCH 7/7] bonding: Don't hold lock when calling rtnl_unlock Jay Vosburgh
2008-01-18  0:38             ` [PATCH 6/7] bonding: fix lock ordering for rtnl and bonding_rwsem Andrew Morton
2008-01-18 19:39   ` [PATCH 1/7] bonding: fix locking in sysfs primary/active selection Jeff Garzik
2008-01-21  1:15 ` [PATCH 0/7] bonding: 7 fixes for 2.6.24 David Miller
2008-01-21  1:36   ` Andrew Morton
2008-01-21  3:58     ` David Miller
2008-01-21  1:57   ` Jeff Garzik

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).