summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorJakub Kicinski <kuba@kernel.org>2026-05-02 10:20:58 -0700
committerJakub Kicinski <kuba@kernel.org>2026-05-02 10:21:00 -0700
commit386829cd895b985b410f85253b1a7247a38148c2 (patch)
tree91478226e09593baa593edcfab27d527aac385cc /net
parent383d0fb8946921b4914ea0f360342e221d419d40 (diff)
parent3a3a30c14d7f04206916824a79878cfefac6c8e2 (diff)
downloadlinux-next-386829cd895b985b410f85253b1a7247a38148c2.tar.gz
linux-next-386829cd895b985b410f85253b1a7247a38148c2.zip
Merge branch 'replace-direct-dequeue-call-with-qdisc_dequeue_peeked'
Jamal Hadi Salim says: ==================== Replace direct dequeue call with qdisc_dequeue_peeked When sfb and red qdiscs have children (eg qfq qdisc) whose peek() callback is qdisc_peek_dequeued(), we could get a kernel panic. When the parent of such qdiscs (eg illustrated in patch #3 as tbf) wants to retrieve an skb from its child (red/sfb in this case), it will do the following: 1a. do a peek() - and when sensing there's an skb the child can offer, then - the child in this case(red/sfb) calls its child's (qfq) peek. qfq does the right thing and will return the gso_skb queue packet. Note: if there wasnt a gso_skb entry then qfq will store it there. 1b. invoke a dequeue() on the child (red/sfb). And herein lies the problem. - red/sfb will call the child's dequeue() which will essentially just try to grab something of qfq's queue. The right thing to do in #1b is to grab the skb off gso_skb queue. This patchset fixes that issue by changing #1b to use qdisc_dequeue_peeked() method instead. Patch 1 fixes the issue for red qdisc. Patch 2 fixes it for sfb. Patch 3 adds testcases for the two setups. ==================== Link: https://patch.msgid.link/20260430152957.194015-1-jhs@mojatatu.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'net')
-rw-r--r--net/sched/sch_red.c2
-rw-r--r--net/sched/sch_sfb.c2
2 files changed, 2 insertions, 2 deletions
diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c
index 432b8a3000a5..4d0e44a2e7c6 100644
--- a/net/sched/sch_red.c
+++ b/net/sched/sch_red.c
@@ -162,7 +162,7 @@ static struct sk_buff *red_dequeue(struct Qdisc *sch)
struct red_sched_data *q = qdisc_priv(sch);
struct Qdisc *child = q->qdisc;
- skb = child->dequeue(child);
+ skb = qdisc_dequeue_peeked(child);
if (skb) {
qdisc_bstats_update(sch, skb);
qdisc_qstats_backlog_dec(sch, skb);
diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c
index bd5ef561030f..d3ee8e5479b3 100644
--- a/net/sched/sch_sfb.c
+++ b/net/sched/sch_sfb.c
@@ -441,7 +441,7 @@ static struct sk_buff *sfb_dequeue(struct Qdisc *sch)
struct Qdisc *child = q->qdisc;
struct sk_buff *skb;
- skb = child->dequeue(q->qdisc);
+ skb = qdisc_dequeue_peeked(child);
if (skb) {
qdisc_bstats_update(sch, skb);