Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2ccccf5f authored by WANG Cong's avatar WANG Cong Committed by David S. Miller
Browse files

net_sched: update hierarchical backlog too



When the bottom qdisc decides to, for example, drop some packet,
it calls qdisc_tree_decrease_qlen() to update the queue length
for all its ancestors, we need to update the backlog too to
keep the stats on root qdisc accurate.

Cc: Jamal Hadi Salim <jhs@mojatatu.com>
Acked-by: default avatarJamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: default avatarCong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 86a7996c
Loading
Loading
Loading
Loading
+4 −0
Original line number Original line Diff line number Diff line
@@ -162,12 +162,14 @@ struct codel_vars {
 * struct codel_stats - contains codel shared variables and stats
 * struct codel_stats - contains codel shared variables and stats
 * @maxpacket:	largest packet we've seen so far
 * @maxpacket:	largest packet we've seen so far
 * @drop_count:	temp count of dropped packets in dequeue()
 * @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
 * 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
 * ce_mark:	number of packets CE marked because sojourn time was above ce_threshold
 */
 */
struct codel_stats {
struct codel_stats {
	u32		maxpacket;
	u32		maxpacket;
	u32		drop_count;
	u32		drop_count;
	u32		drop_len;
	u32		ecn_mark;
	u32		ecn_mark;
	u32		ce_mark;
	u32		ce_mark;
};
};
@@ -308,6 +310,7 @@ static struct sk_buff *codel_dequeue(struct Qdisc *sch,
								  vars->rec_inv_sqrt);
								  vars->rec_inv_sqrt);
					goto end;
					goto end;
				}
				}
				stats->drop_len += qdisc_pkt_len(skb);
				qdisc_drop(skb, sch);
				qdisc_drop(skb, sch);
				stats->drop_count++;
				stats->drop_count++;
				skb = dequeue_func(vars, sch);
				skb = dequeue_func(vars, sch);
@@ -330,6 +333,7 @@ static struct sk_buff *codel_dequeue(struct Qdisc *sch,
		if (params->ecn && INET_ECN_set_ce(skb)) {
		if (params->ecn && INET_ECN_set_ce(skb)) {
			stats->ecn_mark++;
			stats->ecn_mark++;
		} else {
		} else {
			stats->drop_len += qdisc_pkt_len(skb);
			qdisc_drop(skb, sch);
			qdisc_drop(skb, sch);
			stats->drop_count++;
			stats->drop_count++;


+3 −2
Original line number Original line Diff line number Diff line
@@ -396,7 +396,8 @@ struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue,
			      struct Qdisc *qdisc);
			      struct Qdisc *qdisc);
void qdisc_reset(struct Qdisc *qdisc);
void qdisc_reset(struct Qdisc *qdisc);
void qdisc_destroy(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,
struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
			  const struct Qdisc_ops *ops);
			  const struct Qdisc_ops *ops);
struct Qdisc *qdisc_create_dflt(struct netdev_queue *dev_queue,
struct Qdisc *qdisc_create_dflt(struct netdev_queue *dev_queue,
@@ -716,7 +717,7 @@ static inline struct Qdisc *qdisc_replace(struct Qdisc *sch, struct Qdisc *new,
	old = *pold;
	old = *pold;
	*pold = new;
	*pold = new;
	if (old != NULL) {
	if (old != NULL) {
		qdisc_tree_decrease_qlen(old, old->q.qlen);
		qdisc_tree_reduce_backlog(old, old->q.qlen, old->qstats.backlog);
		qdisc_reset(old);
		qdisc_reset(old);
	}
	}
	sch_tree_unlock(sch);
	sch_tree_unlock(sch);
+5 −3
Original line number Original line Diff line number Diff line
@@ -744,14 +744,15 @@ static u32 qdisc_alloc_handle(struct net_device *dev)
	return 0;
	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;
	const struct Qdisc_class_ops *cops;
	unsigned long cl;
	unsigned long cl;
	u32 parentid;
	u32 parentid;
	int drops;
	int drops;


	if (n == 0)
	if (n == 0 && len == 0)
		return;
		return;
	drops = max_t(int, n, 0);
	drops = max_t(int, n, 0);
	rcu_read_lock();
	rcu_read_lock();
@@ -774,11 +775,12 @@ void qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n)
			cops->put(sch, cl);
			cops->put(sch, cl);
		}
		}
		sch->q.qlen -= n;
		sch->q.qlen -= n;
		sch->qstats.backlog -= len;
		__qdisc_qstats_drop(sch, drops);
		__qdisc_qstats_drop(sch, drops);
	}
	}
	rcu_read_unlock();
	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,
static void notify_and_destroy(struct net *net, struct sk_buff *skb,
			       struct nlmsghdr *n, u32 clid,
			       struct nlmsghdr *n, u32 clid,
+3 −2
Original line number Original line Diff line number Diff line
@@ -1909,7 +1909,7 @@ static int cbq_delete(struct Qdisc *sch, unsigned long arg)
{
{
	struct cbq_sched_data *q = qdisc_priv(sch);
	struct cbq_sched_data *q = qdisc_priv(sch);
	struct cbq_class *cl = (struct cbq_class *)arg;
	struct cbq_class *cl = (struct cbq_class *)arg;
	unsigned int qlen;
	unsigned int qlen, backlog;


	if (cl->filters || cl->children || cl == &q->link)
	if (cl->filters || cl->children || cl == &q->link)
		return -EBUSY;
		return -EBUSY;
@@ -1917,8 +1917,9 @@ static int cbq_delete(struct Qdisc *sch, unsigned long arg)
	sch_tree_lock(sch);
	sch_tree_lock(sch);


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


	if (cl->next_alive)
	if (cl->next_alive)
		cbq_deactivate_class(cl);
		cbq_deactivate_class(cl);
+4 −2
Original line number Original line Diff line number Diff line
@@ -128,8 +128,8 @@ static void choke_drop_by_idx(struct Qdisc *sch, unsigned int idx)
		choke_zap_tail_holes(q);
		choke_zap_tail_holes(q);


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


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


			while (q->head != q->tail) {
			while (q->head != q->tail) {
				struct sk_buff *skb = q->tab[q->head];
				struct sk_buff *skb = q->tab[q->head];
@@ -467,11 +468,12 @@ static int choke_change(struct Qdisc *sch, struct nlattr *opt)
					ntab[tail++] = skb;
					ntab[tail++] = skb;
					continue;
					continue;
				}
				}
				dropped += qdisc_pkt_len(skb);
				qdisc_qstats_backlog_dec(sch, skb);
				qdisc_qstats_backlog_dec(sch, skb);
				--sch->q.qlen;
				--sch->q.qlen;
				qdisc_drop(skb, sch);
				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->head = 0;
			q->tail = tail;
			q->tail = tail;
		}
		}
Loading