]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
sch_drr: make drr_qlen_notify() idempotent
authorCong Wang <xiyou.wangcong@gmail.com>
Thu, 3 Apr 2025 21:10:24 +0000 (14:10 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 9 May 2025 07:44:04 +0000 (09:44 +0200)
commit df008598b3a00be02a8051fde89ca0fbc416bd55 upstream.

drr_qlen_notify() always deletes the DRR class from its active list
with list_del(), therefore, it is not idempotent and not friendly
to its callers, like fq_codel_dequeue().

Let's make it idempotent to ease qdisc_tree_reduce_backlog() callers'
life. Also change other list_del()'s to list_del_init() just to be
extra safe.

Reported-by: Gerrard Tai <gerrard.tai@starlabs.sg>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20250403211033.166059-3-xiyou.wangcong@gmail.com
Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
net/sched/sch_drr.c

index edadb3a7bd1429101bf3cb6940a1f4b947c48943..9b36955e32b142b293eec32162ddb692407b9c0e 100644 (file)
@@ -110,6 +110,7 @@ static int drr_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
                return -ENOBUFS;
 
        gnet_stats_basic_sync_init(&cl->bstats);
+       INIT_LIST_HEAD(&cl->alist);
        cl->common.classid = classid;
        cl->quantum        = quantum;
        cl->qdisc          = qdisc_create_dflt(sch->dev_queue,
@@ -234,7 +235,7 @@ static void drr_qlen_notify(struct Qdisc *csh, unsigned long arg)
 {
        struct drr_class *cl = (struct drr_class *)arg;
 
-       list_del(&cl->alist);
+       list_del_init(&cl->alist);
 }
 
 static int drr_dump_class(struct Qdisc *sch, unsigned long arg,
@@ -393,7 +394,7 @@ static struct sk_buff *drr_dequeue(struct Qdisc *sch)
                        if (unlikely(skb == NULL))
                                goto out;
                        if (cl->qdisc->q.qlen == 0)
-                               list_del(&cl->alist);
+                               list_del_init(&cl->alist);
 
                        bstats_update(&cl->bstats, skb);
                        qdisc_bstats_update(sch, skb);
@@ -434,7 +435,7 @@ static void drr_reset_qdisc(struct Qdisc *sch)
        for (i = 0; i < q->clhash.hashsize; i++) {
                hlist_for_each_entry(cl, &q->clhash.hash[i], common.hnode) {
                        if (cl->qdisc->q.qlen)
-                               list_del(&cl->alist);
+                               list_del_init(&cl->alist);
                        qdisc_reset(cl->qdisc);
                }
        }