From patchwork Thu Dec 3 20:29:38 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jarek Poplawski X-Patchwork-Id: 40240 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.176.167]) by ozlabs.org (Postfix) with ESMTP id BDF97B7C06 for ; Fri, 4 Dec 2009 07:30:19 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754192AbZLCUaG (ORCPT ); Thu, 3 Dec 2009 15:30:06 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1753265AbZLCUaG (ORCPT ); Thu, 3 Dec 2009 15:30:06 -0500 Received: from mail-bw0-f227.google.com ([209.85.218.227]:54420 "EHLO mail-bw0-f227.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753482AbZLCUaE (ORCPT ); Thu, 3 Dec 2009 15:30:04 -0500 Received: by bwz27 with SMTP id 27so1476536bwz.21 for ; Thu, 03 Dec 2009 12:30:10 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:date:from:to:cc:subject :message-id:references:mime-version:content-type:content-disposition :content-transfer-encoding:in-reply-to:user-agent; bh=E3tLtMWJXeng6TSYJlzRfg7/Z91isTbc9W01c622yNg=; b=j+uJkDU/NGUdqseKfPQ+dXM1YGWC9kC9H2nbeVoi6WIOTQJnhTCBtBOAl3ccoEwaWk Yqqud1xYe9QQT0K1o36XuhF6x/DCVi0R4MkbkZ34INN3zyUXt3cna7kNscrakM5bSVAZ Al12XUA9oOGjtVuH/JkC+rsUB6MjYDXn82eaM= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=date:from:to:cc:subject:message-id:references:mime-version :content-type:content-disposition:content-transfer-encoding :in-reply-to:user-agent; b=fjK8RJ0YxI8yzhbkBvojV7TTcvfo5LVyP9zveFS5U1uWdU6ddQuyrVSNW+HCITNKEw lM7rdte9+SPhOjjxHGplZW/n3dMpru7x1RhYpyTkfZYJgQgT8y46FyqO4FO++WEUZA4D ZiGV62SdH1VVH+aFWVzb4kc3m+pASk2PiL2aY= Received: by 10.204.8.155 with SMTP id h27mr2237482bkh.55.1259872209017; Thu, 03 Dec 2009 12:30:09 -0800 (PST) Received: from ami.dom.local (public77142.xdsl.centertel.pl [79.162.173.86]) by mx.google.com with ESMTPS id 2sm2890791fks.13.2009.12.03.12.30.04 (version=SSLv3 cipher=RC4-MD5); Thu, 03 Dec 2009 12:30:05 -0800 (PST) Date: Thu, 3 Dec 2009 21:29:38 +0100 From: Jarek Poplawski To: Eric Dumazet Cc: David Miller , mchan@broadcom.com, kaber@trash.net, netdev@vger.kernel.org Subject: [PATCH v4] net: Introduce realloc_netdev_mq() Message-ID: <20091203202937.GA11436@ami.dom.local> References: <20091101132017.GA2598@ami.dom.local> <20091102.033533.08766686.davem@davemloft.net> <20091102123029.GA7790@ff.dom.local> <20091102.043907.236634594.davem@davemloft.net> <20091203143918.GA20526@ff.dom.local> <4B17D697.8000105@gmail.com> <20091203163640.GA2584@ami.dom.local> <20091203165449.GA2960@ami.dom.local> <4B17EFE3.4080301@gmail.com> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <4B17EFE3.4080301@gmail.com> User-Agent: Mutt/1.5.20 (2009-06-14) Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org On Thu, Dec 03, 2009 at 06:05:39PM +0100, Eric Dumazet wrote: > Jarek Poplawski a écrit : > > On Thu, Dec 03, 2009 at 05:36:40PM +0100, Jarek Poplawski wrote: > >> On Thu, Dec 03, 2009 at 04:17:43PM +0100, Eric Dumazet wrote: > >>> if (realloc_netdev_mq(dev, real_queues)) > >>> dev->real_num_tx_queues = real_queues; > >>> > >>> In this case the memory error is not fatal. > >> Good point! We can consider doing this inside the function too? > > > > Hmm... Of course, not exactly this - I mean using min(). > > Sure, allowing to reduce the count in case new allocation failed. > > And report an error if caller wanted to increase number of queues and allocation failed. Hmm... After re-thinking it looks a bit too complex to me. I think, there is no reason to not report this error since in most cases it shouldn't be fatal. That's why I skipped this check in the changelog example. Unless I miss something? Thanks, Jarek P. ---------------> (take 4) This patch separates allocation of TX subqueues from alloc_netdev_mq() to realloc_netdev_mq() to allow for resizing like in this example: some_nic_probe() { ... dev = alloc_etherdev_mq(sizeof(*bp), 1) ... if (MSI-X_available && device_supports_MSI-X_and_multiqueue) realloc_netdev_mq(dev, TX_MAX_RINGS) register_netdev(dev) ... } Alternatively, it can be done in reverse order: starting from the highest queue_count and reallocating with a lower one. The main difference is to hold in num_tx_queues something that is really available, instead of max possible value for all configs, in case of drivers allocating net_device at the beginning of the probe. The description of alloc_netdev_mq() is fixed btw. Reported-by: Eric Dumazet Signed-off-by: Jarek Poplawski Cc: Eric Dumazet Acked-by: Eric Dumazet --- include/linux/netdevice.h | 1 + net/core/dev.c | 69 ++++++++++++++++++++++++++++++++------------ 2 files changed, 51 insertions(+), 19 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index daf13d3..36cbd53 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1904,6 +1904,7 @@ extern void ether_setup(struct net_device *dev); extern struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, void (*setup)(struct net_device *), unsigned int queue_count); +extern int realloc_netdev_mq(struct net_device *dev, unsigned int queue_count); #define alloc_netdev(sizeof_priv, name, setup) \ alloc_netdev_mq(sizeof_priv, name, setup, 1) extern int register_netdev(struct net_device *dev); diff --git a/net/core/dev.c b/net/core/dev.c index e3e18de..1f45bae 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5265,11 +5265,53 @@ static void netdev_init_one_queue(struct net_device *dev, queue->dev = dev; } -static void netdev_init_queues(struct net_device *dev) +/** + * realloc_netdev_mq - (re)allocate network subqueues + * @dev: device + * @queue_count: the number of subqueues to (re)allocate + * + * (Re)allocates and initializes subqueue structs for each queue. + * It is allowed to use only until register_netdev(). + * On error previous structs are intact, but dev->real_num_tx_queue is + * replaced if the queue_count is lower. + */ +int realloc_netdev_mq(struct net_device *dev, unsigned int queue_count) { - netdev_init_one_queue(dev, &dev->rx_queue, NULL); + struct netdev_queue *tx; + + tx = kcalloc(queue_count, sizeof(struct netdev_queue), GFP_KERNEL); + if (!tx) { + printk(KERN_ERR "alloc_netdev: Unable to (re)allocate " + "tx qdiscs.\n"); + if (dev->real_num_tx_queues > queue_count) + dev->real_num_tx_queues = queue_count; + + return -ENOMEM; + } + + kfree(dev->_tx); + + dev->_tx = tx; + dev->num_tx_queues = queue_count; + dev->real_num_tx_queues = queue_count; + netdev_for_each_tx_queue(dev, netdev_init_one_queue, NULL); + + return 0; +} +EXPORT_SYMBOL(realloc_netdev_mq); + +static int netdev_init_queues(struct net_device *dev, unsigned int queue_count) +{ + int err = realloc_netdev_mq(dev, queue_count); + + if (err) + return err; + + netdev_init_one_queue(dev, &dev->rx_queue, NULL); spin_lock_init(&dev->tx_global_lock); + + return 0; } /** @@ -5280,13 +5322,12 @@ static void netdev_init_queues(struct net_device *dev) * @queue_count: the number of subqueues to allocate * * Allocates a struct net_device with private data area for driver use - * and performs basic initialization. Also allocates subquue structs - * for each queue on the device at the end of the netdevice. + * and performs basic initialization. Also allocates subqueue structs + * for each queue on the device. */ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, void (*setup)(struct net_device *), unsigned int queue_count) { - struct netdev_queue *tx; struct net_device *dev; size_t alloc_size; struct net_device *p; @@ -5308,16 +5349,12 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, return NULL; } - tx = kcalloc(queue_count, sizeof(struct netdev_queue), GFP_KERNEL); - if (!tx) { - printk(KERN_ERR "alloc_netdev: Unable to allocate " - "tx qdiscs.\n"); - goto free_p; - } - dev = PTR_ALIGN(p, NETDEV_ALIGN); dev->padded = (char *)dev - (char *)p; + if (netdev_init_queues(dev, queue_count)) + goto free_p; + if (dev_addr_init(dev)) goto free_tx; @@ -5325,14 +5362,8 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, dev_net_set(dev, &init_net); - dev->_tx = tx; - dev->num_tx_queues = queue_count; - dev->real_num_tx_queues = queue_count; - dev->gso_max_size = GSO_MAX_SIZE; - netdev_init_queues(dev); - INIT_LIST_HEAD(&dev->napi_list); INIT_LIST_HEAD(&dev->unreg_list); INIT_LIST_HEAD(&dev->link_watch_list); @@ -5342,7 +5373,7 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, return dev; free_tx: - kfree(tx); + kfree(dev->_tx); free_p: kfree(p);