Commit 084c9535 authored by David S. Miller's avatar David S. Miller

Merge branch 'qdisc-hashtable'

Jiri Kosina says:

====================
Convert qdisc linked list into a hashtable

This is a respin of the v6 of the original patch [1], split into two-patch
series as requested by davem; first patch fixes all symbol conflicts
that'd happen once netdevice.h starts to include hashtable.h, the second
one performs the actual switch to hashtable.

I've preserved Cong's Reviewed-by:, as code-wise this series is identical
to the original v6 of the patch.

[1] lkml.kernel.org/r/alpine.LNX.2.00.1608011220580.22028@cbobk.fhfr.pm
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents b89b815c 59cc1f61
...@@ -597,14 +597,14 @@ static u32 hash_get(u8 *addr) ...@@ -597,14 +597,14 @@ static u32 hash_get(u8 *addr)
} }
/** /**
* hash_add - Hash function to add mac addr from hash table * emac_hash_add - Hash function to add mac addr from hash table
* @priv: The DaVinci EMAC private adapter structure * @priv: The DaVinci EMAC private adapter structure
* @mac_addr: mac address to delete from hash table * @mac_addr: mac address to delete from hash table
* *
* Adds mac address to the internal hash table * Adds mac address to the internal hash table
* *
*/ */
static int hash_add(struct emac_priv *priv, u8 *mac_addr) static int emac_hash_add(struct emac_priv *priv, u8 *mac_addr)
{ {
struct device *emac_dev = &priv->ndev->dev; struct device *emac_dev = &priv->ndev->dev;
u32 rc = 0; u32 rc = 0;
...@@ -613,7 +613,7 @@ static int hash_add(struct emac_priv *priv, u8 *mac_addr) ...@@ -613,7 +613,7 @@ static int hash_add(struct emac_priv *priv, u8 *mac_addr)
if (hash_value >= EMAC_NUM_MULTICAST_BITS) { if (hash_value >= EMAC_NUM_MULTICAST_BITS) {
if (netif_msg_drv(priv)) { if (netif_msg_drv(priv)) {
dev_err(emac_dev, "DaVinci EMAC: hash_add(): Invalid "\ dev_err(emac_dev, "DaVinci EMAC: emac_hash_add(): Invalid "\
"Hash %08x, should not be greater than %08x", "Hash %08x, should not be greater than %08x",
hash_value, (EMAC_NUM_MULTICAST_BITS - 1)); hash_value, (EMAC_NUM_MULTICAST_BITS - 1));
} }
...@@ -639,14 +639,14 @@ static int hash_add(struct emac_priv *priv, u8 *mac_addr) ...@@ -639,14 +639,14 @@ static int hash_add(struct emac_priv *priv, u8 *mac_addr)
} }
/** /**
* hash_del - Hash function to delete mac addr from hash table * emac_hash_del - Hash function to delete mac addr from hash table
* @priv: The DaVinci EMAC private adapter structure * @priv: The DaVinci EMAC private adapter structure
* @mac_addr: mac address to delete from hash table * @mac_addr: mac address to delete from hash table
* *
* Removes mac address from the internal hash table * Removes mac address from the internal hash table
* *
*/ */
static int hash_del(struct emac_priv *priv, u8 *mac_addr) static int emac_hash_del(struct emac_priv *priv, u8 *mac_addr)
{ {
u32 hash_value; u32 hash_value;
u32 hash_bit; u32 hash_bit;
...@@ -696,10 +696,10 @@ static void emac_add_mcast(struct emac_priv *priv, u32 action, u8 *mac_addr) ...@@ -696,10 +696,10 @@ static void emac_add_mcast(struct emac_priv *priv, u32 action, u8 *mac_addr)
switch (action) { switch (action) {
case EMAC_MULTICAST_ADD: case EMAC_MULTICAST_ADD:
update = hash_add(priv, mac_addr); update = emac_hash_add(priv, mac_addr);
break; break;
case EMAC_MULTICAST_DEL: case EMAC_MULTICAST_DEL:
update = hash_del(priv, mac_addr); update = emac_hash_del(priv, mac_addr);
break; break;
case EMAC_ALL_MULTI_SET: case EMAC_ALL_MULTI_SET:
update = 1; update = 1;
......
...@@ -52,6 +52,7 @@ ...@@ -52,6 +52,7 @@
#include <uapi/linux/netdevice.h> #include <uapi/linux/netdevice.h>
#include <uapi/linux/if_bonding.h> #include <uapi/linux/if_bonding.h>
#include <uapi/linux/pkt_cls.h> #include <uapi/linux/pkt_cls.h>
#include <linux/hashtable.h>
struct netpoll_info; struct netpoll_info;
struct device; struct device;
...@@ -1800,6 +1801,9 @@ struct net_device { ...@@ -1800,6 +1801,9 @@ struct net_device {
unsigned int num_tx_queues; unsigned int num_tx_queues;
unsigned int real_num_tx_queues; unsigned int real_num_tx_queues;
struct Qdisc *qdisc; struct Qdisc *qdisc;
#ifdef CONFIG_NET_SCHED
DECLARE_HASHTABLE (qdisc_hash, 4);
#endif
unsigned long tx_queue_len; unsigned long tx_queue_len;
spinlock_t tx_global_lock; spinlock_t tx_global_lock;
int watchdog_timeo; int watchdog_timeo;
......
...@@ -90,8 +90,8 @@ int unregister_qdisc(struct Qdisc_ops *qops); ...@@ -90,8 +90,8 @@ int unregister_qdisc(struct Qdisc_ops *qops);
void qdisc_get_default(char *id, size_t len); void qdisc_get_default(char *id, size_t len);
int qdisc_set_default(const char *id); int qdisc_set_default(const char *id);
void qdisc_list_add(struct Qdisc *q); void qdisc_hash_add(struct Qdisc *q);
void qdisc_list_del(struct Qdisc *q); void qdisc_hash_del(struct Qdisc *q);
struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle); struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle);
struct Qdisc *qdisc_lookup_class(struct net_device *dev, u32 handle); struct Qdisc *qdisc_lookup_class(struct net_device *dev, u32 handle);
struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r, struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r,
......
...@@ -61,7 +61,7 @@ struct Qdisc { ...@@ -61,7 +61,7 @@ struct Qdisc {
u32 limit; u32 limit;
const struct Qdisc_ops *ops; const struct Qdisc_ops *ops;
struct qdisc_size_table __rcu *stab; struct qdisc_size_table __rcu *stab;
struct list_head list; struct hlist_node hash;
u32 handle; u32 handle;
u32 parent; u32 parent;
void *u32_node; void *u32_node;
......
...@@ -7629,6 +7629,9 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, ...@@ -7629,6 +7629,9 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
INIT_LIST_HEAD(&dev->all_adj_list.lower); INIT_LIST_HEAD(&dev->all_adj_list.lower);
INIT_LIST_HEAD(&dev->ptype_all); INIT_LIST_HEAD(&dev->ptype_all);
INIT_LIST_HEAD(&dev->ptype_specific); INIT_LIST_HEAD(&dev->ptype_specific);
#ifdef CONFIG_NET_SCHED
hash_init(dev->qdisc_hash);
#endif
dev->priv_flags = IFF_XMIT_DST_RELEASE | IFF_XMIT_DST_RELEASE_PERM; dev->priv_flags = IFF_XMIT_DST_RELEASE | IFF_XMIT_DST_RELEASE_PERM;
setup(dev); setup(dev);
......
...@@ -61,12 +61,12 @@ static bool log_ecn_error = true; ...@@ -61,12 +61,12 @@ static bool log_ecn_error = true;
module_param(log_ecn_error, bool, 0644); module_param(log_ecn_error, bool, 0644);
MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN"); MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
#define HASH_SIZE_SHIFT 5 #define IP6_GRE_HASH_SIZE_SHIFT 5
#define HASH_SIZE (1 << HASH_SIZE_SHIFT) #define IP6_GRE_HASH_SIZE (1 << IP6_GRE_HASH_SIZE_SHIFT)
static int ip6gre_net_id __read_mostly; static int ip6gre_net_id __read_mostly;
struct ip6gre_net { struct ip6gre_net {
struct ip6_tnl __rcu *tunnels[4][HASH_SIZE]; struct ip6_tnl __rcu *tunnels[4][IP6_GRE_HASH_SIZE];
struct net_device *fb_tunnel_dev; struct net_device *fb_tunnel_dev;
}; };
...@@ -96,12 +96,12 @@ static void ip6gre_tnl_link_config(struct ip6_tnl *t, int set_mtu); ...@@ -96,12 +96,12 @@ static void ip6gre_tnl_link_config(struct ip6_tnl *t, int set_mtu);
will match fallback tunnel. will match fallback tunnel.
*/ */
#define HASH_KEY(key) (((__force u32)key^((__force u32)key>>4))&(HASH_SIZE - 1)) #define HASH_KEY(key) (((__force u32)key^((__force u32)key>>4))&(IP6_GRE_HASH_SIZE - 1))
static u32 HASH_ADDR(const struct in6_addr *addr) static u32 HASH_ADDR(const struct in6_addr *addr)
{ {
u32 hash = ipv6_addr_hash(addr); u32 hash = ipv6_addr_hash(addr);
return hash_32(hash, HASH_SIZE_SHIFT); return hash_32(hash, IP6_GRE_HASH_SIZE_SHIFT);
} }
#define tunnels_r_l tunnels[3] #define tunnels_r_l tunnels[3]
...@@ -1089,7 +1089,7 @@ static void ip6gre_destroy_tunnels(struct net *net, struct list_head *head) ...@@ -1089,7 +1089,7 @@ static void ip6gre_destroy_tunnels(struct net *net, struct list_head *head)
for (prio = 0; prio < 4; prio++) { for (prio = 0; prio < 4; prio++) {
int h; int h;
for (h = 0; h < HASH_SIZE; h++) { for (h = 0; h < IP6_GRE_HASH_SIZE; h++) {
struct ip6_tnl *t; struct ip6_tnl *t;
t = rtnl_dereference(ign->tunnels[prio][h]); t = rtnl_dereference(ign->tunnels[prio][h]);
......
...@@ -64,8 +64,8 @@ MODULE_LICENSE("GPL"); ...@@ -64,8 +64,8 @@ MODULE_LICENSE("GPL");
MODULE_ALIAS_RTNL_LINK("ip6tnl"); MODULE_ALIAS_RTNL_LINK("ip6tnl");
MODULE_ALIAS_NETDEV("ip6tnl0"); MODULE_ALIAS_NETDEV("ip6tnl0");
#define HASH_SIZE_SHIFT 5 #define IP6_TUNNEL_HASH_SIZE_SHIFT 5
#define HASH_SIZE (1 << HASH_SIZE_SHIFT) #define IP6_TUNNEL_HASH_SIZE (1 << IP6_TUNNEL_HASH_SIZE_SHIFT)
static bool log_ecn_error = true; static bool log_ecn_error = true;
module_param(log_ecn_error, bool, 0644); module_param(log_ecn_error, bool, 0644);
...@@ -75,7 +75,7 @@ static u32 HASH(const struct in6_addr *addr1, const struct in6_addr *addr2) ...@@ -75,7 +75,7 @@ static u32 HASH(const struct in6_addr *addr1, const struct in6_addr *addr2)
{ {
u32 hash = ipv6_addr_hash(addr1) ^ ipv6_addr_hash(addr2); u32 hash = ipv6_addr_hash(addr1) ^ ipv6_addr_hash(addr2);
return hash_32(hash, HASH_SIZE_SHIFT); return hash_32(hash, IP6_TUNNEL_HASH_SIZE_SHIFT);
} }
static int ip6_tnl_dev_init(struct net_device *dev); static int ip6_tnl_dev_init(struct net_device *dev);
...@@ -87,7 +87,7 @@ struct ip6_tnl_net { ...@@ -87,7 +87,7 @@ struct ip6_tnl_net {
/* the IPv6 tunnel fallback device */ /* the IPv6 tunnel fallback device */
struct net_device *fb_tnl_dev; struct net_device *fb_tnl_dev;
/* lists for storing tunnels in use */ /* lists for storing tunnels in use */
struct ip6_tnl __rcu *tnls_r_l[HASH_SIZE]; struct ip6_tnl __rcu *tnls_r_l[IP6_TUNNEL_HASH_SIZE];
struct ip6_tnl __rcu *tnls_wc[1]; struct ip6_tnl __rcu *tnls_wc[1];
struct ip6_tnl __rcu **tnls[2]; struct ip6_tnl __rcu **tnls[2];
}; };
...@@ -2031,7 +2031,7 @@ static void __net_exit ip6_tnl_destroy_tunnels(struct net *net) ...@@ -2031,7 +2031,7 @@ static void __net_exit ip6_tnl_destroy_tunnels(struct net *net)
if (dev->rtnl_link_ops == &ip6_link_ops) if (dev->rtnl_link_ops == &ip6_link_ops)
unregister_netdevice_queue(dev, &list); unregister_netdevice_queue(dev, &list);
for (h = 0; h < HASH_SIZE; h++) { for (h = 0; h < IP6_TUNNEL_HASH_SIZE; h++) {
t = rtnl_dereference(ip6n->tnls_r_l[h]); t = rtnl_dereference(ip6n->tnls_r_l[h]);
while (t) { while (t) {
/* If dev is in the same netns, it has already /* If dev is in the same netns, it has already
......
...@@ -50,14 +50,14 @@ ...@@ -50,14 +50,14 @@
#include <net/net_namespace.h> #include <net/net_namespace.h>
#include <net/netns/generic.h> #include <net/netns/generic.h>
#define HASH_SIZE_SHIFT 5 #define IP6_VTI_HASH_SIZE_SHIFT 5
#define HASH_SIZE (1 << HASH_SIZE_SHIFT) #define IP6_VTI_HASH_SIZE (1 << IP6_VTI_HASH_SIZE_SHIFT)
static u32 HASH(const struct in6_addr *addr1, const struct in6_addr *addr2) static u32 HASH(const struct in6_addr *addr1, const struct in6_addr *addr2)
{ {
u32 hash = ipv6_addr_hash(addr1) ^ ipv6_addr_hash(addr2); u32 hash = ipv6_addr_hash(addr1) ^ ipv6_addr_hash(addr2);
return hash_32(hash, HASH_SIZE_SHIFT); return hash_32(hash, IP6_VTI_HASH_SIZE_SHIFT);
} }
static int vti6_dev_init(struct net_device *dev); static int vti6_dev_init(struct net_device *dev);
...@@ -69,7 +69,7 @@ struct vti6_net { ...@@ -69,7 +69,7 @@ struct vti6_net {
/* the vti6 tunnel fallback device */ /* the vti6 tunnel fallback device */
struct net_device *fb_tnl_dev; struct net_device *fb_tnl_dev;
/* lists for storing tunnels in use */ /* lists for storing tunnels in use */
struct ip6_tnl __rcu *tnls_r_l[HASH_SIZE]; struct ip6_tnl __rcu *tnls_r_l[IP6_VTI_HASH_SIZE];
struct ip6_tnl __rcu *tnls_wc[1]; struct ip6_tnl __rcu *tnls_wc[1];
struct ip6_tnl __rcu **tnls[2]; struct ip6_tnl __rcu **tnls[2];
}; };
...@@ -1040,7 +1040,7 @@ static void __net_exit vti6_destroy_tunnels(struct vti6_net *ip6n) ...@@ -1040,7 +1040,7 @@ static void __net_exit vti6_destroy_tunnels(struct vti6_net *ip6n)
struct ip6_tnl *t; struct ip6_tnl *t;
LIST_HEAD(list); LIST_HEAD(list);
for (h = 0; h < HASH_SIZE; h++) { for (h = 0; h < IP6_VTI_HASH_SIZE; h++) {
t = rtnl_dereference(ip6n->tnls_r_l[h]); t = rtnl_dereference(ip6n->tnls_r_l[h]);
while (t) { while (t) {
unregister_netdevice_queue(t->dev, &list); unregister_netdevice_queue(t->dev, &list);
......
...@@ -62,7 +62,7 @@ ...@@ -62,7 +62,7 @@
For comments look at net/ipv4/ip_gre.c --ANK For comments look at net/ipv4/ip_gre.c --ANK
*/ */
#define HASH_SIZE 16 #define IP6_SIT_HASH_SIZE 16
#define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) #define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF)
static bool log_ecn_error = true; static bool log_ecn_error = true;
...@@ -78,9 +78,9 @@ static struct rtnl_link_ops sit_link_ops __read_mostly; ...@@ -78,9 +78,9 @@ static struct rtnl_link_ops sit_link_ops __read_mostly;
static int sit_net_id __read_mostly; static int sit_net_id __read_mostly;
struct sit_net { struct sit_net {
struct ip_tunnel __rcu *tunnels_r_l[HASH_SIZE]; struct ip_tunnel __rcu *tunnels_r_l[IP6_SIT_HASH_SIZE];
struct ip_tunnel __rcu *tunnels_r[HASH_SIZE]; struct ip_tunnel __rcu *tunnels_r[IP6_SIT_HASH_SIZE];
struct ip_tunnel __rcu *tunnels_l[HASH_SIZE]; struct ip_tunnel __rcu *tunnels_l[IP6_SIT_HASH_SIZE];
struct ip_tunnel __rcu *tunnels_wc[1]; struct ip_tunnel __rcu *tunnels_wc[1];
struct ip_tunnel __rcu **tunnels[4]; struct ip_tunnel __rcu **tunnels[4];
...@@ -1783,7 +1783,7 @@ static void __net_exit sit_destroy_tunnels(struct net *net, ...@@ -1783,7 +1783,7 @@ static void __net_exit sit_destroy_tunnels(struct net *net,
for (prio = 1; prio < 4; prio++) { for (prio = 1; prio < 4; prio++) {
int h; int h;
for (h = 0; h < HASH_SIZE; h++) { for (h = 0; h < IP6_SIT_HASH_SIZE; h++) {
struct ip_tunnel *t; struct ip_tunnel *t;
t = rtnl_dereference(sitn->tunnels[prio][h]); t = rtnl_dereference(sitn->tunnels[prio][h]);
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <linux/hrtimer.h> #include <linux/hrtimer.h>
#include <linux/lockdep.h> #include <linux/lockdep.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/hashtable.h>
#include <net/net_namespace.h> #include <net/net_namespace.h>
#include <net/sock.h> #include <net/sock.h>
...@@ -263,33 +264,33 @@ static struct Qdisc *qdisc_match_from_root(struct Qdisc *root, u32 handle) ...@@ -263,33 +264,33 @@ static struct Qdisc *qdisc_match_from_root(struct Qdisc *root, u32 handle)
root->handle == handle) root->handle == handle)
return root; return root;
list_for_each_entry_rcu(q, &root->list, list) { hash_for_each_possible_rcu(qdisc_dev(root)->qdisc_hash, q, hash, handle) {
if (q->handle == handle) if (q->handle == handle)
return q; return q;
} }
return NULL; return NULL;
} }
void qdisc_list_add(struct Qdisc *q) void qdisc_hash_add(struct Qdisc *q)
{ {
if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) { if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) {
struct Qdisc *root = qdisc_dev(q)->qdisc; struct Qdisc *root = qdisc_dev(q)->qdisc;
WARN_ON_ONCE(root == &noop_qdisc); WARN_ON_ONCE(root == &noop_qdisc);
ASSERT_RTNL(); ASSERT_RTNL();
list_add_tail_rcu(&q->list, &root->list); hash_add_rcu(qdisc_dev(q)->qdisc_hash, &q->hash, q->handle);
} }
} }
EXPORT_SYMBOL(qdisc_list_add); EXPORT_SYMBOL(qdisc_hash_add);
void qdisc_list_del(struct Qdisc *q) void qdisc_hash_del(struct Qdisc *q)
{ {
if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) { if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) {
ASSERT_RTNL(); ASSERT_RTNL();
list_del_rcu(&q->list); hash_del_rcu(&q->hash);
} }
} }
EXPORT_SYMBOL(qdisc_list_del); EXPORT_SYMBOL(qdisc_hash_del);
struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle) struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle)
{ {
...@@ -998,7 +999,7 @@ qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue, ...@@ -998,7 +999,7 @@ qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue,
goto err_out4; goto err_out4;
} }
qdisc_list_add(sch); qdisc_hash_add(sch);
return sch; return sch;
} }
...@@ -1435,6 +1436,7 @@ static int tc_dump_qdisc_root(struct Qdisc *root, struct sk_buff *skb, ...@@ -1435,6 +1436,7 @@ static int tc_dump_qdisc_root(struct Qdisc *root, struct sk_buff *skb,
{ {
int ret = 0, q_idx = *q_idx_p; int ret = 0, q_idx = *q_idx_p;
struct Qdisc *q; struct Qdisc *q;
int b;
if (!root) if (!root)
return 0; return 0;
...@@ -1449,7 +1451,7 @@ static int tc_dump_qdisc_root(struct Qdisc *root, struct sk_buff *skb, ...@@ -1449,7 +1451,7 @@ static int tc_dump_qdisc_root(struct Qdisc *root, struct sk_buff *skb,
goto done; goto done;
q_idx++; q_idx++;
} }
list_for_each_entry(q, &root->list, list) { hash_for_each(qdisc_dev(root)->qdisc_hash, b, q, hash) {
if (q_idx < s_q_idx) { if (q_idx < s_q_idx) {
q_idx++; q_idx++;
continue; continue;
...@@ -1765,6 +1767,7 @@ static int tc_dump_tclass_root(struct Qdisc *root, struct sk_buff *skb, ...@@ -1765,6 +1767,7 @@ static int tc_dump_tclass_root(struct Qdisc *root, struct sk_buff *skb,
int *t_p, int s_t) int *t_p, int s_t)
{ {
struct Qdisc *q; struct Qdisc *q;
int b;
if (!root) if (!root)
return 0; return 0;
...@@ -1772,7 +1775,7 @@ static int tc_dump_tclass_root(struct Qdisc *root, struct sk_buff *skb, ...@@ -1772,7 +1775,7 @@ static int tc_dump_tclass_root(struct Qdisc *root, struct sk_buff *skb,
if (tc_dump_tclass_qdisc(root, skb, tcm, cb, t_p, s_t) < 0) if (tc_dump_tclass_qdisc(root, skb, tcm, cb, t_p, s_t) < 0)
return -1; return -1;
list_for_each_entry(q, &root->list, list) { hash_for_each(qdisc_dev(root)->qdisc_hash, b, q, hash) {
if (tc_dump_tclass_qdisc(q, skb, tcm, cb, t_p, s_t) < 0) if (tc_dump_tclass_qdisc(q, skb, tcm, cb, t_p, s_t) < 0)
return -1; return -1;
} }
......
...@@ -423,7 +423,6 @@ struct Qdisc noop_qdisc = { ...@@ -423,7 +423,6 @@ struct Qdisc noop_qdisc = {
.dequeue = noop_dequeue, .dequeue = noop_dequeue,
.flags = TCQ_F_BUILTIN, .flags = TCQ_F_BUILTIN,
.ops = &noop_qdisc_ops, .ops = &noop_qdisc_ops,
.list = LIST_HEAD_INIT(noop_qdisc.list),
.q.lock = __SPIN_LOCK_UNLOCKED(noop_qdisc.q.lock), .q.lock = __SPIN_LOCK_UNLOCKED(noop_qdisc.q.lock),
.dev_queue = &noop_netdev_queue, .dev_queue = &noop_netdev_queue,
.running = SEQCNT_ZERO(noop_qdisc.running), .running = SEQCNT_ZERO(noop_qdisc.running),
...@@ -613,7 +612,6 @@ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue, ...@@ -613,7 +612,6 @@ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
sch = (struct Qdisc *) QDISC_ALIGN((unsigned long) p); sch = (struct Qdisc *) QDISC_ALIGN((unsigned long) p);
sch->padded = (char *) sch - (char *) p; sch->padded = (char *) sch - (char *) p;
} }
INIT_LIST_HEAD(&sch->list);
skb_queue_head_init(&sch->q); skb_queue_head_init(&sch->q);
spin_lock_init(&sch->busylock); spin_lock_init(&sch->busylock);
...@@ -700,7 +698,7 @@ void qdisc_destroy(struct Qdisc *qdisc) ...@@ -700,7 +698,7 @@ void qdisc_destroy(struct Qdisc *qdisc)
return; return;
#ifdef CONFIG_NET_SCHED #ifdef CONFIG_NET_SCHED
qdisc_list_del(qdisc); qdisc_hash_del(qdisc);
qdisc_put_stab(rtnl_dereference(qdisc->stab)); qdisc_put_stab(rtnl_dereference(qdisc->stab));
#endif #endif
...@@ -788,6 +786,10 @@ static void attach_default_qdiscs(struct net_device *dev) ...@@ -788,6 +786,10 @@ static void attach_default_qdiscs(struct net_device *dev)
qdisc->ops->attach(qdisc); qdisc->ops->attach(qdisc);
} }
} }
#ifdef CONFIG_NET_SCHED
if (dev->qdisc)
qdisc_hash_add(dev->qdisc);
#endif
} }
static void transition_one_qdisc(struct net_device *dev, static void transition_one_qdisc(struct net_device *dev,
......
...@@ -88,7 +88,7 @@ static void mq_attach(struct Qdisc *sch) ...@@ -88,7 +88,7 @@ static void mq_attach(struct Qdisc *sch)
qdisc_destroy(old); qdisc_destroy(old);
#ifdef CONFIG_NET_SCHED #ifdef CONFIG_NET_SCHED
if (ntx < dev->real_num_tx_queues) if (ntx < dev->real_num_tx_queues)
qdisc_list_add(qdisc); qdisc_hash_add(qdisc);
#endif #endif
} }
......
...@@ -182,7 +182,7 @@ static void mqprio_attach(struct Qdisc *sch) ...@@ -182,7 +182,7 @@ static void mqprio_attach(struct Qdisc *sch)
if (old) if (old)
qdisc_destroy(old); qdisc_destroy(old);
if (ntx < dev->real_num_tx_queues) if (ntx < dev->real_num_tx_queues)
qdisc_list_add(qdisc); qdisc_hash_add(qdisc);
} }
kfree(priv->qdiscs); kfree(priv->qdiscs);
priv->qdiscs = NULL; priv->qdiscs = NULL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment