From 7060437bc1f81856b91248d7decd32e87dcd2550 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Dec 2012 15:40:21 -0800 Subject: [PATCH] compat: backport netif_set_real_num_tx_queues() This was added as of v2.6.35. We implement a slightly modified version given that this was later changed to return int through commit e6484930. The changes on e6484930 however were added due to some internal changes on core networking, we'll leave in place a simpler implementation for older kernels. Note that for older kernels than 2.6.27 we use the netdev egress_subqueue_count to set the TX queue count. Commit fd2ea0a7 added real_num_tx_queues to the netdevice when Multiqueue was added. mcgrof@frijol ~/linux-next (git::master)$ git describe --contains f0796d5c73e59786d09a1e617689d1d415f2db44 v2.6.35-rc5~14^2~14 mcgrof@frijol ~/linux-next (git::master)$ git describe --contains 3171d026 v2.6.37-rc1~147^2~339 mcgrof@frijol ~/linux-next (git::master)$ git describe --contains fd2ea0a7 v2.6.27-rc1~964^2~78 commit f0796d5c73e59786d09a1e617689d1d415f2db44 Author: John Fastabend Date: Thu Jul 1 13:21:57 2010 +0000 net: decreasing real_num_tx_queues needs to flush qdisc Reducing real_num_queues needs to flush the qdisc otherwise skbs with queue_mappings greater then real_num_tx_queues can be sent to the underlying driver. The flow for this is, dev_queue_xmit() dev_pick_tx() skb_tx_hash() => hash using real_num_tx_queues skb_set_queue_mapping() ... qdisc_enqueue_root() => enqueue skb on txq from hash ... dev->real_num_tx_queues -= n ... sch_direct_xmit() dev_hard_start_xmit() ndo_start_xmit(skb,dev) => skb queue set with old hash skbs are enqueued on the qdisc with skb->queue_mapping set 0 < queue_mappings < real_num_tx_queues. When the driver decreases real_num_tx_queues skb's may be dequeued from the qdisc with a queue_mapping greater then real_num_tx_queues. This fixes a case in ixgbe where this was occurring with DCB and FCoE. Because the driver is using queue_mapping to map skbs to tx descriptor rings we can potentially map skbs to rings that no longer exist. Signed-off-by: John Fastabend Tested-by: Ross Brattain Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller commit e6484930d7c73d324bccda7d43d131088da697b9 Author: Tom Herbert Date: Mon Oct 18 18:04:39 2010 +0000 net: allocate tx queues in register_netdevice 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. Also, queue locks allocation is done in netdev_init_one_queue. Change set_real_num_tx_queues to fail if requested number < 1 or greater than number of allocated queues. Signed-off-by: Tom Herbert Acked-by: Eric Dumazet Signed-off-by: David S. Miller commit fd2ea0a79faad824258af5dcec1927aa24d81c16 Author: David S. Miller Date: Thu Jul 17 01:56:23 2008 -0700 net: Use queue aware tests throughout. This effectively "flips the switch" by making the core networking and multiqueue-aware drivers use the new TX multiqueue structures. Non-multiqueue drivers need no changes. The interfaces they use such as netif_stop_queue() degenerate into an operation on TX queue zero. So everything "just works" for them. Code that really wants to do "X" to all TX queues now invokes a routine that does so, such as netif_tx_wake_all_queues(), netif_tx_stop_all_queues(), etc. pktgen and netpoll required a little bit more surgery than the others. In particular the pktgen changes, whilst functional, could be largely improved. The initial check in pktgen_xmit() will sometimes check the wrong queue, which is mostly harmless. The thing to do is probably to invoke fill_packet() earlier. The bulk of the netpoll changes is to make the code operate solely on the TX queue indicated by by the SKB queue mapping. Setting of the SKB queue mapping is entirely confined inside of net/core/dev.c:dev_pick_tx(). If we end up needing any kind of special semantics (drops, for example) it will be implemented here. Finally, we now have a "real_num_tx_queues" which is where the driver indicates how many TX queues are actually active. With IGB changes from Jeff Kirsher. Signed-off-by: David S. Miller mcgrof@drvbp1 ~/compat (git::master)$ time ckmake Trying kernel 3.6.5-030605-generic [OK] Trying kernel 3.5.7-030507-generic [OK] Trying kernel 3.4.17-030417-generic [OK] Trying kernel 3.3.8-030308-generic [OK] Trying kernel 3.2.33-030233-generic [OK] Trying kernel 3.1.10-030110-generic [OK] Trying kernel 3.0.50-030050-generic [OK] Trying kernel 2.6.39-02063904-generic [OK] Trying kernel 2.6.38-02063808-generic [OK] Trying kernel 2.6.37-02063706-generic [OK] Trying kernel 2.6.36-02063604-generic [OK] Trying kernel 2.6.35-02063513-generic [OK] Trying kernel 2.6.34-02063413-generic [OK] Trying kernel 2.6.33-02063320-generic [OK] Trying kernel 2.6.32-02063260-generic [OK] Trying kernel 2.6.31-02063113-generic [OK] Trying kernel 2.6.30-02063010-generic [OK] Trying kernel 2.6.29-02062906-generic [OK] Trying kernel 2.6.28-02062810-generic [OK] Trying kernel 2.6.27-020627-generic [OK] Trying kernel 2.6.26-020626-generic [OK] Trying kernel 2.6.25-020625-generic [OK] Trying kernel 2.6.24-020624-generic [OK] real 1m51.110s user 4m58.571s sys 1m39.282s Signed-off-by: Luis R. Rodriguez --- compat/compat-2.6.35.c | 28 ++++++++++++++++++++++++++++ include/linux/compat-2.6.35.h | 26 ++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/compat/compat-2.6.35.c b/compat/compat-2.6.35.c index 24551722274d..c2c54bb8734a 100644 --- a/compat/compat-2.6.35.c +++ b/compat/compat-2.6.35.c @@ -1,5 +1,6 @@ /* * Copyright 2010 Kshitij Kulshreshtha + * Copyright 2012 Luis R. Rodriguez * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -11,6 +12,33 @@ #include #include +/* + * 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. + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) +int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq) +{ + unsigned int real_num = dev->real_num_tx_queues; + + if (unlikely(txq > dev->num_tx_queues)) + return -EINVAL; + 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); + } +} +#else +int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq) +{ + dev->egress_subqueue_count = txq; + /* XXX: consider qdisc reset for older kernels */ +} +#endif +EXPORT_SYMBOL_GPL(netif_set_real_num_tx_queues); + /** * hex_to_bin - convert a hex digit to its real value * @ch: ascii character represents hex digit diff --git a/include/linux/compat-2.6.35.h b/include/linux/compat-2.6.35.h index d184f00ed536..22981a94fcfa 100644 --- a/include/linux/compat-2.6.35.h +++ b/include/linux/compat-2.6.35.h @@ -8,6 +8,8 @@ #include #include #include +#include +#include /* added on linux/kernel.h */ #define USHRT_MAX ((u16)(~0U)) @@ -19,6 +21,30 @@ #define netdev_hw_addr dev_mc_list +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) +/* Reset all TX qdiscs greater then index of a device. */ +static inline void qdisc_reset_all_tx_gt(struct net_device *dev, unsigned int i) +{ + struct Qdisc *qdisc; + + for (; i < dev->num_tx_queues; i++) { + qdisc = netdev_get_tx_queue(dev, i)->qdisc; + if (qdisc) { + spin_lock_bh(qdisc_lock(qdisc)); + qdisc_reset(qdisc); + spin_unlock_bh(qdisc_lock(qdisc)); + } + } +} +#else +static inline void qdisc_reset_all_tx_gt(struct net_device *dev, unsigned int i) +{ +} +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) */ + +extern int netif_set_real_num_tx_queues(struct net_device *dev, + unsigned int txq); + /* mask irq_set_affinity_hint as RHEL6 backports this */ #define irq_set_affinity_hint(a,b) compat_irq_set_affinity_hint(a,b) /* -- 2.30.2