Skip to content
Permalink
Browse files
net/sched: cbs: fix calculation error of idleslope credits
in the function cbs_dequeue_soft, when q->credits< 0, (now- q->last)
should be accounted for sendslope, not idleslope.

so the solution is as follows: when q->credits is less than 0, directly
calculate delay time, activate hrtimer and when hrtimer fires, calculate
idleslope credits and update it to q->credits.

Signed-off-by: Xiaoyong Yan <yanxiaoyong5@gmail.com>
  • Loading branch information
yanxiaoyong-ch authored and intel-lab-lkp committed Sep 18, 2020
1 parent 10b82d5 commit 6e3656a6f5879070aaee0343f90e633de7d2d85a
Showing 1 changed file with 48 additions and 23 deletions.
@@ -76,14 +76,51 @@ struct cbs_sched_data {
s32 hicredit; /* in bytes */
s64 sendslope; /* in bytes/s */
s64 idleslope; /* in bytes/s */
struct qdisc_watchdog watchdog;
struct hrtimer timer;
struct Qdisc *sch;
u64 last_expires;
int (*enqueue)(struct sk_buff *skb, struct Qdisc *sch,
struct sk_buff **to_free);
struct sk_buff *(*dequeue)(struct Qdisc *sch);
struct Qdisc *qdisc;
struct list_head cbs_list;
};

/* timediff is in ns, slope is in bytes/s */
static s64 timediff_to_credits(s64 timediff, s64 slope)
{
return div64_s64(timediff * slope, NSEC_PER_SEC);
}

static void cbs_timer_schedule(struct cbs_sched_data *q, u64 expires)
{
if (test_bit(__QDISC_STATE_DEACTIVATED,
&qdisc_root_sleeping(q->sch)->state))
return;
if (q->last_expires == expires)
return;
q->last_expires = expires;
hrtimer_start(&q->timer,
ns_to_ktime(expires),
HRTIMER_MODE_ABS_PINNED);

}
static enum hrtimer_restart cbs_timer(struct hrtimer *timer)
{
struct cbs_sched_data *q = container_of(timer, struct cbs_sched_data, timer);
s64 now = ktime_get_ns();
s64 credits;

credits = timediff_to_credits(now- q->last, q->idleslope);
credits = q->credits+ credits;
q->credits = clamp_t(s64, credits, q->locredit, q->hicredit);
q->last = now;
rcu_read_lock();
__netif_schedule(qdisc_root(q->sch));
rcu_read_unlock();

return HRTIMER_NORESTART;
}
static int cbs_child_enqueue(struct sk_buff *skb, struct Qdisc *sch,
struct Qdisc *child,
struct sk_buff **to_free)
@@ -135,12 +172,6 @@ static int cbs_enqueue(struct sk_buff *skb, struct Qdisc *sch,
return q->enqueue(skb, sch, to_free);
}

/* timediff is in ns, slope is in bytes/s */
static s64 timediff_to_credits(s64 timediff, s64 slope)
{
return div64_s64(timediff * slope, NSEC_PER_SEC);
}

static s64 delay_from_credits(s64 credits, s64 slope)
{
if (unlikely(slope == 0))
@@ -183,25 +214,17 @@ static struct sk_buff *cbs_dequeue_soft(struct Qdisc *sch)

/* The previous packet is still being sent */
if (now < q->last) {
qdisc_watchdog_schedule_ns(&q->watchdog, q->last);
cbs_timer_schedule(q, q->last);
return NULL;
}
if (q->credits < 0) {
credits = timediff_to_credits(now - q->last, q->idleslope);

credits = q->credits + credits;
q->credits = min_t(s64, credits, q->hicredit);

if (q->credits < 0) {
s64 delay;

delay = delay_from_credits(q->credits, q->idleslope);
qdisc_watchdog_schedule_ns(&q->watchdog, now + delay);
s64 delay;

q->last = now;
delay = delay_from_credits(q->credits, q->idleslope);
cbs_timer_schedule(q, now+ delay);
q->last = now;

return NULL;
}
return NULL;
}
skb = cbs_child_dequeue(sch, qdisc);
if (!skb)
@@ -424,7 +447,9 @@ static int cbs_init(struct Qdisc *sch, struct nlattr *opt,
q->enqueue = cbs_enqueue_soft;
q->dequeue = cbs_dequeue_soft;

qdisc_watchdog_init(&q->watchdog, sch);
hrtimer_init(&q->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_PINNED);
q->timer.function = cbs_timer;
q->sch = sch;

return cbs_change(sch, opt, extack);
}
@@ -438,7 +463,7 @@ static void cbs_destroy(struct Qdisc *sch)
if (!q->qdisc)
return;

qdisc_watchdog_cancel(&q->watchdog);
hrtimer_cancel(&q->timer);
cbs_disable_offload(dev, q);

spin_lock(&cbs_list_lock);

0 comments on commit 6e3656a

Please sign in to comment.