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

Commit e5f0e8f8 authored by Paolo Abeni's avatar Paolo Abeni Committed by David S. Miller
Browse files

net: sched: introduce and use qdisc tree flush/purge helpers



The same code to flush qdisc tree and purge the qdisc queue
is duplicated in many places and in most cases it does not
respect NOLOCK qdisc: the global backlog len is used and the
per CPU values are ignored.

This change addresses the above, factoring-out the relevant
code and using the helpers introduced by the previous patch
to fetch the correct backlog len.

Fixes: c5ad119f ("net: sched: pfifo_fast use skb_array")
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 5dd431b6
Loading
Loading
Loading
Loading
+19 −7
Original line number Diff line number Diff line
@@ -941,6 +941,23 @@ static inline void qdisc_qstats_qlen_backlog(struct Qdisc *sch, __u32 *qlen,
	*backlog = qstats.backlog;
}

static inline void qdisc_tree_flush_backlog(struct Qdisc *sch)
{
	__u32 qlen, backlog;

	qdisc_qstats_qlen_backlog(sch, &qlen, &backlog);
	qdisc_tree_reduce_backlog(sch, qlen, backlog);
}

static inline void qdisc_purge_queue(struct Qdisc *sch)
{
	__u32 qlen, backlog;

	qdisc_qstats_qlen_backlog(sch, &qlen, &backlog);
	qdisc_reset(sch);
	qdisc_tree_reduce_backlog(sch, qlen, backlog);
}

static inline void qdisc_skb_head_init(struct qdisc_skb_head *qh)
{
	qh->head = NULL;
@@ -1124,13 +1141,8 @@ static inline struct Qdisc *qdisc_replace(struct Qdisc *sch, struct Qdisc *new,
	sch_tree_lock(sch);
	old = *pold;
	*pold = new;
	if (old != NULL) {
		unsigned int qlen = old->q.qlen;
		unsigned int backlog = old->qstats.backlog;

		qdisc_reset(old);
		qdisc_tree_reduce_backlog(old, qlen, backlog);
	}
	if (old != NULL)
		qdisc_tree_flush_backlog(old);
	sch_tree_unlock(sch);

	return old;
+1 −5
Original line number Diff line number Diff line
@@ -1667,17 +1667,13 @@ 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, 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_reduce_backlog(cl->q, qlen, backlog);
	qdisc_purge_queue(cl->q);

	if (cl->next_alive)
		cbq_deactivate_class(cl);
+1 −10
Original line number Diff line number Diff line
@@ -50,15 +50,6 @@ static struct drr_class *drr_find_class(struct Qdisc *sch, u32 classid)
	return container_of(clc, struct drr_class, common);
}

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_reduce_backlog(cl->qdisc, len, backlog);
}

static const struct nla_policy drr_policy[TCA_DRR_MAX + 1] = {
	[TCA_DRR_QUANTUM]	= { .type = NLA_U32 },
};
@@ -167,7 +158,7 @@ static int drr_delete_class(struct Qdisc *sch, unsigned long arg)

	sch_tree_lock(sch);

	drr_purge_queue(cl);
	qdisc_purge_queue(cl->qdisc);
	qdisc_class_hash_remove(&q->clhash, &cl->common);

	sch_tree_unlock(sch);
+2 −12
Original line number Diff line number Diff line
@@ -844,16 +844,6 @@ qdisc_peek_len(struct Qdisc *sch)
	return len;
}

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_reduce_backlog(cl->qdisc, len, backlog);
}

static void
hfsc_adjust_levels(struct hfsc_class *cl)
{
@@ -1076,7 +1066,7 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
	qdisc_class_hash_insert(&q->clhash, &cl->cl_common);
	list_add_tail(&cl->siblings, &parent->children);
	if (parent->level == 0)
		hfsc_purge_queue(sch, parent);
		qdisc_purge_queue(parent->qdisc);
	hfsc_adjust_levels(parent);
	sch_tree_unlock(sch);

@@ -1112,7 +1102,7 @@ hfsc_delete_class(struct Qdisc *sch, unsigned long arg)
	list_del(&cl->siblings);
	hfsc_adjust_levels(cl->cl_parent);

	hfsc_purge_queue(sch, cl);
	qdisc_purge_queue(cl->qdisc);
	qdisc_class_hash_remove(&q->clhash, &cl->cl_common);

	sch_tree_unlock(sch);
+3 −12
Original line number Diff line number Diff line
@@ -1269,13 +1269,8 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg)

	sch_tree_lock(sch);

	if (!cl->level) {
		unsigned int qlen = cl->leaf.q->q.qlen;
		unsigned int backlog = cl->leaf.q->qstats.backlog;

		qdisc_reset(cl->leaf.q);
		qdisc_tree_reduce_backlog(cl->leaf.q, qlen, backlog);
	}
	if (!cl->level)
		qdisc_purge_queue(cl->leaf.q);

	/* delete from hash and active; remainder in destroy_class */
	qdisc_class_hash_remove(&q->clhash, &cl->common);
@@ -1403,12 +1398,8 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
					  classid, NULL);
		sch_tree_lock(sch);
		if (parent && !parent->level) {
			unsigned int qlen = parent->leaf.q->q.qlen;
			unsigned int backlog = parent->leaf.q->qstats.backlog;

			/* turn parent into inner node */
			qdisc_reset(parent->leaf.q);
			qdisc_tree_reduce_backlog(parent->leaf.q, qlen, backlog);
			qdisc_purge_queue(parent->leaf.q);
			qdisc_put(parent->leaf.q);
			if (parent->prio_activity)
				htb_deactivate(q, parent);
Loading