Commit 251f4c31 authored by Patrick McHardy's avatar Patrick McHardy Committed by David S. Miller

[PKT_SCHED]: Use double-linked list for dev->qdisc_list

Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@redhat.com>
parent a7682ad7
...@@ -362,8 +362,8 @@ struct net_device ...@@ -362,8 +362,8 @@ struct net_device
struct Qdisc *qdisc; struct Qdisc *qdisc;
struct Qdisc *qdisc_sleeping; struct Qdisc *qdisc_sleeping;
struct Qdisc *qdisc_list;
struct Qdisc *qdisc_ingress; struct Qdisc *qdisc_ingress;
struct list_head qdisc_list;
unsigned long tx_queue_len; /* Max frames per queue allowed */ unsigned long tx_queue_len; /* Max frames per queue allowed */
/* ingress path synchronizer */ /* ingress path synchronizer */
......
...@@ -78,11 +78,11 @@ struct Qdisc ...@@ -78,11 +78,11 @@ struct Qdisc
#define TCQ_F_THROTTLED 2 #define TCQ_F_THROTTLED 2
#define TCQ_F_INGRES 4 #define TCQ_F_INGRES 4
struct Qdisc_ops *ops; struct Qdisc_ops *ops;
struct Qdisc *next;
u32 handle; u32 handle;
atomic_t refcnt; atomic_t refcnt;
struct sk_buff_head q; struct sk_buff_head q;
struct net_device *dev; struct net_device *dev;
struct list_head list;
struct tc_stats stats; struct tc_stats stats;
spinlock_t *stats_lock; spinlock_t *stats_lock;
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/kmod.h> #include <linux/kmod.h>
#include <linux/list.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/pkt_sched.h> #include <net/pkt_sched.h>
...@@ -195,7 +196,7 @@ struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle) ...@@ -195,7 +196,7 @@ struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle)
{ {
struct Qdisc *q; struct Qdisc *q;
for (q = dev->qdisc_list; q; q = q->next) { list_for_each_entry(q, &dev->qdisc_list, list) {
if (q->handle == handle) if (q->handle == handle)
return q; return q;
} }
...@@ -421,6 +422,7 @@ qdisc_create(struct net_device *dev, u32 handle, struct rtattr **tca, int *errp) ...@@ -421,6 +422,7 @@ qdisc_create(struct net_device *dev, u32 handle, struct rtattr **tca, int *errp)
memset(sch, 0, size); memset(sch, 0, size);
INIT_LIST_HEAD(&sch->list);
skb_queue_head_init(&sch->q); skb_queue_head_init(&sch->q);
if (handle == TC_H_INGRESS) if (handle == TC_H_INGRESS)
...@@ -454,8 +456,7 @@ qdisc_create(struct net_device *dev, u32 handle, struct rtattr **tca, int *errp) ...@@ -454,8 +456,7 @@ qdisc_create(struct net_device *dev, u32 handle, struct rtattr **tca, int *errp)
smp_wmb(); smp_wmb();
if (!ops->init || (err = ops->init(sch, tca[TCA_OPTIONS-1])) == 0) { if (!ops->init || (err = ops->init(sch, tca[TCA_OPTIONS-1])) == 0) {
qdisc_lock_tree(dev); qdisc_lock_tree(dev);
sch->next = dev->qdisc_list; list_add_tail(&sch->list, &dev->qdisc_list);
dev->qdisc_list = sch;
qdisc_unlock_tree(dev); qdisc_unlock_tree(dev);
#ifdef CONFIG_NET_ESTIMATOR #ifdef CONFIG_NET_ESTIMATOR
...@@ -814,9 +815,9 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -814,9 +815,9 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb)
if (idx > s_idx) if (idx > s_idx)
s_q_idx = 0; s_q_idx = 0;
read_lock_bh(&qdisc_tree_lock); read_lock_bh(&qdisc_tree_lock);
for (q = dev->qdisc_list, q_idx = 0; q; q_idx = 0;
q = q->next, q_idx++) { list_for_each_entry(q, &dev->qdisc_list, list) {
if (q_idx < s_q_idx) if (q_idx++ < s_q_idx)
continue; continue;
if (tc_fill_qdisc(skb, q, 0, NETLINK_CB(cb->skb).pid, if (tc_fill_qdisc(skb, q, 0, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0) { cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0) {
...@@ -831,7 +832,7 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -831,7 +832,7 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb)
read_unlock(&dev_base_lock); read_unlock(&dev_base_lock);
cb->args[0] = idx; cb->args[0] = idx;
cb->args[1] = q_idx; cb->args[1] = q_idx - 1;
return skb->len; return skb->len;
} }
...@@ -1033,13 +1034,16 @@ static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -1033,13 +1034,16 @@ static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb)
return 0; return 0;
s_t = cb->args[0]; s_t = cb->args[0];
t = 0;
read_lock_bh(&qdisc_tree_lock); read_lock_bh(&qdisc_tree_lock);
for (q=dev->qdisc_list, t=0; q; q = q->next, t++) { list_for_each_entry(q, &dev->qdisc_list, list) {
if (t < s_t) continue; if (t < s_t || !q->ops->cl_ops ||
if (!q->ops->cl_ops) continue; (tcm->tcm_parent &&
if (tcm->tcm_parent && TC_H_MAJ(tcm->tcm_parent) != q->handle) TC_H_MAJ(tcm->tcm_parent) != q->handle)) {
t++;
continue; continue;
}
if (t > s_t) if (t > s_t)
memset(&cb->args[1], 0, sizeof(cb->args)-sizeof(cb->args[0])); memset(&cb->args[1], 0, sizeof(cb->args)-sizeof(cb->args[0]));
arg.w.fn = qdisc_class_dump; arg.w.fn = qdisc_class_dump;
...@@ -1052,6 +1056,7 @@ static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -1052,6 +1056,7 @@ static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb)
cb->args[1] = arg.w.count; cb->args[1] = arg.w.count;
if (arg.w.stop) if (arg.w.stop)
break; break;
t++;
} }
read_unlock_bh(&qdisc_tree_lock); read_unlock_bh(&qdisc_tree_lock);
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/rcupdate.h> #include <linux/rcupdate.h>
#include <linux/list.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/pkt_sched.h> #include <net/pkt_sched.h>
...@@ -394,6 +395,7 @@ struct Qdisc * qdisc_create_dflt(struct net_device *dev, struct Qdisc_ops *ops) ...@@ -394,6 +395,7 @@ struct Qdisc * qdisc_create_dflt(struct net_device *dev, struct Qdisc_ops *ops)
return NULL; return NULL;
memset(sch, 0, size); memset(sch, 0, size);
INIT_LIST_HEAD(&sch->list);
skb_queue_head_init(&sch->q); skb_queue_head_init(&sch->q);
sch->ops = ops; sch->ops = ops;
sch->enqueue = ops->enqueue; sch->enqueue = ops->enqueue;
...@@ -450,20 +452,9 @@ static void __qdisc_destroy(struct rcu_head *head) ...@@ -450,20 +452,9 @@ static void __qdisc_destroy(struct rcu_head *head)
void qdisc_destroy(struct Qdisc *qdisc) void qdisc_destroy(struct Qdisc *qdisc)
{ {
struct net_device *dev = qdisc->dev;
if (!atomic_dec_and_test(&qdisc->refcnt)) if (!atomic_dec_and_test(&qdisc->refcnt))
return; return;
list_del(&qdisc->list);
if (dev) {
struct Qdisc *q, **qp;
for (qp = &qdisc->dev->qdisc_list; (q=*qp) != NULL; qp = &q->next) {
if (q == qdisc) {
*qp = q->next;
break;
}
}
}
call_rcu(&qdisc->q_rcu, __qdisc_destroy); call_rcu(&qdisc->q_rcu, __qdisc_destroy);
} }
...@@ -483,12 +474,9 @@ void dev_activate(struct net_device *dev) ...@@ -483,12 +474,9 @@ void dev_activate(struct net_device *dev)
printk(KERN_INFO "%s: activation failed\n", dev->name); printk(KERN_INFO "%s: activation failed\n", dev->name);
return; return;
} }
write_lock_bh(&qdisc_tree_lock); write_lock_bh(&qdisc_tree_lock);
qdisc->next = dev->qdisc_list; list_add_tail(&qdisc->list, &dev->qdisc_list);
dev->qdisc_list = qdisc;
write_unlock_bh(&qdisc_tree_lock); write_unlock_bh(&qdisc_tree_lock);
} else { } else {
qdisc = &noqueue_qdisc; qdisc = &noqueue_qdisc;
} }
...@@ -530,7 +518,7 @@ void dev_init_scheduler(struct net_device *dev) ...@@ -530,7 +518,7 @@ void dev_init_scheduler(struct net_device *dev)
qdisc_lock_tree(dev); qdisc_lock_tree(dev);
dev->qdisc = &noop_qdisc; dev->qdisc = &noop_qdisc;
dev->qdisc_sleeping = &noop_qdisc; dev->qdisc_sleeping = &noop_qdisc;
dev->qdisc_list = NULL; INIT_LIST_HEAD(&dev->qdisc_list);
qdisc_unlock_tree(dev); qdisc_unlock_tree(dev);
dev_watchdog_init(dev); dev_watchdog_init(dev);
...@@ -551,9 +539,7 @@ void dev_shutdown(struct net_device *dev) ...@@ -551,9 +539,7 @@ void dev_shutdown(struct net_device *dev)
qdisc_destroy(qdisc); qdisc_destroy(qdisc);
} }
#endif #endif
BUG_TRAP(dev->qdisc_list == NULL);
BUG_TRAP(!timer_pending(&dev->watchdog_timer)); BUG_TRAP(!timer_pending(&dev->watchdog_timer));
dev->qdisc_list = NULL;
qdisc_unlock_tree(dev); qdisc_unlock_tree(dev);
} }
......
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