|
@@ -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 {
|
|
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];
|
|
|
|
-
|
|
|
|
- /* 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 */
|
|
/* 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 {
|
|
|
|
|
|
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,
|
|
{
|
|
{
|
|
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);
|
|
|
|
- if (cl->pq_key == q->jiffies)
|
|
|
|
|
|
+ cl->pq_key = q->now + delay;
|
|
|
|
+ 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)
|
|
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,
|
|
/**
|
|
/**
|
|
* 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)
|
|
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)) {
|
|
|
|
- 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);
|
|
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)
|
|
}
|
|
}
|
|
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 @@ next:
|
|
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;
|
|
|
|
-
|
|
|
|
- q->jiffies = jiffies;
|
|
|
|
|
|
+ psched_time_t next_event;
|
|
|
|
|
|
/* 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)
|
|
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;
|
|
|
|
- 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
|
|
} 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)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- 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)
|
|
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- sch->flags &= ~TCQ_F_THROTTLED;
|
|
|
|
- del_timer(&q->timer);
|
|
|
|
|
|
+ qdisc_watchdog_cancel(&q->watchdog);
|
|
__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)
|
|
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)
|
|
{
|
|
{
|
|
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
|