Skip to content

Commit

Permalink
Merge branch 'sch-accurate-backlog'
Browse files Browse the repository at this point in the history
Cong Wang says:

====================
net_sched: update backlog for hierarchical qdisc's

For hierarchical qdisc like HTB, we currently only update its qlen
but leave its backlog as zero:

    qdisc htb 1: dev eth0 root refcnt 2 r2q 10 default 1 direct_packets_stat 0 ver 3.17
     Sent 172680457356 bytes 222469449 pkt (dropped 0, overlimits 123575834 requeues 0)
     backlog 0b 72p requeues 0

This patchset makes backlog as accurate as qlen.

v3: rebase and fix the n==0 case for qdisc_tree_reduce_backlog()
v2: rebase and update changelog, not code change
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Feb 29, 2016
2 parents f12d33f + bdf1766 commit c0affa1
Show file tree
Hide file tree
Showing 22 changed files with 126 additions and 127 deletions.
4 changes: 4 additions & 0 deletions include/net/codel.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,12 +162,14 @@ struct codel_vars {
* struct codel_stats - contains codel shared variables and stats
* @maxpacket: largest packet we've seen so far
* @drop_count: temp count of dropped packets in dequeue()
* @drop_len: bytes of dropped packets in dequeue()
* ecn_mark: number of packets we ECN marked instead of dropping
* ce_mark: number of packets CE marked because sojourn time was above ce_threshold
*/
struct codel_stats {
u32 maxpacket;
u32 drop_count;
u32 drop_len;
u32 ecn_mark;
u32 ce_mark;
};
Expand Down Expand Up @@ -308,6 +310,7 @@ static struct sk_buff *codel_dequeue(struct Qdisc *sch,
vars->rec_inv_sqrt);
goto end;
}
stats->drop_len += qdisc_pkt_len(skb);
qdisc_drop(skb, sch);
stats->drop_count++;
skb = dequeue_func(vars, sch);
Expand All @@ -330,6 +333,7 @@ static struct sk_buff *codel_dequeue(struct Qdisc *sch,
if (params->ecn && INET_ECN_set_ce(skb)) {
stats->ecn_mark++;
} else {
stats->drop_len += qdisc_pkt_len(skb);
qdisc_drop(skb, sch);
stats->drop_count++;

Expand Down
20 changes: 19 additions & 1 deletion include/net/sch_generic.h
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,8 @@ struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue,
struct Qdisc *qdisc);
void qdisc_reset(struct Qdisc *qdisc);
void qdisc_destroy(struct Qdisc *qdisc);
void qdisc_tree_decrease_qlen(struct Qdisc *qdisc, unsigned int n);
void qdisc_tree_reduce_backlog(struct Qdisc *qdisc, unsigned int n,
unsigned int len);
struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
const struct Qdisc_ops *ops);
struct Qdisc *qdisc_create_dflt(struct netdev_queue *dev_queue,
Expand Down Expand Up @@ -707,6 +708,23 @@ static inline void qdisc_reset_queue(struct Qdisc *sch)
sch->qstats.backlog = 0;
}

static inline struct Qdisc *qdisc_replace(struct Qdisc *sch, struct Qdisc *new,
struct Qdisc **pold)
{
struct Qdisc *old;

sch_tree_lock(sch);
old = *pold;
*pold = new;
if (old != NULL) {
qdisc_tree_reduce_backlog(old, old->q.qlen, old->qstats.backlog);
qdisc_reset(old);
}
sch_tree_unlock(sch);

return old;
}

static inline unsigned int __qdisc_queue_drop(struct Qdisc *sch,
struct sk_buff_head *list)
{
Expand Down
8 changes: 5 additions & 3 deletions net/sched/sch_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -744,14 +744,15 @@ static u32 qdisc_alloc_handle(struct net_device *dev)
return 0;
}

void qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n)
void qdisc_tree_reduce_backlog(struct Qdisc *sch, unsigned int n,
unsigned int len)
{
const struct Qdisc_class_ops *cops;
unsigned long cl;
u32 parentid;
int drops;

if (n == 0)
if (n == 0 && len == 0)
return;
drops = max_t(int, n, 0);
rcu_read_lock();
Expand All @@ -774,11 +775,12 @@ void qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n)
cops->put(sch, cl);
}
sch->q.qlen -= n;
sch->qstats.backlog -= len;
__qdisc_qstats_drop(sch, drops);
}
rcu_read_unlock();
}
EXPORT_SYMBOL(qdisc_tree_decrease_qlen);
EXPORT_SYMBOL(qdisc_tree_reduce_backlog);

static void notify_and_destroy(struct net *net, struct sk_buff *skb,
struct nlmsghdr *n, u32 clid,
Expand Down
12 changes: 4 additions & 8 deletions net/sched/sch_cbq.c
Original file line number Diff line number Diff line change
Expand Up @@ -1624,13 +1624,8 @@ static int cbq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
new->reshape_fail = cbq_reshape_fail;
#endif
}
sch_tree_lock(sch);
*old = cl->q;
cl->q = new;
qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
qdisc_reset(*old);
sch_tree_unlock(sch);

*old = qdisc_replace(sch, new, &cl->q);
return 0;
}

Expand Down Expand Up @@ -1914,16 +1909,17 @@ static int cbq_delete(struct Qdisc *sch, unsigned long arg)
{
struct cbq_sched_data *q = qdisc_priv(sch);
struct cbq_class *cl = (struct cbq_class *)arg;
unsigned int qlen;
unsigned int qlen, backlog;

if (cl->filters || cl->children || cl == &q->link)
return -EBUSY;

sch_tree_lock(sch);

qlen = cl->q->q.qlen;
backlog = cl->q->qstats.backlog;
qdisc_reset(cl->q);
qdisc_tree_decrease_qlen(cl->q, qlen);
qdisc_tree_reduce_backlog(cl->q, qlen, backlog);

if (cl->next_alive)
cbq_deactivate_class(cl);
Expand Down
6 changes: 4 additions & 2 deletions net/sched/sch_choke.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,8 @@ static void choke_drop_by_idx(struct Qdisc *sch, unsigned int idx)
choke_zap_tail_holes(q);

qdisc_qstats_backlog_dec(sch, skb);
qdisc_tree_reduce_backlog(sch, 1, qdisc_pkt_len(skb));
qdisc_drop(skb, sch);
qdisc_tree_decrease_qlen(sch, 1);
--sch->q.qlen;
}

Expand Down Expand Up @@ -456,6 +456,7 @@ static int choke_change(struct Qdisc *sch, struct nlattr *opt)
old = q->tab;
if (old) {
unsigned int oqlen = sch->q.qlen, tail = 0;
unsigned dropped = 0;

while (q->head != q->tail) {
struct sk_buff *skb = q->tab[q->head];
Expand All @@ -467,11 +468,12 @@ static int choke_change(struct Qdisc *sch, struct nlattr *opt)
ntab[tail++] = skb;
continue;
}
dropped += qdisc_pkt_len(skb);
qdisc_qstats_backlog_dec(sch, skb);
--sch->q.qlen;
qdisc_drop(skb, sch);
}
qdisc_tree_decrease_qlen(sch, oqlen - sch->q.qlen);
qdisc_tree_reduce_backlog(sch, oqlen - sch->q.qlen, dropped);
q->head = 0;
q->tail = tail;
}
Expand Down
10 changes: 6 additions & 4 deletions net/sched/sch_codel.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,13 @@ static struct sk_buff *codel_qdisc_dequeue(struct Qdisc *sch)

skb = codel_dequeue(sch, &q->params, &q->vars, &q->stats, dequeue);

/* We cant call qdisc_tree_decrease_qlen() if our qlen is 0,
/* We cant call qdisc_tree_reduce_backlog() if our qlen is 0,
* or HTB crashes. Defer it for next round.
*/
if (q->stats.drop_count && sch->q.qlen) {
qdisc_tree_decrease_qlen(sch, q->stats.drop_count);
qdisc_tree_reduce_backlog(sch, q->stats.drop_count, q->stats.drop_len);
q->stats.drop_count = 0;
q->stats.drop_len = 0;
}
if (skb)
qdisc_bstats_update(sch, skb);
Expand Down Expand Up @@ -116,7 +117,7 @@ static int codel_change(struct Qdisc *sch, struct nlattr *opt)
{
struct codel_sched_data *q = qdisc_priv(sch);
struct nlattr *tb[TCA_CODEL_MAX + 1];
unsigned int qlen;
unsigned int qlen, dropped = 0;
int err;

if (!opt)
Expand Down Expand Up @@ -156,10 +157,11 @@ static int codel_change(struct Qdisc *sch, struct nlattr *opt)
while (sch->q.qlen > sch->limit) {
struct sk_buff *skb = __skb_dequeue(&sch->q);

dropped += qdisc_pkt_len(skb);
qdisc_qstats_backlog_dec(sch, skb);
qdisc_drop(skb, sch);
}
qdisc_tree_decrease_qlen(sch, qlen - sch->q.qlen);
qdisc_tree_reduce_backlog(sch, qlen - sch->q.qlen, dropped);

sch_tree_unlock(sch);
return 0;
Expand Down
9 changes: 3 additions & 6 deletions net/sched/sch_drr.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,10 @@ static struct drr_class *drr_find_class(struct Qdisc *sch, u32 classid)
static void drr_purge_queue(struct drr_class *cl)
{
unsigned int len = cl->qdisc->q.qlen;
unsigned int backlog = cl->qdisc->qstats.backlog;

qdisc_reset(cl->qdisc);
qdisc_tree_decrease_qlen(cl->qdisc, len);
qdisc_tree_reduce_backlog(cl->qdisc, len, backlog);
}

static const struct nla_policy drr_policy[TCA_DRR_MAX + 1] = {
Expand Down Expand Up @@ -226,11 +227,7 @@ static int drr_graft_class(struct Qdisc *sch, unsigned long arg,
new = &noop_qdisc;
}

sch_tree_lock(sch);
drr_purge_queue(cl);
*old = cl->qdisc;
cl->qdisc = new;
sch_tree_unlock(sch);
*old = qdisc_replace(sch, new, &cl->qdisc);
return 0;
}

Expand Down
11 changes: 4 additions & 7 deletions net/sched/sch_dsmark.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,7 @@ static int dsmark_graft(struct Qdisc *sch, unsigned long arg,
new = &noop_qdisc;
}

sch_tree_lock(sch);
*old = p->q;
p->q = new;
qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
qdisc_reset(*old);
sch_tree_unlock(sch);

*old = qdisc_replace(sch, new, &p->q);
return 0;
}

Expand Down Expand Up @@ -264,6 +258,7 @@ static int dsmark_enqueue(struct sk_buff *skb, struct Qdisc *sch)
return err;
}

qdisc_qstats_backlog_inc(sch, skb);
sch->q.qlen++;

return NET_XMIT_SUCCESS;
Expand All @@ -286,6 +281,7 @@ static struct sk_buff *dsmark_dequeue(struct Qdisc *sch)
return NULL;

qdisc_bstats_update(sch, skb);
qdisc_qstats_backlog_dec(sch, skb);
sch->q.qlen--;

index = skb->tc_index & (p->indices - 1);
Expand Down Expand Up @@ -401,6 +397,7 @@ static void dsmark_reset(struct Qdisc *sch)

pr_debug("%s(sch %p,[qdisc %p])\n", __func__, sch, p);
qdisc_reset(p->q);
sch->qstats.backlog = 0;
sch->q.qlen = 0;
}

Expand Down
4 changes: 3 additions & 1 deletion net/sched/sch_fq.c
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,7 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt)
struct fq_sched_data *q = qdisc_priv(sch);
struct nlattr *tb[TCA_FQ_MAX + 1];
int err, drop_count = 0;
unsigned drop_len = 0;
u32 fq_log;

if (!opt)
Expand Down Expand Up @@ -736,10 +737,11 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt)

if (!skb)
break;
drop_len += qdisc_pkt_len(skb);
kfree_skb(skb);
drop_count++;
}
qdisc_tree_decrease_qlen(sch, drop_count);
qdisc_tree_reduce_backlog(sch, drop_count, drop_len);

sch_tree_unlock(sch);
return err;
Expand Down
17 changes: 12 additions & 5 deletions net/sched/sch_fq_codel.c
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ static unsigned int fq_codel_qdisc_drop(struct Qdisc *sch)
static int fq_codel_enqueue(struct sk_buff *skb, struct Qdisc *sch)
{
struct fq_codel_sched_data *q = qdisc_priv(sch);
unsigned int idx;
unsigned int idx, prev_backlog;
struct fq_codel_flow *flow;
int uninitialized_var(ret);

Expand Down Expand Up @@ -203,6 +203,7 @@ static int fq_codel_enqueue(struct sk_buff *skb, struct Qdisc *sch)
if (++sch->q.qlen <= sch->limit)
return NET_XMIT_SUCCESS;

prev_backlog = sch->qstats.backlog;
q->drop_overlimit++;
/* Return Congestion Notification only if we dropped a packet
* from this flow.
Expand All @@ -211,7 +212,7 @@ static int fq_codel_enqueue(struct sk_buff *skb, struct Qdisc *sch)
return NET_XMIT_CN;

/* As we dropped a packet, better let upper stack know this */
qdisc_tree_decrease_qlen(sch, 1);
qdisc_tree_reduce_backlog(sch, 1, prev_backlog - sch->qstats.backlog);
return NET_XMIT_SUCCESS;
}

Expand Down Expand Up @@ -241,6 +242,7 @@ static struct sk_buff *fq_codel_dequeue(struct Qdisc *sch)
struct fq_codel_flow *flow;
struct list_head *head;
u32 prev_drop_count, prev_ecn_mark;
unsigned int prev_backlog;

begin:
head = &q->new_flows;
Expand All @@ -259,6 +261,7 @@ static struct sk_buff *fq_codel_dequeue(struct Qdisc *sch)

prev_drop_count = q->cstats.drop_count;
prev_ecn_mark = q->cstats.ecn_mark;
prev_backlog = sch->qstats.backlog;

skb = codel_dequeue(sch, &q->cparams, &flow->cvars, &q->cstats,
dequeue);
Expand All @@ -276,12 +279,14 @@ static struct sk_buff *fq_codel_dequeue(struct Qdisc *sch)
}
qdisc_bstats_update(sch, skb);
flow->deficit -= qdisc_pkt_len(skb);
/* We cant call qdisc_tree_decrease_qlen() if our qlen is 0,
/* We cant call qdisc_tree_reduce_backlog() if our qlen is 0,
* or HTB crashes. Defer it for next round.
*/
if (q->cstats.drop_count && sch->q.qlen) {
qdisc_tree_decrease_qlen(sch, q->cstats.drop_count);
qdisc_tree_reduce_backlog(sch, q->cstats.drop_count,
q->cstats.drop_len);
q->cstats.drop_count = 0;
q->cstats.drop_len = 0;
}
return skb;
}
Expand Down Expand Up @@ -372,11 +377,13 @@ static int fq_codel_change(struct Qdisc *sch, struct nlattr *opt)
while (sch->q.qlen > sch->limit) {
struct sk_buff *skb = fq_codel_dequeue(sch);

q->cstats.drop_len += qdisc_pkt_len(skb);
kfree_skb(skb);
q->cstats.drop_count++;
}
qdisc_tree_decrease_qlen(sch, q->cstats.drop_count);
qdisc_tree_reduce_backlog(sch, q->cstats.drop_count, q->cstats.drop_len);
q->cstats.drop_count = 0;
q->cstats.drop_len = 0;

sch_tree_unlock(sch);
return 0;
Expand Down
9 changes: 3 additions & 6 deletions net/sched/sch_hfsc.c
Original file line number Diff line number Diff line change
Expand Up @@ -895,9 +895,10 @@ static void
hfsc_purge_queue(struct Qdisc *sch, struct hfsc_class *cl)
{
unsigned int len = cl->qdisc->q.qlen;
unsigned int backlog = cl->qdisc->qstats.backlog;

qdisc_reset(cl->qdisc);
qdisc_tree_decrease_qlen(cl->qdisc, len);
qdisc_tree_reduce_backlog(cl->qdisc, len, backlog);
}

static void
Expand Down Expand Up @@ -1215,11 +1216,7 @@ hfsc_graft_class(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
new = &noop_qdisc;
}

sch_tree_lock(sch);
hfsc_purge_queue(sch, cl);
*old = cl->qdisc;
cl->qdisc = new;
sch_tree_unlock(sch);
*old = qdisc_replace(sch, new, &cl->qdisc);
return 0;
}

Expand Down
Loading

0 comments on commit c0affa1

Please sign in to comment.