From c38c83cb705a41e30a99545ae2314c00e3b9bf1c Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 27 Mar 2007 14:04:24 -0700 Subject: [NET_SCHED]: sch_htb/sch_hfsc: fix oops in qlen_notify During both HTB and HFSC class deletion the class is removed from the class hash before calling qdisc_tree_decrease_qlen. This makes the ->get operation in qdisc_tree_decrease_qlen fail, so it passes a NULL pointer to ->qlen_notify, causing an oops. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/sched/sch_htb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net/sched/sch_htb.c') diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 97cbb9aec946..3c3294d01041 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -1380,15 +1380,15 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg) sch_tree_lock(sch); - /* delete from hash and active; remainder in destroy_class */ - hlist_del_init(&cl->hlist); - if (!cl->level) { qlen = cl->un.leaf.q->q.qlen; qdisc_reset(cl->un.leaf.q); qdisc_tree_decrease_qlen(cl->un.leaf.q, qlen); } + /* delete from hash and active; remainder in destroy_class */ + hlist_del_init(&cl->hlist); + if (cl->prio_activity) htb_deactivate(q, cl); -- cgit v1.2.2 From fb983d4578e238b7f483b4f8f39f3a0f35d34d16 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 16 Mar 2007 01:22:39 -0700 Subject: [NET_SCHED]: sch_htb: use hrtimer based watchdog Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/sched/sch_htb.c | 91 ++++++++++++++++++----------------------------------- 1 file changed, 31 insertions(+), 60 deletions(-) (limited to 'net/sched/sch_htb.c') diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 3c3294d01041..4d84200f097b 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -128,7 +128,7 @@ struct htb_class { } un; struct rb_node node[TC_HTB_NUMPRIO]; /* node for self or feed tree */ struct rb_node pq_node; /* node for event queue */ - unsigned long pq_key; /* the same type as jiffies global */ + psched_time_t pq_key; int prio_activity; /* for which prios are we active */ enum htb_cmode cmode; /* current mode of the class */ @@ -179,10 +179,7 @@ struct htb_sched { struct rb_root wait_pq[TC_HTB_MAXDEPTH]; /* time of nearest event per level (row) */ - unsigned long near_ev_cache[TC_HTB_MAXDEPTH]; - - /* cached value of jiffies in dequeue */ - unsigned long jiffies; + psched_time_t near_ev_cache[TC_HTB_MAXDEPTH]; /* whether we hit non-work conserving class during this dequeue; we use */ int nwc_hit; /* this to disable mindelay complaint in dequeue */ @@ -195,7 +192,7 @@ struct htb_sched { int rate2quantum; /* quant = rate / rate2quantum */ psched_time_t now; /* cached dequeue time */ - struct timer_list timer; /* send delay timer */ + struct qdisc_watchdog watchdog; #ifdef HTB_RATECM struct timer_list rttim; /* rate computer timer */ int recmp_bucket; /* which hash bucket to recompute next */ @@ -342,19 +339,19 @@ static void htb_add_to_wait_tree(struct htb_sched *q, { struct rb_node **p = &q->wait_pq[cl->level].rb_node, *parent = NULL; - cl->pq_key = q->jiffies + PSCHED_US2JIFFIE(delay); - if (cl->pq_key == q->jiffies) + cl->pq_key = q->now + delay; + if (cl->pq_key == q->now) cl->pq_key++; /* update the nearest event cache */ - if (time_after(q->near_ev_cache[cl->level], cl->pq_key)) + if (q->near_ev_cache[cl->level] > cl->pq_key) q->near_ev_cache[cl->level] = cl->pq_key; while (*p) { struct htb_class *c; parent = *p; c = rb_entry(parent, struct htb_class, pq_node); - if (time_after_eq(cl->pq_key, c->pq_key)) + if (cl->pq_key >= c->pq_key) p = &parent->rb_right; else p = &parent->rb_left; @@ -679,14 +676,6 @@ static int htb_requeue(struct sk_buff *skb, struct Qdisc *sch) return NET_XMIT_SUCCESS; } -static void htb_timer(unsigned long arg) -{ - struct Qdisc *sch = (struct Qdisc *)arg; - sch->flags &= ~TCQ_F_THROTTLED; - wmb(); - netif_schedule(sch->dev); -} - #ifdef HTB_RATECM #define RT_GEN(D,R) R+=D-(R/HTB_EWMAC);D=0 static void htb_rate_timer(unsigned long arg) @@ -778,11 +767,11 @@ static void htb_charge_class(struct htb_sched *q, struct htb_class *cl, /** * htb_do_events - make mode changes to classes at the level * - * Scans event queue for pending events and applies them. Returns jiffies to + * Scans event queue for pending events and applies them. Returns time of * next pending event (0 for no event in pq). - * Note: Aplied are events whose have cl->pq_key <= jiffies. + * Note: Applied are events whose have cl->pq_key <= q->now. */ -static long htb_do_events(struct htb_sched *q, int level) +static psched_time_t htb_do_events(struct htb_sched *q, int level) { int i; @@ -795,9 +784,9 @@ static long htb_do_events(struct htb_sched *q, int level) return 0; cl = rb_entry(p, struct htb_class, pq_node); - if (time_after(cl->pq_key, q->jiffies)) { - return cl->pq_key - q->jiffies; - } + if (cl->pq_key > q->now) + return cl->pq_key; + htb_safe_rb_erase(p, q->wait_pq + level); diff = PSCHED_TDIFF_SAFE(q->now, cl->t_c, (u32) cl->mbuffer); htb_change_class_mode(q, cl, &diff); @@ -806,7 +795,7 @@ static long htb_do_events(struct htb_sched *q, int level) } if (net_ratelimit()) printk(KERN_WARNING "htb: too many events !\n"); - return HZ / 10; + return q->now + PSCHED_TICKS_PER_SEC / 10; } /* Returns class->node+prio from id-tree where classe's id is >= id. NULL @@ -958,30 +947,12 @@ next: return skb; } -static void htb_delay_by(struct Qdisc *sch, long delay) -{ - struct htb_sched *q = qdisc_priv(sch); - if (delay <= 0) - delay = 1; - if (unlikely(delay > 5 * HZ)) { - if (net_ratelimit()) - printk(KERN_INFO "HTB delay %ld > 5sec\n", delay); - delay = 5 * HZ; - } - /* why don't use jiffies here ? because expires can be in past */ - mod_timer(&q->timer, q->jiffies + delay); - sch->flags |= TCQ_F_THROTTLED; - sch->qstats.overlimits++; -} - static struct sk_buff *htb_dequeue(struct Qdisc *sch) { struct sk_buff *skb = NULL; struct htb_sched *q = qdisc_priv(sch); int level; - long min_delay; - - q->jiffies = jiffies; + psched_time_t next_event; /* try to dequeue direct packets as high prio (!) to minimize cpu work */ skb = __skb_dequeue(&q->direct_queue); @@ -995,21 +966,23 @@ static struct sk_buff *htb_dequeue(struct Qdisc *sch) goto fin; PSCHED_GET_TIME(q->now); - min_delay = LONG_MAX; + next_event = q->now + 5 * PSCHED_TICKS_PER_SEC; q->nwc_hit = 0; for (level = 0; level < TC_HTB_MAXDEPTH; level++) { /* common case optimization - skip event handler quickly */ int m; - long delay; - if (time_after_eq(q->jiffies, q->near_ev_cache[level])) { - delay = htb_do_events(q, level); - q->near_ev_cache[level] = - q->jiffies + (delay ? delay : HZ); + psched_time_t event; + + if (q->now >= q->near_ev_cache[level]) { + event = htb_do_events(q, level); + q->near_ev_cache[level] = event ? event : + PSCHED_TICKS_PER_SEC; } else - delay = q->near_ev_cache[level] - q->jiffies; + event = q->near_ev_cache[level]; + + if (event && next_event > event) + next_event = event; - if (delay && min_delay > delay) - min_delay = delay; m = ~q->row_mask[level]; while (m != (int)(-1)) { int prio = ffz(m); @@ -1022,7 +995,8 @@ static struct sk_buff *htb_dequeue(struct Qdisc *sch) } } } - htb_delay_by(sch, min_delay > 5 * HZ ? 5 * HZ : min_delay); + sch->qstats.overlimits++; + qdisc_watchdog_schedule(&q->watchdog, next_event); fin: return skb; } @@ -1075,8 +1049,7 @@ static void htb_reset(struct Qdisc *sch) } } - sch->flags &= ~TCQ_F_THROTTLED; - del_timer(&q->timer); + qdisc_watchdog_cancel(&q->watchdog); __skb_queue_purge(&q->direct_queue); sch->q.qlen = 0; memset(q->row, 0, sizeof(q->row)); @@ -1113,14 +1086,12 @@ static int htb_init(struct Qdisc *sch, struct rtattr *opt) for (i = 0; i < TC_HTB_NUMPRIO; i++) INIT_LIST_HEAD(q->drops + i); - init_timer(&q->timer); + qdisc_watchdog_init(&q->watchdog, sch); skb_queue_head_init(&q->direct_queue); q->direct_qlen = sch->dev->tx_queue_len; if (q->direct_qlen < 2) /* some devices have zero tx_queue_len */ q->direct_qlen = 2; - q->timer.function = htb_timer; - q->timer.data = (unsigned long)sch; #ifdef HTB_RATECM init_timer(&q->rttim); @@ -1341,7 +1312,7 @@ static void htb_destroy(struct Qdisc *sch) { struct htb_sched *q = qdisc_priv(sch); - del_timer_sync(&q->timer); + qdisc_watchdog_cancel(&q->watchdog); #ifdef HTB_RATECM del_timer_sync(&q->rttim); #endif -- cgit v1.2.2 From 00c04af9df3d26e5a8093da850e982a7b6aeada7 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 16 Mar 2007 01:23:02 -0700 Subject: [NET_SCHED]: kill jiffie conversion macros Now that all packet schedulers have been converted to hrtimers most users of PSCHED_JIFFIE2US and PSCHED_US2JIFFIE are gone. The remaining users use it to convert external time units to packet scheduler clock ticks, so use PSCHED_TICKS_PER_SEC instead. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/sched/sch_htb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/sched/sch_htb.c') diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 4d84200f097b..f76c20c0a109 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -1469,7 +1469,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, /* set class to be in HTB_CAN_SEND state */ cl->tokens = hopt->buffer; cl->ctokens = hopt->cbuffer; - cl->mbuffer = PSCHED_JIFFIE2US(HZ * 60); /* 1min */ + cl->mbuffer = 60 * PSCHED_TICKS_PER_SEC; /* 1min */ PSCHED_GET_TIME(cl->t_c); cl->cmode = HTB_CAN_SEND; -- cgit v1.2.2 From 27a884dc3cb63b93c2b3b643f5b31eed5f8a4d26 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 19 Apr 2007 20:29:13 -0700 Subject: [SK_BUFF]: Convert skb->tail to sk_buff_data_t So that it is also an offset from skb->head, reduces its size from 8 to 4 bytes on 64bit architectures, allowing us to combine the 4 bytes hole left by the layer headers conversion, reducing struct sk_buff size to 256 bytes, i.e. 4 64byte cachelines, and since the sk_buff slab cache is SLAB_HWCACHE_ALIGN... :-) Many calculations that previously required that skb->{transport,network, mac}_header be first converted to a pointer now can be done directly, being meaningful as offsets or pointers. Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/sched/sch_htb.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'net/sched/sch_htb.c') diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index f76c20c0a109..c687388a8cb6 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -1110,7 +1110,7 @@ static int htb_init(struct Qdisc *sch, struct rtattr *opt) static int htb_dump(struct Qdisc *sch, struct sk_buff *skb) { struct htb_sched *q = qdisc_priv(sch); - unsigned char *b = skb->tail; + unsigned char *b = skb_tail_pointer(skb); struct rtattr *rta; struct tc_htb_glob gopt; spin_lock_bh(&sch->dev->queue_lock); @@ -1123,12 +1123,12 @@ static int htb_dump(struct Qdisc *sch, struct sk_buff *skb) rta = (struct rtattr *)b; RTA_PUT(skb, TCA_OPTIONS, 0, NULL); RTA_PUT(skb, TCA_HTB_INIT, sizeof(gopt), &gopt); - rta->rta_len = skb->tail - b; + rta->rta_len = skb_tail_pointer(skb) - b; spin_unlock_bh(&sch->dev->queue_lock); return skb->len; rtattr_failure: spin_unlock_bh(&sch->dev->queue_lock); - skb_trim(skb, skb->tail - skb->data); + skb_trim(skb, skb_tail_pointer(skb) - skb->data); return -1; } @@ -1136,7 +1136,7 @@ static int htb_dump_class(struct Qdisc *sch, unsigned long arg, struct sk_buff *skb, struct tcmsg *tcm) { struct htb_class *cl = (struct htb_class *)arg; - unsigned char *b = skb->tail; + unsigned char *b = skb_tail_pointer(skb); struct rtattr *rta; struct tc_htb_opt opt; @@ -1159,7 +1159,7 @@ static int htb_dump_class(struct Qdisc *sch, unsigned long arg, opt.prio = cl->un.leaf.prio; opt.level = cl->level; RTA_PUT(skb, TCA_HTB_PARMS, sizeof(opt), &opt); - rta->rta_len = skb->tail - b; + rta->rta_len = skb_tail_pointer(skb) - b; spin_unlock_bh(&sch->dev->queue_lock); return skb->len; rtattr_failure: -- cgit v1.2.2 From dc5fc579b90ed0a9a4e55b0218cdbaf0a8cf2e67 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 25 Mar 2007 23:06:12 -0700 Subject: [NETLINK]: Use nlmsg_trim() where appropriate Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/sched/sch_htb.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'net/sched/sch_htb.c') diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index c687388a8cb6..b7abd0ae676a 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -1128,7 +1129,7 @@ static int htb_dump(struct Qdisc *sch, struct sk_buff *skb) return skb->len; rtattr_failure: spin_unlock_bh(&sch->dev->queue_lock); - skb_trim(skb, skb_tail_pointer(skb) - skb->data); + nlmsg_trim(skb, skb_tail_pointer(skb)); return -1; } @@ -1164,7 +1165,7 @@ static int htb_dump_class(struct Qdisc *sch, unsigned long arg, return skb->len; rtattr_failure: spin_unlock_bh(&sch->dev->queue_lock); - skb_trim(skb, b - skb->data); + nlmsg_trim(skb, b); return -1; } -- cgit v1.2.2 From 03cc45c0a5b9b7f74768feb43b9a2525d203bbdb Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 23 Mar 2007 11:29:11 -0700 Subject: [NET_SCHED]: turn PSCHED_TDIFF_SAFE into inline function Also rename to psched_tdiff_bounded. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/sched/sch_htb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net/sched/sch_htb.c') diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index b7abd0ae676a..71e4c92b7e87 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -729,7 +729,7 @@ static void htb_charge_class(struct htb_sched *q, struct htb_class *cl, cl->T = toks while (cl) { - diff = PSCHED_TDIFF_SAFE(q->now, cl->t_c, (u32) cl->mbuffer); + diff = psched_tdiff_bounded(q->now, cl->t_c, cl->mbuffer); if (cl->level >= level) { if (cl->level == level) cl->xstats.lends++; @@ -789,7 +789,7 @@ static psched_time_t htb_do_events(struct htb_sched *q, int level) return cl->pq_key; htb_safe_rb_erase(p, q->wait_pq + level); - diff = PSCHED_TDIFF_SAFE(q->now, cl->t_c, (u32) cl->mbuffer); + diff = psched_tdiff_bounded(q->now, cl->t_c, cl->mbuffer); htb_change_class_mode(q, cl, &diff); if (cl->cmode != HTB_CAN_SEND) htb_add_to_wait_tree(q, cl, diff); -- cgit v1.2.2 From 3bebcda28077375470dd60545b71bba2f83335fd Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 23 Mar 2007 11:29:25 -0700 Subject: [NET_SCHED]: turn PSCHED_GET_TIME into inline function Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/sched/sch_htb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net/sched/sch_htb.c') diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 71e4c92b7e87..3f528554b0d4 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -965,7 +965,7 @@ static struct sk_buff *htb_dequeue(struct Qdisc *sch) if (!sch->q.qlen) goto fin; - PSCHED_GET_TIME(q->now); + q->now = psched_get_time(); next_event = q->now + 5 * PSCHED_TICKS_PER_SEC; q->nwc_hit = 0; @@ -1274,7 +1274,7 @@ static void htb_parent_to_leaf(struct htb_class *cl, struct Qdisc *new_q) parent->un.leaf.prio = parent->prio; parent->tokens = parent->buffer; parent->ctokens = parent->cbuffer; - PSCHED_GET_TIME(parent->t_c); + parent->t_c = psched_get_time(); parent->cmode = HTB_CAN_SEND; } @@ -1471,7 +1471,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, cl->tokens = hopt->buffer; cl->ctokens = hopt->cbuffer; cl->mbuffer = 60 * PSCHED_TICKS_PER_SEC; /* 1min */ - PSCHED_GET_TIME(cl->t_c); + cl->t_c = psched_get_time(); cl->cmode = HTB_CAN_SEND; /* attach to the hash list and parent's family */ -- cgit v1.2.2 From a48b5a61448899040dfbd2e0cd55b06a2bd2466c Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 23 Mar 2007 11:29:43 -0700 Subject: [NET_SCHED]: Unline tcf_destroy Uninline tcf_destroy and add a helper function to destroy an entire filter chain. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/sched/sch_htb.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) (limited to 'net/sched/sch_htb.c') diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 3f528554b0d4..99bcec8dd04c 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -1236,16 +1236,6 @@ static unsigned long htb_get(struct Qdisc *sch, u32 classid) return (unsigned long)cl; } -static void htb_destroy_filters(struct tcf_proto **fl) -{ - struct tcf_proto *tp; - - while ((tp = *fl) != NULL) { - *fl = tp->next; - tcf_destroy(tp); - } -} - static inline int htb_parent_last_child(struct htb_class *cl) { if (!cl->parent) @@ -1289,7 +1279,7 @@ static void htb_destroy_class(struct Qdisc *sch, struct htb_class *cl) qdisc_put_rtab(cl->rate); qdisc_put_rtab(cl->ceil); - htb_destroy_filters(&cl->filter_list); + tcf_destroy_chain(cl->filter_list); while (!list_empty(&cl->children)) htb_destroy_class(sch, list_entry(cl->children.next, @@ -1321,7 +1311,7 @@ static void htb_destroy(struct Qdisc *sch) and surprisingly it worked in 2.4. But it must precede it because filter need its target class alive to be able to call unbind_filter on it (without Oops). */ - htb_destroy_filters(&q->filter_list); + tcf_destroy_chain(q->filter_list); while (!list_empty(&q->root)) htb_destroy_class(sch, list_entry(q->root.next, -- cgit v1.2.2