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

[NET_SCHED]: sch_htb: use hrtimer based watchdog

Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 1a13cb63
...@@ -128,7 +128,7 @@ struct htb_class { ...@@ -128,7 +128,7 @@ struct htb_class {
} un; } un;
struct rb_node node[TC_HTB_NUMPRIO]; /* node for self or feed tree */ struct rb_node node[TC_HTB_NUMPRIO]; /* node for self or feed tree */
struct rb_node pq_node; /* node for event queue */ 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 */ int prio_activity; /* for which prios are we active */
enum htb_cmode cmode; /* current mode of the class */ enum htb_cmode cmode; /* current mode of the class */
...@@ -179,10 +179,7 @@ struct htb_sched { ...@@ -179,10 +179,7 @@ struct htb_sched {
struct rb_root wait_pq[TC_HTB_MAXDEPTH]; struct rb_root wait_pq[TC_HTB_MAXDEPTH];
/* time of nearest event per level (row) */ /* time of nearest event per level (row) */
unsigned long near_ev_cache[TC_HTB_MAXDEPTH]; psched_time_t near_ev_cache[TC_HTB_MAXDEPTH];
/* cached value of jiffies in dequeue */
unsigned long jiffies;
/* whether we hit non-work conserving class during this dequeue; we use */ /* whether we hit non-work conserving class during this dequeue; we use */
int nwc_hit; /* this to disable mindelay complaint in dequeue */ int nwc_hit; /* this to disable mindelay complaint in dequeue */
...@@ -195,7 +192,7 @@ struct htb_sched { ...@@ -195,7 +192,7 @@ struct htb_sched {
int rate2quantum; /* quant = rate / rate2quantum */ int rate2quantum; /* quant = rate / rate2quantum */
psched_time_t now; /* cached dequeue time */ psched_time_t now; /* cached dequeue time */
struct timer_list timer; /* send delay timer */ struct qdisc_watchdog watchdog;
#ifdef HTB_RATECM #ifdef HTB_RATECM
struct timer_list rttim; /* rate computer timer */ struct timer_list rttim; /* rate computer timer */
int recmp_bucket; /* which hash bucket to recompute next */ int recmp_bucket; /* which hash bucket to recompute next */
...@@ -342,19 +339,19 @@ static void htb_add_to_wait_tree(struct htb_sched *q, ...@@ -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; struct rb_node **p = &q->wait_pq[cl->level].rb_node, *parent = NULL;
cl->pq_key = q->jiffies + PSCHED_US2JIFFIE(delay); cl->pq_key = q->now + delay;
if (cl->pq_key == q->jiffies) if (cl->pq_key == q->now)
cl->pq_key++; cl->pq_key++;
/* update the nearest event cache */ /* 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; q->near_ev_cache[cl->level] = cl->pq_key;
while (*p) { while (*p) {
struct htb_class *c; struct htb_class *c;
parent = *p; parent = *p;
c = rb_entry(parent, struct htb_class, pq_node); 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; p = &parent->rb_right;
else else
p = &parent->rb_left; p = &parent->rb_left;
...@@ -679,14 +676,6 @@ static int htb_requeue(struct sk_buff *skb, struct Qdisc *sch) ...@@ -679,14 +676,6 @@ static int htb_requeue(struct sk_buff *skb, struct Qdisc *sch)
return NET_XMIT_SUCCESS; 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 #ifdef HTB_RATECM
#define RT_GEN(D,R) R+=D-(R/HTB_EWMAC);D=0 #define RT_GEN(D,R) R+=D-(R/HTB_EWMAC);D=0
static void htb_rate_timer(unsigned long arg) 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, ...@@ -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 * 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). * 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; int i;
...@@ -795,9 +784,9 @@ static long htb_do_events(struct htb_sched *q, int level) ...@@ -795,9 +784,9 @@ static long htb_do_events(struct htb_sched *q, int level)
return 0; return 0;
cl = rb_entry(p, struct htb_class, pq_node); cl = rb_entry(p, struct htb_class, pq_node);
if (time_after(cl->pq_key, q->jiffies)) { if (cl->pq_key > q->now)
return cl->pq_key - q->jiffies; return cl->pq_key;
}
htb_safe_rb_erase(p, q->wait_pq + level); htb_safe_rb_erase(p, q->wait_pq + level);
diff = PSCHED_TDIFF_SAFE(q->now, cl->t_c, (u32) cl->mbuffer); diff = PSCHED_TDIFF_SAFE(q->now, cl->t_c, (u32) cl->mbuffer);
htb_change_class_mode(q, cl, &diff); htb_change_class_mode(q, cl, &diff);
...@@ -806,7 +795,7 @@ static long htb_do_events(struct htb_sched *q, int level) ...@@ -806,7 +795,7 @@ static long htb_do_events(struct htb_sched *q, int level)
} }
if (net_ratelimit()) if (net_ratelimit())
printk(KERN_WARNING "htb: too many events !\n"); 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 /* Returns class->node+prio from id-tree where classe's id is >= id. NULL
...@@ -958,30 +947,12 @@ static struct sk_buff *htb_dequeue_tree(struct htb_sched *q, int prio, ...@@ -958,30 +947,12 @@ static struct sk_buff *htb_dequeue_tree(struct htb_sched *q, int prio,
return skb; 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) static struct sk_buff *htb_dequeue(struct Qdisc *sch)
{ {
struct sk_buff *skb = NULL; struct sk_buff *skb = NULL;
struct htb_sched *q = qdisc_priv(sch); struct htb_sched *q = qdisc_priv(sch);
int level; int level;
long min_delay; psched_time_t next_event;
q->jiffies = jiffies;
/* try to dequeue direct packets as high prio (!) to minimize cpu work */ /* try to dequeue direct packets as high prio (!) to minimize cpu work */
skb = __skb_dequeue(&q->direct_queue); skb = __skb_dequeue(&q->direct_queue);
...@@ -995,21 +966,23 @@ static struct sk_buff *htb_dequeue(struct Qdisc *sch) ...@@ -995,21 +966,23 @@ static struct sk_buff *htb_dequeue(struct Qdisc *sch)
goto fin; goto fin;
PSCHED_GET_TIME(q->now); PSCHED_GET_TIME(q->now);
min_delay = LONG_MAX; next_event = q->now + 5 * PSCHED_TICKS_PER_SEC;
q->nwc_hit = 0; q->nwc_hit = 0;
for (level = 0; level < TC_HTB_MAXDEPTH; level++) { for (level = 0; level < TC_HTB_MAXDEPTH; level++) {
/* common case optimization - skip event handler quickly */ /* common case optimization - skip event handler quickly */
int m; int m;
long delay; psched_time_t event;
if (time_after_eq(q->jiffies, q->near_ev_cache[level])) {
delay = htb_do_events(q, level); if (q->now >= q->near_ev_cache[level]) {
q->near_ev_cache[level] = event = htb_do_events(q, level);
q->jiffies + (delay ? delay : HZ); q->near_ev_cache[level] = event ? event :
PSCHED_TICKS_PER_SEC;
} else } 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]; m = ~q->row_mask[level];
while (m != (int)(-1)) { while (m != (int)(-1)) {
int prio = ffz(m); int prio = ffz(m);
...@@ -1022,7 +995,8 @@ static struct sk_buff *htb_dequeue(struct Qdisc *sch) ...@@ -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: fin:
return skb; return skb;
} }
...@@ -1075,8 +1049,7 @@ static void htb_reset(struct Qdisc *sch) ...@@ -1075,8 +1049,7 @@ static void htb_reset(struct Qdisc *sch)
} }
} }
sch->flags &= ~TCQ_F_THROTTLED; qdisc_watchdog_cancel(&q->watchdog);
del_timer(&q->timer);
__skb_queue_purge(&q->direct_queue); __skb_queue_purge(&q->direct_queue);
sch->q.qlen = 0; sch->q.qlen = 0;
memset(q->row, 0, sizeof(q->row)); memset(q->row, 0, sizeof(q->row));
...@@ -1113,14 +1086,12 @@ static int htb_init(struct Qdisc *sch, struct rtattr *opt) ...@@ -1113,14 +1086,12 @@ static int htb_init(struct Qdisc *sch, struct rtattr *opt)
for (i = 0; i < TC_HTB_NUMPRIO; i++) for (i = 0; i < TC_HTB_NUMPRIO; i++)
INIT_LIST_HEAD(q->drops + i); INIT_LIST_HEAD(q->drops + i);
init_timer(&q->timer); qdisc_watchdog_init(&q->watchdog, sch);
skb_queue_head_init(&q->direct_queue); skb_queue_head_init(&q->direct_queue);
q->direct_qlen = sch->dev->tx_queue_len; q->direct_qlen = sch->dev->tx_queue_len;
if (q->direct_qlen < 2) /* some devices have zero tx_queue_len */ if (q->direct_qlen < 2) /* some devices have zero tx_queue_len */
q->direct_qlen = 2; q->direct_qlen = 2;
q->timer.function = htb_timer;
q->timer.data = (unsigned long)sch;
#ifdef HTB_RATECM #ifdef HTB_RATECM
init_timer(&q->rttim); init_timer(&q->rttim);
...@@ -1341,7 +1312,7 @@ static void htb_destroy(struct Qdisc *sch) ...@@ -1341,7 +1312,7 @@ static void htb_destroy(struct Qdisc *sch)
{ {
struct htb_sched *q = qdisc_priv(sch); struct htb_sched *q = qdisc_priv(sch);
del_timer_sync(&q->timer); qdisc_watchdog_cancel(&q->watchdog);
#ifdef HTB_RATECM #ifdef HTB_RATECM
del_timer_sync(&q->rttim); del_timer_sync(&q->rttim);
#endif #endif
......
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