netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 3/3] net: allocate tx queues in register_netdevice
@ 2010-10-18 18:02 Tom Herbert
  2010-10-18 21:41 ` Ben Hutchings
  0 siblings, 1 reply; 5+ messages in thread
From: Tom Herbert @ 2010-10-18 18:02 UTC (permalink / raw)
  To: davem, netdev; +Cc: eric.dumazet, bhutchings

This patch introduces netif_alloc_netdev_queues which is called from
register_device instead of alloc_netdev_mq.  This makes TX queue
allocation symmetric with RX allocation similarly allows drivers to
change dev->num_tx_queues after allocating netdev and before
registering it.  Also, queue locks allocation is done in
netdev_init_one_queue.

Signed-off-by: Tom Herbert <therbert@google.com>
---
 include/linux/netdevice.h |    4 +-
 net/core/dev.c            |  112 +++++++++++++++++++++++----------------------
 2 files changed, 60 insertions(+), 56 deletions(-)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 14fbb04..880d565 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1696,8 +1696,8 @@ static inline int netif_is_multiqueue(const struct net_device *dev)
 	return dev->num_tx_queues > 1;
 }
 
-extern void netif_set_real_num_tx_queues(struct net_device *dev,
-					 unsigned int txq);
+extern int netif_set_real_num_tx_queues(struct net_device *dev,
+					unsigned int txq);
 
 #ifdef CONFIG_RPS
 extern int netif_set_real_num_rx_queues(struct net_device *dev,
diff --git a/net/core/dev.c b/net/core/dev.c
index 77b860d..c7b8d5a 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1553,18 +1553,24 @@ static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
  * Routine to help set real_num_tx_queues. To avoid skbs mapped to queues
  * greater then real_num_tx_queues stale skbs on the qdisc must be flushed.
  */
-void netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq)
+int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq)
 {
-	unsigned int real_num = dev->real_num_tx_queues;
+	if (txq < 1)
+		return -EINVAL;
 
-	if (unlikely(txq > dev->num_tx_queues))
-		;
-	else if (txq > real_num)
-		dev->real_num_tx_queues = txq;
-	else if (txq < real_num) {
-		dev->real_num_tx_queues = txq;
-		qdisc_reset_all_tx_gt(dev, txq);
-	}
+	if (dev->reg_state == NETREG_REGISTERED) {
+		ASSERT_RTNL();
+
+		if (txq > dev->num_tx_queues)
+			return -EINVAL;
+
+		if (txq < dev->real_num_tx_queues)
+			qdisc_reset_all_tx_gt(dev, txq);
+	} else
+		dev->num_tx_queues = txq;
+
+	dev->real_num_tx_queues = txq;
+	return 0;
 }
 EXPORT_SYMBOL(netif_set_real_num_tx_queues);
 
@@ -4932,20 +4938,6 @@ static void rollback_registered(struct net_device *dev)
 	rollback_registered_many(&single);
 }
 
-static void __netdev_init_queue_locks_one(struct net_device *dev,
-					  struct netdev_queue *dev_queue,
-					  void *_unused)
-{
-	spin_lock_init(&dev_queue->_xmit_lock);
-	netdev_set_xmit_lockdep_class(&dev_queue->_xmit_lock, dev->type);
-	dev_queue->xmit_lock_owner = -1;
-}
-
-static void netdev_init_queue_locks(struct net_device *dev)
-{
-	netdev_for_each_tx_queue(dev, __netdev_init_queue_locks_one, NULL);
-}
-
 unsigned long netdev_fix_features(unsigned long features, const char *name)
 {
 	/* Fix illegal SG+CSUM combinations. */
@@ -5038,6 +5030,41 @@ static int netif_alloc_rx_queues(struct net_device *dev)
 	return 0;
 }
 
+static int netif_alloc_netdev_queues(struct net_device *dev)
+{
+	unsigned int count = dev->num_tx_queues;
+	struct netdev_queue *tx;
+
+	BUG_ON(count < 1);
+
+	tx = kcalloc(count, sizeof(struct netdev_queue), GFP_KERNEL);
+	if (!tx) {
+		pr_err("netdev: Unable to allocate %u tx queues.\n",
+		       count);
+			return -ENOMEM;
+	}
+	dev->_tx = tx;
+	return 0;
+}
+
+static void netdev_init_one_queue(struct net_device *dev,
+				  struct netdev_queue *queue,
+				  void *_unused)
+{
+	queue->dev = dev;
+
+	/* Initialize queue lock */
+	spin_lock_init(&queue->_xmit_lock);
+	netdev_set_xmit_lockdep_class(&queue->_xmit_lock, dev->type);
+	queue->xmit_lock_owner = -1;
+}
+
+static void netdev_init_queues(struct net_device *dev)
+{
+	netdev_for_each_tx_queue(dev, netdev_init_one_queue, NULL);
+	spin_lock_init(&dev->tx_global_lock);
+}
+
 /**
  *	register_netdevice	- register a network device
  *	@dev: device to register
@@ -5071,7 +5098,6 @@ int register_netdevice(struct net_device *dev)
 
 	spin_lock_init(&dev->addr_list_lock);
 	netdev_set_addr_lockdep_class(dev);
-	netdev_init_queue_locks(dev);
 
 	dev->iflink = -1;
 
@@ -5079,6 +5105,12 @@ int register_netdevice(struct net_device *dev)
 	if (ret)
 		goto out;
 
+	ret = netif_alloc_netdev_queues(dev);
+	if (ret)
+		goto out;
+
+	netdev_init_queues(dev);
+
 	/* Init, if this function is available */
 	if (dev->netdev_ops->ndo_init) {
 		ret = dev->netdev_ops->ndo_init(dev);
@@ -5460,19 +5492,6 @@ struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev,
 }
 EXPORT_SYMBOL(dev_get_stats);
 
-static void netdev_init_one_queue(struct net_device *dev,
-				  struct netdev_queue *queue,
-				  void *_unused)
-{
-	queue->dev = dev;
-}
-
-static void netdev_init_queues(struct net_device *dev)
-{
-	netdev_for_each_tx_queue(dev, netdev_init_one_queue, NULL);
-	spin_lock_init(&dev->tx_global_lock);
-}
-
 struct netdev_queue *dev_ingress_queue_create(struct net_device *dev)
 {
 	struct netdev_queue *queue = dev_ingress_queue(dev);
@@ -5484,7 +5503,6 @@ struct netdev_queue *dev_ingress_queue_create(struct net_device *dev)
 	if (!queue)
 		return NULL;
 	netdev_init_one_queue(dev, queue, NULL);
-	__netdev_init_queue_locks_one(dev, queue, NULL);
 	queue->qdisc = &noop_qdisc;
 	queue->qdisc_sleeping = &noop_qdisc;
 	rcu_assign_pointer(dev->ingress_queue, queue);
@@ -5506,7 +5524,6 @@ struct netdev_queue *dev_ingress_queue_create(struct net_device *dev)
 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;
@@ -5534,20 +5551,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;
 
 	dev->pcpu_refcnt = alloc_percpu(int);
 	if (!dev->pcpu_refcnt)
-		goto free_tx;
+		goto free_p;
 
 	if (dev_addr_init(dev))
 		goto free_pcpu;
@@ -5557,7 +5566,6 @@ 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;
 
@@ -5568,8 +5576,6 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
 
 	dev->gso_max_size = GSO_MAX_SIZE;
 
-	netdev_init_queues(dev);
-
 	INIT_LIST_HEAD(&dev->ethtool_ntuple_list.list);
 	dev->ethtool_ntuple_list.count = 0;
 	INIT_LIST_HEAD(&dev->napi_list);
@@ -5580,8 +5586,6 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
 	strcpy(dev->name, name);
 	return dev;
 
-free_tx:
-	kfree(tx);
 free_pcpu:
 	free_percpu(dev->pcpu_refcnt);
 free_p:
-- 
1.7.1


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

* Re: [PATCH 3/3] net: allocate tx queues in register_netdevice
  2010-10-18 18:02 [PATCH 3/3] net: allocate tx queues in register_netdevice Tom Herbert
@ 2010-10-18 21:41 ` Ben Hutchings
  2010-10-19  0:12   ` John Fastabend
  0 siblings, 1 reply; 5+ messages in thread
From: Ben Hutchings @ 2010-10-18 21:41 UTC (permalink / raw)
  To: Tom Herbert; +Cc: davem, netdev, eric.dumazet, John Fastabend

On Mon, 2010-10-18 at 11:02 -0700, Tom Herbert wrote:
> This patch introduces netif_alloc_netdev_queues which is called from
> register_device instead of alloc_netdev_mq.  This makes TX queue
> allocation symmetric with RX allocation similarly allows drivers to
> change dev->num_tx_queues after allocating netdev and before
> registering it.

Changing num_tx_queues is probably *not* desirable, same as for
num_rx_queues.

[...]
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -1553,18 +1553,24 @@ static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
>   * Routine to help set real_num_tx_queues. To avoid skbs mapped to queues
>   * greater then real_num_tx_queues stale skbs on the qdisc must be flushed.
>   */
> -void netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq)
> +int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq)
>  {
> -	unsigned int real_num = dev->real_num_tx_queues;
> +	if (txq < 1)
> +		return -EINVAL;
>  
> -	if (unlikely(txq > dev->num_tx_queues))
> -		;
> -	else if (txq > real_num)
> -		dev->real_num_tx_queues = txq;
> -	else if (txq < real_num) {
> -		dev->real_num_tx_queues = txq;
> -		qdisc_reset_all_tx_gt(dev, txq);
> -	}
> +	if (dev->reg_state == NETREG_REGISTERED) {
> +		ASSERT_RTNL();
> +
> +		if (txq > dev->num_tx_queues)
> +			return -EINVAL;
> +
> +		if (txq < dev->real_num_tx_queues)
> +			qdisc_reset_all_tx_gt(dev, txq);
> +	} else
> +		dev->num_tx_queues = txq;
[...]

The kernel-doc comment should be updated to reflect the locking
requirement and the possibility of failure when called after
registration.

Ben.

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


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

* Re: [PATCH 3/3] net: allocate tx queues in register_netdevice
  2010-10-18 21:41 ` Ben Hutchings
@ 2010-10-19  0:12   ` John Fastabend
  2010-10-19  0:17     ` Tom Herbert
  0 siblings, 1 reply; 5+ messages in thread
From: John Fastabend @ 2010-10-19  0:12 UTC (permalink / raw)
  To: Ben Hutchings
  Cc: Tom Herbert, davem@davemloft.net, netdev@vger.kernel.org,
	eric.dumazet@gmail.com

On 10/18/2010 2:41 PM, Ben Hutchings wrote:
> On Mon, 2010-10-18 at 11:02 -0700, Tom Herbert wrote:
>> This patch introduces netif_alloc_netdev_queues which is called from
>> register_device instead of alloc_netdev_mq.  This makes TX queue
>> allocation symmetric with RX allocation similarly allows drivers to
>> change dev->num_tx_queues after allocating netdev and before
>> registering it.
> 
> Changing num_tx_queues is probably *not* desirable, same as for
> num_rx_queues.
> 

Right, this will break ixgbe and other drivers that may call netif_set_real_num_{rx|tx}_queues() to increase the number of
queues. Returning an error code seems like a good idea though.

John.

> [...]
>> --- a/net/core/dev.c
>> +++ b/net/core/dev.c
>> @@ -1553,18 +1553,24 @@ static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
>>   * Routine to help set real_num_tx_queues. To avoid skbs mapped to queues
>>   * greater then real_num_tx_queues stale skbs on the qdisc must be flushed.
>>   */
>> -void netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq)
>> +int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq)
>>  {
>> -	unsigned int real_num = dev->real_num_tx_queues;
>> +	if (txq < 1)
>> +		return -EINVAL;
>>  
>> -	if (unlikely(txq > dev->num_tx_queues))
>> -		;
>> -	else if (txq > real_num)
>> -		dev->real_num_tx_queues = txq;
>> -	else if (txq < real_num) {
>> -		dev->real_num_tx_queues = txq;
>> -		qdisc_reset_all_tx_gt(dev, txq);
>> -	}
>> +	if (dev->reg_state == NETREG_REGISTERED) {
>> +		ASSERT_RTNL();
>> +
>> +		if (txq > dev->num_tx_queues)
>> +			return -EINVAL;
>> +
>> +		if (txq < dev->real_num_tx_queues)
>> +			qdisc_reset_all_tx_gt(dev, txq);
>> +	} else
>> +		dev->num_tx_queues = txq;
> [...]
> 
> The kernel-doc comment should be updated to reflect the locking
> requirement and the possibility of failure when called after
> registration.
> 
> Ben.
> 


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

* Re: [PATCH 3/3] net: allocate tx queues in register_netdevice
  2010-10-19  0:12   ` John Fastabend
@ 2010-10-19  0:17     ` Tom Herbert
  2010-10-19  1:19       ` John Fastabend
  0 siblings, 1 reply; 5+ messages in thread
From: Tom Herbert @ 2010-10-19  0:17 UTC (permalink / raw)
  To: John Fastabend
  Cc: Ben Hutchings, davem@davemloft.net, netdev@vger.kernel.org,
	eric.dumazet@gmail.com

On Mon, Oct 18, 2010 at 5:12 PM, John Fastabend
<john.r.fastabend@intel.com> wrote:
> On 10/18/2010 2:41 PM, Ben Hutchings wrote:
>> On Mon, 2010-10-18 at 11:02 -0700, Tom Herbert wrote:
>>> This patch introduces netif_alloc_netdev_queues which is called from
>>> register_device instead of alloc_netdev_mq.  This makes TX queue
>>> allocation symmetric with RX allocation similarly allows drivers to
>>> change dev->num_tx_queues after allocating netdev and before
>>> registering it.
>>
>> Changing num_tx_queues is probably *not* desirable, same as for
>> num_rx_queues.
>>

Okay, so both netif_set_real_num_rx_queues and
netif_set_real_num_tx_queues should return -EINVAL if queue count >
num_[tr]x_queues?

>
> Right, this will break ixgbe and other drivers that may call netif_set_real_num_{rx|tx}_queues() to increase the number of
> queues. Returning an error code seems like a good idea though.
>
> John.
>
>> [...]
>>> --- a/net/core/dev.c
>>> +++ b/net/core/dev.c
>>> @@ -1553,18 +1553,24 @@ static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
>>>   * Routine to help set real_num_tx_queues. To avoid skbs mapped to queues
>>>   * greater then real_num_tx_queues stale skbs on the qdisc must be flushed.
>>>   */
>>> -void netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq)
>>> +int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq)
>>>  {
>>> -    unsigned int real_num = dev->real_num_tx_queues;
>>> +    if (txq < 1)
>>> +            return -EINVAL;
>>>
>>> -    if (unlikely(txq > dev->num_tx_queues))
>>> -            ;
>>> -    else if (txq > real_num)
>>> -            dev->real_num_tx_queues = txq;
>>> -    else if (txq < real_num) {
>>> -            dev->real_num_tx_queues = txq;
>>> -            qdisc_reset_all_tx_gt(dev, txq);
>>> -    }
>>> +    if (dev->reg_state == NETREG_REGISTERED) {
>>> +            ASSERT_RTNL();
>>> +
>>> +            if (txq > dev->num_tx_queues)
>>> +                    return -EINVAL;
>>> +
>>> +            if (txq < dev->real_num_tx_queues)
>>> +                    qdisc_reset_all_tx_gt(dev, txq);
>>> +    } else
>>> +            dev->num_tx_queues = txq;
>> [...]
>>
>> The kernel-doc comment should be updated to reflect the locking
>> requirement and the possibility of failure when called after
>> registration.
>>
>> Ben.
>>
>
>

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

* Re: [PATCH 3/3] net: allocate tx queues in register_netdevice
  2010-10-19  0:17     ` Tom Herbert
@ 2010-10-19  1:19       ` John Fastabend
  0 siblings, 0 replies; 5+ messages in thread
From: John Fastabend @ 2010-10-19  1:19 UTC (permalink / raw)
  To: Tom Herbert
  Cc: Ben Hutchings, davem@davemloft.net, netdev@vger.kernel.org,
	eric.dumazet@gmail.com

On 10/18/2010 5:17 PM, Tom Herbert wrote:
> On Mon, Oct 18, 2010 at 5:12 PM, John Fastabend
> <john.r.fastabend@intel.com> wrote:
>> On 10/18/2010 2:41 PM, Ben Hutchings wrote:
>>> On Mon, 2010-10-18 at 11:02 -0700, Tom Herbert wrote:
>>>> This patch introduces netif_alloc_netdev_queues which is called from
>>>> register_device instead of alloc_netdev_mq.  This makes TX queue
>>>> allocation symmetric with RX allocation similarly allows drivers to
>>>> change dev->num_tx_queues after allocating netdev and before
>>>> registering it.
>>>
>>> Changing num_tx_queues is probably *not* desirable, same as for
>>> num_rx_queues.
>>>
> 
> Okay, so both netif_set_real_num_rx_queues and
> netif_set_real_num_tx_queues should return -EINVAL if queue count >
> num_[tr]x_queues?
> 

Yes and also if txq|rxq < 1 but it looks like this case is covered.

>>
>> Right, this will break ixgbe and other drivers that may call netif_set_real_num_{rx|tx}_queues() to increase the number of
>> queues. Returning an error code seems like a good idea though.
>>
>> John.
>>
>>> [...]
>>>> --- a/net/core/dev.c
>>>> +++ b/net/core/dev.c
>>>> @@ -1553,18 +1553,24 @@ static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
>>>>   * Routine to help set real_num_tx_queues. To avoid skbs mapped to queues
>>>>   * greater then real_num_tx_queues stale skbs on the qdisc must be flushed.
>>>>   */
>>>> -void netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq)
>>>> +int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq)
>>>>  {
>>>> -    unsigned int real_num = dev->real_num_tx_queues;
>>>> +    if (txq < 1)
>>>> +            return -EINVAL;
>>>>
>>>> -    if (unlikely(txq > dev->num_tx_queues))
>>>> -            ;
>>>> -    else if (txq > real_num)
>>>> -            dev->real_num_tx_queues = txq;
>>>> -    else if (txq < real_num) {
>>>> -            dev->real_num_tx_queues = txq;
>>>> -            qdisc_reset_all_tx_gt(dev, txq);
>>>> -    }
>>>> +    if (dev->reg_state == NETREG_REGISTERED) {
>>>> +            ASSERT_RTNL();
>>>> +
>>>> +            if (txq > dev->num_tx_queues)
>>>> +                    return -EINVAL;
>>>> +
>>>> +            if (txq < dev->real_num_tx_queues)
>>>> +                    qdisc_reset_all_tx_gt(dev, txq);
>>>> +    } else
>>>> +            dev->num_tx_queues = txq;
>>> [...]
>>>
>>> The kernel-doc comment should be updated to reflect the locking
>>> requirement and the possibility of failure when called after
>>> registration.
>>>
>>> Ben.
>>>
>>
>>
> --
> 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


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

end of thread, other threads:[~2010-10-19  1:20 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-10-18 18:02 [PATCH 3/3] net: allocate tx queues in register_netdevice Tom Herbert
2010-10-18 21:41 ` Ben Hutchings
2010-10-19  0:12   ` John Fastabend
2010-10-19  0:17     ` Tom Herbert
2010-10-19  1:19       ` John Fastabend

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).