From patchwork Thu Mar 12 15:20:18 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan-Bernd Themann X-Patchwork-Id: 24345 Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from ozlabs.org (localhost [127.0.0.1]) by ozlabs.org (Postfix) with ESMTP id A2E54DE465 for ; Fri, 13 Mar 2009 02:22:03 +1100 (EST) X-Original-To: linuxppc-dev@ozlabs.org Delivered-To: linuxppc-dev@ozlabs.org Received: from mtagate5.uk.ibm.com (mtagate5.uk.ibm.com [195.212.29.138]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "mtagate5.uk.ibm.com", Issuer "Equifax" (verified OK)) by ozlabs.org (Postfix) with ESMTPS id F1DD9DDF4A for ; Fri, 13 Mar 2009 02:21:34 +1100 (EST) Received: from d06nrmr1707.portsmouth.uk.ibm.com (d06nrmr1707.portsmouth.uk.ibm.com [9.149.39.225]) by mtagate5.uk.ibm.com (8.14.3/8.13.8) with ESMTP id n2CFKOL3366806 for ; Thu, 12 Mar 2009 15:20:24 GMT Received: from d06av02.portsmouth.uk.ibm.com (d06av02.portsmouth.uk.ibm.com [9.149.37.228]) by d06nrmr1707.portsmouth.uk.ibm.com (8.13.8/8.13.8/NCO v9.2) with ESMTP id n2CFKO0l1548318 for ; Thu, 12 Mar 2009 15:20:24 GMT Received: from d06av02.portsmouth.uk.ibm.com (loopback [127.0.0.1]) by d06av02.portsmouth.uk.ibm.com (8.12.11.20060308/8.13.3) with ESMTP id n2CFKN1P014812 for ; Thu, 12 Mar 2009 15:20:24 GMT Received: from dyn-9-152-241-108.boeblingen.de.ibm.com (dyn-9-152-241-108.boeblingen.de.ibm.com [9.152.241.108]) by d06av02.portsmouth.uk.ibm.com (8.12.11.20060308/8.12.11) with ESMTP id n2CFKJ0f014693 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Thu, 12 Mar 2009 15:20:23 GMT From: "Jan-Bernd Themann" Organization: IBM To: David Miller Subject: [PATCH net-next-2.6] ehea: fix circular locking problem Date: Thu, 12 Mar 2009 16:20:18 +0100 User-Agent: KMail/1.9.9 MIME-Version: 1.0 Content-Disposition: inline Message-Id: <200903121620.19075.ossthema@de.ibm.com> Cc: tklein@de.ibm.com, Hannes Hering , netdev@vger.kernel.org, themann@de.ibm.com, linux-kernel , linuxppc-dev@ozlabs.org, raisch@de.ibm.com X-BeenThere: linuxppc-dev@ozlabs.org X-Mailman-Version: 2.1.11 Precedence: list List-Id: Linux on PowerPC Developers Mail List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@ozlabs.org Errors-To: linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@ozlabs.org This patch fixes the circular locking problem by changing the locking strategy concerning the logging of firmware handles. Signed-off-by: Jan-Bernd Themann --- drivers/net/ehea/ehea.h | 2 +- drivers/net/ehea/ehea_main.c | 56 ++++++++++++++++++++++------------------- 2 files changed, 31 insertions(+), 27 deletions(-) diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h index 029631c..6e317ca 100644 --- a/drivers/net/ehea/ehea.h +++ b/drivers/net/ehea/ehea.h @@ -40,7 +40,7 @@ #include #define DRV_NAME "ehea" -#define DRV_VERSION "EHEA_0099" +#define DRV_VERSION "EHEA_0100" /* eHEA capability flags */ #define DLPAR_PORT_ADD_REM 1 diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 40c34bf..ac0c5b4 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -155,6 +155,8 @@ static void ehea_update_firmware_handles(void) int num_fw_handles, k, l; /* Determine number of handles */ + mutex_lock(&ehea_fw_handles.lock); + list_for_each_entry(adapter, &adapter_list, list) { num_adapters++; @@ -176,15 +178,19 @@ static void ehea_update_firmware_handles(void) if (num_fw_handles) { arr = kzalloc(num_fw_handles * sizeof(*arr), GFP_KERNEL); if (!arr) - return; /* Keep the existing array */ + goto out; /* Keep the existing array */ } else goto out_update; list_for_each_entry(adapter, &adapter_list, list) { + if (num_adapters == 0) + break; + for (k = 0; k < EHEA_MAX_PORTS; k++) { struct ehea_port *port = adapter->port[k]; - if (!port || (port->state != EHEA_PORT_UP)) + if (!port || (port->state != EHEA_PORT_UP) + || (num_ports == 0)) continue; for (l = 0; @@ -207,6 +213,7 @@ static void ehea_update_firmware_handles(void) } arr[i].adh = adapter->handle; arr[i++].fwh = port->qp_eq->fw_handle; + num_ports--; } arr[i].adh = adapter->handle; @@ -216,16 +223,20 @@ static void ehea_update_firmware_handles(void) arr[i].adh = adapter->handle; arr[i++].fwh = adapter->mr.handle; } + num_adapters--; } out_update: kfree(ehea_fw_handles.arr); ehea_fw_handles.arr = arr; ehea_fw_handles.num_entries = i; +out: + mutex_unlock(&ehea_fw_handles.lock); } static void ehea_update_bcmc_registrations(void) { + unsigned long flags; struct ehea_bcmc_reg_entry *arr = NULL; struct ehea_adapter *adapter; struct ehea_mc_list *mc_entry; @@ -233,6 +244,8 @@ static void ehea_update_bcmc_registrations(void) int i = 0; int k; + spin_lock_irqsave(&ehea_bcmc_regs.lock, flags); + /* Determine number of registrations */ list_for_each_entry(adapter, &adapter_list, list) for (k = 0; k < EHEA_MAX_PORTS; k++) { @@ -250,7 +263,7 @@ static void ehea_update_bcmc_registrations(void) if (num_registrations) { arr = kzalloc(num_registrations * sizeof(*arr), GFP_ATOMIC); if (!arr) - return; /* Keep the existing array */ + goto out; /* Keep the existing array */ } else goto out_update; @@ -261,6 +274,9 @@ static void ehea_update_bcmc_registrations(void) if (!port || (port->state != EHEA_PORT_UP)) continue; + if (num_registrations == 0) + goto out_update; + arr[i].adh = adapter->handle; arr[i].port_id = port->logical_port_id; arr[i].reg_type = EHEA_BCMC_BROADCAST | @@ -272,9 +288,13 @@ static void ehea_update_bcmc_registrations(void) arr[i].reg_type = EHEA_BCMC_BROADCAST | EHEA_BCMC_VLANID_ALL; arr[i++].macaddr = port->mac_addr; + num_registrations -= 2; list_for_each_entry(mc_entry, &port->mc_list->list, list) { + if (num_registrations == 0) + goto out_update; + arr[i].adh = adapter->handle; arr[i].port_id = port->logical_port_id; arr[i].reg_type = EHEA_BCMC_SCOPE_ALL | @@ -288,6 +308,7 @@ static void ehea_update_bcmc_registrations(void) EHEA_BCMC_MULTICAST | EHEA_BCMC_VLANID_ALL; arr[i++].macaddr = mc_entry->macaddr; + num_registrations -= 2; } } } @@ -296,6 +317,8 @@ out_update: kfree(ehea_bcmc_regs.arr); ehea_bcmc_regs.arr = arr; ehea_bcmc_regs.num_entries = i; +out: + spin_unlock_irqrestore(&ehea_bcmc_regs.lock, flags); } static struct net_device_stats *ehea_get_stats(struct net_device *dev) @@ -1762,8 +1785,6 @@ static int ehea_set_mac_addr(struct net_device *dev, void *sa) memcpy(dev->dev_addr, mac_addr->sa_data, dev->addr_len); - spin_lock(&ehea_bcmc_regs.lock); - /* Deregister old MAC in pHYP */ if (port->state == EHEA_PORT_UP) { ret = ehea_broadcast_reg_helper(port, H_DEREG_BCMC); @@ -1784,7 +1805,6 @@ static int ehea_set_mac_addr(struct net_device *dev, void *sa) out_upregs: ehea_update_bcmc_registrations(); - spin_unlock(&ehea_bcmc_regs.lock); out_free: free_page((unsigned long)cb0); out: @@ -1946,8 +1966,6 @@ static void ehea_set_multicast_list(struct net_device *dev) } ehea_promiscuous(dev, 0); - spin_lock(&ehea_bcmc_regs.lock); - if (dev->flags & IFF_ALLMULTI) { ehea_allmulti(dev, 1); goto out; @@ -1977,7 +1995,6 @@ static void ehea_set_multicast_list(struct net_device *dev) } out: ehea_update_bcmc_registrations(); - spin_unlock(&ehea_bcmc_regs.lock); return; } @@ -2458,8 +2475,6 @@ static int ehea_up(struct net_device *dev) if (port->state == EHEA_PORT_UP) return 0; - mutex_lock(&ehea_fw_handles.lock); - ret = ehea_port_res_setup(port, port->num_def_qps, port->num_add_tx_qps); if (ret) { @@ -2496,8 +2511,6 @@ static int ehea_up(struct net_device *dev) } } - spin_lock(&ehea_bcmc_regs.lock); - ret = ehea_broadcast_reg_helper(port, H_REG_BCMC); if (ret) { ret = -EIO; @@ -2519,10 +2532,7 @@ out: ehea_info("Failed starting %s. ret=%i", dev->name, ret); ehea_update_bcmc_registrations(); - spin_unlock(&ehea_bcmc_regs.lock); - ehea_update_firmware_handles(); - mutex_unlock(&ehea_fw_handles.lock); return ret; } @@ -2572,9 +2582,6 @@ static int ehea_down(struct net_device *dev) if (port->state == EHEA_PORT_DOWN) return 0; - mutex_lock(&ehea_fw_handles.lock); - - spin_lock(&ehea_bcmc_regs.lock); ehea_drop_multicast_list(dev); ehea_broadcast_reg_helper(port, H_DEREG_BCMC); @@ -2583,7 +2590,6 @@ static int ehea_down(struct net_device *dev) port->state = EHEA_PORT_DOWN; ehea_update_bcmc_registrations(); - spin_unlock(&ehea_bcmc_regs.lock); ret = ehea_clean_all_portres(port); if (ret) @@ -2591,7 +2597,6 @@ static int ehea_down(struct net_device *dev) dev->name, ret); ehea_update_firmware_handles(); - mutex_unlock(&ehea_fw_handles.lock); return ret; } @@ -3368,7 +3373,6 @@ static int __devinit ehea_probe_adapter(struct of_device *dev, ehea_error("Invalid ibmebus device probed"); return -EINVAL; } - mutex_lock(&ehea_fw_handles.lock); adapter = kzalloc(sizeof(*adapter), GFP_KERNEL); if (!adapter) { @@ -3453,7 +3457,7 @@ out_free_ad: out: ehea_update_firmware_handles(); - mutex_unlock(&ehea_fw_handles.lock); + return ret; } @@ -3472,8 +3476,6 @@ static int __devexit ehea_remove(struct of_device *dev) flush_scheduled_work(); - mutex_lock(&ehea_fw_handles.lock); - ibmebus_free_irq(adapter->neq->attr.ist1, adapter); tasklet_kill(&adapter->neq_tasklet); @@ -3483,7 +3485,6 @@ static int __devexit ehea_remove(struct of_device *dev) kfree(adapter); ehea_update_firmware_handles(); - mutex_unlock(&ehea_fw_handles.lock); return 0; } @@ -3532,6 +3533,9 @@ static int ehea_mem_notifier(struct notifier_block *nb, default: break; } + + ehea_update_firmware_handles(); + return NOTIFY_OK; }