netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] hfsc: ensure class is added to eltree exactly once
@ 2016-05-31 10:12 Florian Westphal
  2016-05-31 14:55 ` Eric Dumazet
  0 siblings, 1 reply; 5+ messages in thread
From: Florian Westphal @ 2016-05-31 10:12 UTC (permalink / raw)
  To: netdev; +Cc: Florian Westphal, Miroslav Kratochvil

Intent is to insert the class into the eligible tree when first packet
is enqueued (its removed from list when class becomes empty again).

Checking for a size of 1 is problematic:

1. child qdisc might have segmented the skb, in which backlog can transition
from 0 to a value > 1.

In this case we can't dequeue anymore as this class is not in the tree.

2. some qdiscs like fq_codel can purge their backlogs when internal
limits are hit and update the parent qlen via qdisc_tree_reduce_backlog(),
so its possible that we end up with a length of 1 after enqueue for a class
that was already on the active list.

If this happens, we add the same class twice (which then results
in qdisc dequeue soft lockup).

Fix it by testing the length before we attempt to enqueue to child qdisc,
if enqueue operation is successful and old qlen was 0, then the
class was not yet inserted into eltree.

Cc: Miroslav Kratochvil <exa.exa@gmail.com>
Signed-off-by: Florian Westphal <fw@strlen.de>
---
 This was found while looking at Miroslav Kratochvil bug report
 but I don't think this fixes his case (I could trigger the 2nd case
 above w. fq_codel+really_stupid_config_knobs but I got softlockup
 which did not match his report).

diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
index d783d7c..0854be3 100644
--- a/net/sched/sch_hfsc.c
+++ b/net/sched/sch_hfsc.c
@@ -1583,6 +1583,7 @@ hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 {
 	struct hfsc_class *cl;
 	int uninitialized_var(err);
+	unsigned int qlen;
 
 	cl = hfsc_classify(skb, sch, &err);
 	if (cl == NULL) {
@@ -1592,6 +1593,7 @@ hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 		return err;
 	}
 
+	qlen = cl->qdisc->q.qlen;
 	err = qdisc_enqueue(skb, cl->qdisc);
 	if (unlikely(err != NET_XMIT_SUCCESS)) {
 		if (net_xmit_drop_count(err)) {
@@ -1601,7 +1603,7 @@ hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 		return err;
 	}
 
-	if (cl->qdisc->q.qlen == 1)
+	if (qlen == 0)
 		set_active(cl, qdisc_pkt_len(skb));
 
 	sch->q.qlen++;
-- 
2.7.3

^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2016-05-31 23:49 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-05-31 10:12 [PATCH] hfsc: ensure class is added to eltree exactly once Florian Westphal
2016-05-31 14:55 ` Eric Dumazet
2016-05-31 23:00   ` Florian Westphal
2016-05-31 23:33     ` Eric Dumazet
2016-05-31 23:49       ` Florian Westphal

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).