From patchwork Sun Jun 16 17:20:44 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Veaceslav Falico X-Patchwork-Id: 251728 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 1A7D32C0097 for ; Mon, 17 Jun 2013 03:20:21 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755379Ab3FPRUQ (ORCPT ); Sun, 16 Jun 2013 13:20:16 -0400 Received: from mx1.redhat.com ([209.132.183.28]:27950 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755369Ab3FPRUP (ORCPT ); Sun, 16 Jun 2013 13:20:15 -0400 Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id r5GHKCDq025142 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Sun, 16 Jun 2013 13:20:12 -0400 Received: from darkmag.usersys.redhat.com (dhcp-27-204.brq.redhat.com [10.34.27.204]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id r5GHK8Do020199; Sun, 16 Jun 2013 13:20:09 -0400 From: Veaceslav Falico To: netdev@vger.kernel.org Cc: fubar@us.ibm.com, andy@greyhouse.net, vfalico@redhat.com Subject: [PATCH net-next] bonding: don't call alb_set_slave_mac_addr() while atomic Date: Sun, 16 Jun 2013 19:20:44 +0200 Message-Id: <1371403244-2891-1-git-send-email-vfalico@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.24 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org alb_set_slave_mac_addr() sets the mac address in alb mode via dev_set_mac_address(), which might sleep. It's called from alb_handle_addr_collision_on_attach() in atomic context (under read_lock(bond->lock)), thus triggering a bug. Fix this by moving the lock inside alb_handle_addr_collision_on_attach(). Signed-off-by: Veaceslav Falico --- drivers/net/bonding/bond_alb.c | 21 ++++++++++----------- 1 files changed, 10 insertions(+), 11 deletions(-) diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index a236234..3f14f99 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -1175,10 +1175,7 @@ static void alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *sla * @slave. * * assumption: this function is called before @slave is attached to the - * bond slave list. - * - * caller must hold the bond lock for write since the mac addresses are compared - * and may be swapped. + * bond slave list. */ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slave *slave) { @@ -1196,6 +1193,9 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav * slaves in the bond. */ if (!ether_addr_equal_64bits(slave->perm_hwaddr, bond->dev->dev_addr)) { + + read_lock(&bond->lock); + bond_for_each_slave(bond, tmp_slave1, i) { if (ether_addr_equal_64bits(tmp_slave1->dev->dev_addr, slave->dev->dev_addr)) { @@ -1204,6 +1204,8 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav } } + read_unlock(&bond->lock); + if (!found) return 0; @@ -1217,6 +1219,8 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav */ free_mac_slave = NULL; + read_lock(&bond->lock); + bond_for_each_slave(bond, tmp_slave1, i) { found = 0; bond_for_each_slave(bond, tmp_slave2, j) { @@ -1244,6 +1248,8 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav } } + read_unlock(&bond->lock); + if (free_mac_slave) { alb_set_slave_mac_addr(slave, free_mac_slave->perm_hwaddr); @@ -1607,15 +1613,8 @@ int bond_alb_init_slave(struct bonding *bond, struct slave *slave) return res; } - /* caller must hold the bond lock for write since the mac addresses - * are compared and may be swapped. - */ - read_lock(&bond->lock); - res = alb_handle_addr_collision_on_attach(bond, slave); - read_unlock(&bond->lock); - if (res) { return res; }