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

[NET_SCHED]: sch_cbq: use hrtimer for delay_timer

Switch delay_timer to hrtimer.

The class penalty parameter is changed to use psched ticks as units.
Since iproute never supported using this and the only existing user
(libnl) incorrectly assumes psched ticks as units anyway, this
shouldn't break anything.
Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e9054a33
...@@ -112,7 +112,7 @@ struct cbq_class ...@@ -112,7 +112,7 @@ struct cbq_class
/* Overlimit strategy parameters */ /* Overlimit strategy parameters */
void (*overlimit)(struct cbq_class *cl); void (*overlimit)(struct cbq_class *cl);
long penalty; psched_tdiff_t penalty;
/* General scheduler (WRR) parameters */ /* General scheduler (WRR) parameters */
long allot; long allot;
...@@ -143,7 +143,7 @@ struct cbq_class ...@@ -143,7 +143,7 @@ struct cbq_class
psched_time_t undertime; psched_time_t undertime;
long avgidle; long avgidle;
long deficit; /* Saved deficit for WRR */ long deficit; /* Saved deficit for WRR */
unsigned long penalized; psched_time_t penalized;
struct gnet_stats_basic bstats; struct gnet_stats_basic bstats;
struct gnet_stats_queue qstats; struct gnet_stats_queue qstats;
struct gnet_stats_rate_est rate_est; struct gnet_stats_rate_est rate_est;
...@@ -180,7 +180,7 @@ struct cbq_sched_data ...@@ -180,7 +180,7 @@ struct cbq_sched_data
psched_time_t now_rt; /* Cached real time */ psched_time_t now_rt; /* Cached real time */
unsigned pmask; unsigned pmask;
struct timer_list delay_timer; struct hrtimer delay_timer;
struct qdisc_watchdog watchdog; /* Watchdog timer, struct qdisc_watchdog watchdog; /* Watchdog timer,
started when CBQ has started when CBQ has
backlog, but cannot backlog, but cannot
...@@ -549,7 +549,8 @@ static void cbq_ovl_delay(struct cbq_class *cl) ...@@ -549,7 +549,8 @@ static void cbq_ovl_delay(struct cbq_class *cl)
psched_tdiff_t delay = PSCHED_TDIFF(cl->undertime, q->now); psched_tdiff_t delay = PSCHED_TDIFF(cl->undertime, q->now);
if (!cl->delayed) { if (!cl->delayed) {
unsigned long sched = jiffies; psched_time_t sched = q->now;
ktime_t expires;
delay += cl->offtime; delay += cl->offtime;
if (cl->avgidle < 0) if (cl->avgidle < 0)
...@@ -559,14 +560,18 @@ static void cbq_ovl_delay(struct cbq_class *cl) ...@@ -559,14 +560,18 @@ static void cbq_ovl_delay(struct cbq_class *cl)
PSCHED_TADD2(q->now, delay, cl->undertime); PSCHED_TADD2(q->now, delay, cl->undertime);
if (delay > 0) { if (delay > 0) {
sched += PSCHED_US2JIFFIE(delay) + cl->penalty; sched += delay + cl->penalty;
cl->penalized = sched; cl->penalized = sched;
cl->cpriority = TC_CBQ_MAXPRIO; cl->cpriority = TC_CBQ_MAXPRIO;
q->pmask |= (1<<TC_CBQ_MAXPRIO); q->pmask |= (1<<TC_CBQ_MAXPRIO);
if (del_timer(&q->delay_timer) &&
(long)(q->delay_timer.expires - sched) > 0) expires = ktime_set(0, 0);
q->delay_timer.expires = sched; expires = ktime_add_ns(expires, PSCHED_US2NS(sched));
add_timer(&q->delay_timer); if (hrtimer_try_to_cancel(&q->delay_timer) &&
ktime_to_ns(ktime_sub(q->delay_timer.expires,
expires)) > 0)
q->delay_timer.expires = expires;
hrtimer_restart(&q->delay_timer);
cl->delayed = 1; cl->delayed = 1;
cl->xstats.overactions++; cl->xstats.overactions++;
return; return;
...@@ -583,7 +588,7 @@ static void cbq_ovl_lowprio(struct cbq_class *cl) ...@@ -583,7 +588,7 @@ static void cbq_ovl_lowprio(struct cbq_class *cl)
{ {
struct cbq_sched_data *q = qdisc_priv(cl->qdisc); struct cbq_sched_data *q = qdisc_priv(cl->qdisc);
cl->penalized = jiffies + cl->penalty; cl->penalized = q->now + cl->penalty;
if (cl->cpriority != cl->priority2) { if (cl->cpriority != cl->priority2) {
cl->cpriority = cl->priority2; cl->cpriority = cl->priority2;
...@@ -604,19 +609,19 @@ static void cbq_ovl_drop(struct cbq_class *cl) ...@@ -604,19 +609,19 @@ static void cbq_ovl_drop(struct cbq_class *cl)
cbq_ovl_classic(cl); cbq_ovl_classic(cl);
} }
static unsigned long cbq_undelay_prio(struct cbq_sched_data *q, int prio) static psched_tdiff_t cbq_undelay_prio(struct cbq_sched_data *q, int prio,
psched_time_t now)
{ {
struct cbq_class *cl; struct cbq_class *cl;
struct cbq_class *cl_prev = q->active[prio]; struct cbq_class *cl_prev = q->active[prio];
unsigned long now = jiffies; psched_time_t sched = now;
unsigned long sched = now;
if (cl_prev == NULL) if (cl_prev == NULL)
return 0; return 0;
do { do {
cl = cl_prev->next_alive; cl = cl_prev->next_alive;
if ((long)(now - cl->penalized) > 0) { if (now - cl->penalized > 0) {
cl_prev->next_alive = cl->next_alive; cl_prev->next_alive = cl->next_alive;
cl->next_alive = NULL; cl->next_alive = NULL;
cl->cpriority = cl->priority; cl->cpriority = cl->priority;
...@@ -632,30 +637,34 @@ static unsigned long cbq_undelay_prio(struct cbq_sched_data *q, int prio) ...@@ -632,30 +637,34 @@ static unsigned long cbq_undelay_prio(struct cbq_sched_data *q, int prio)
} }
cl = cl_prev->next_alive; cl = cl_prev->next_alive;
} else if ((long)(sched - cl->penalized) > 0) } else if (sched - cl->penalized > 0)
sched = cl->penalized; sched = cl->penalized;
} while ((cl_prev = cl) != q->active[prio]); } while ((cl_prev = cl) != q->active[prio]);
return (long)(sched - now); return sched - now;
} }
static void cbq_undelay(unsigned long arg) static enum hrtimer_restart cbq_undelay(struct hrtimer *timer)
{ {
struct Qdisc *sch = (struct Qdisc*)arg; struct cbq_sched_data *q = container_of(timer, struct cbq_sched_data,
struct cbq_sched_data *q = qdisc_priv(sch); delay_timer);
long delay = 0; struct Qdisc *sch = q->watchdog.qdisc;
psched_time_t now;
psched_tdiff_t delay = 0;
unsigned pmask; unsigned pmask;
PSCHED_GET_TIME(now);
pmask = q->pmask; pmask = q->pmask;
q->pmask = 0; q->pmask = 0;
while (pmask) { while (pmask) {
int prio = ffz(~pmask); int prio = ffz(~pmask);
long tmp; psched_tdiff_t tmp;
pmask &= ~(1<<prio); pmask &= ~(1<<prio);
tmp = cbq_undelay_prio(q, prio); tmp = cbq_undelay_prio(q, prio, now);
if (tmp > 0) { if (tmp > 0) {
q->pmask |= 1<<prio; q->pmask |= 1<<prio;
if (tmp < delay || delay == 0) if (tmp < delay || delay == 0)
...@@ -664,12 +673,16 @@ static void cbq_undelay(unsigned long arg) ...@@ -664,12 +673,16 @@ static void cbq_undelay(unsigned long arg)
} }
if (delay) { if (delay) {
q->delay_timer.expires = jiffies + delay; ktime_t time;
add_timer(&q->delay_timer);
time = ktime_set(0, 0);
time = ktime_add_ns(time, PSCHED_US2NS(now + delay));
hrtimer_start(&q->delay_timer, time, HRTIMER_MODE_ABS);
} }
sch->flags &= ~TCQ_F_THROTTLED; sch->flags &= ~TCQ_F_THROTTLED;
netif_schedule(sch->dev); netif_schedule(sch->dev);
return HRTIMER_NORESTART;
} }
...@@ -1265,7 +1278,7 @@ cbq_reset(struct Qdisc* sch) ...@@ -1265,7 +1278,7 @@ cbq_reset(struct Qdisc* sch)
q->tx_class = NULL; q->tx_class = NULL;
q->tx_borrowed = NULL; q->tx_borrowed = NULL;
qdisc_watchdog_cancel(&q->watchdog); qdisc_watchdog_cancel(&q->watchdog);
del_timer(&q->delay_timer); hrtimer_cancel(&q->delay_timer);
q->toplevel = TC_CBQ_MAXLEVEL; q->toplevel = TC_CBQ_MAXLEVEL;
PSCHED_GET_TIME(q->now); PSCHED_GET_TIME(q->now);
q->now_rt = q->now; q->now_rt = q->now;
...@@ -1367,7 +1380,7 @@ static int cbq_set_overlimit(struct cbq_class *cl, struct tc_cbq_ovl *ovl) ...@@ -1367,7 +1380,7 @@ static int cbq_set_overlimit(struct cbq_class *cl, struct tc_cbq_ovl *ovl)
default: default:
return -EINVAL; return -EINVAL;
} }
cl->penalty = (ovl->penalty*HZ)/1000; cl->penalty = ovl->penalty;
return 0; return 0;
} }
...@@ -1435,8 +1448,7 @@ static int cbq_init(struct Qdisc *sch, struct rtattr *opt) ...@@ -1435,8 +1448,7 @@ static int cbq_init(struct Qdisc *sch, struct rtattr *opt)
q->link.stats_lock = &sch->dev->queue_lock; q->link.stats_lock = &sch->dev->queue_lock;
qdisc_watchdog_init(&q->watchdog, sch); qdisc_watchdog_init(&q->watchdog, sch);
init_timer(&q->delay_timer); hrtimer_init(&q->delay_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
q->delay_timer.data = (unsigned long)sch;
q->delay_timer.function = cbq_undelay; q->delay_timer.function = cbq_undelay;
q->toplevel = TC_CBQ_MAXLEVEL; q->toplevel = TC_CBQ_MAXLEVEL;
PSCHED_GET_TIME(q->now); PSCHED_GET_TIME(q->now);
...@@ -1514,7 +1526,7 @@ static __inline__ int cbq_dump_ovl(struct sk_buff *skb, struct cbq_class *cl) ...@@ -1514,7 +1526,7 @@ static __inline__ int cbq_dump_ovl(struct sk_buff *skb, struct cbq_class *cl)
opt.strategy = cl->ovl_strategy; opt.strategy = cl->ovl_strategy;
opt.priority2 = cl->priority2+1; opt.priority2 = cl->priority2+1;
opt.pad = 0; opt.pad = 0;
opt.penalty = (cl->penalty*1000)/HZ; opt.penalty = cl->penalty;
RTA_PUT(skb, TCA_CBQ_OVL_STRATEGY, sizeof(opt), &opt); RTA_PUT(skb, TCA_CBQ_OVL_STRATEGY, sizeof(opt), &opt);
return skb->len; return skb->len;
......
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