From 8798481b667fa7c9bbd5aa843bf1557ada699964 Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Fri, 28 Jul 2023 12:35:33 -0300 Subject: net/sched: wrap open coded Qdics class filter counter The 'filter_cnt' counter is used to control a Qdisc class lifetime. Each filter referecing this class by its id will eventually increment/decrement this counter in their respective 'add/update/delete' routines. As these operations are always serialized under rtnl lock, we don't need an atomic type like 'refcount_t'. It also means that we lose the overflow/underflow checks already present in refcount_t, which are valuable to hunt down bugs where the unsigned counter wraps around as it aids automated tools like syzkaller to scream in such situations. Wrap the open coded increment/decrement into helper functions and add overflow checks to the operations. Acked-by: Jamal Hadi Salim Signed-off-by: Pedro Tammela Reviewed-by: Simon Horman Signed-off-by: Paolo Abeni --- net/sched/sch_drr.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'net/sched/sch_drr.c') diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c index e35a4e90f4e6..1b22b3b741c9 100644 --- a/net/sched/sch_drr.c +++ b/net/sched/sch_drr.c @@ -17,7 +17,6 @@ struct drr_class { struct Qdisc_class_common common; - unsigned int filter_cnt; struct gnet_stats_basic_sync bstats; struct gnet_stats_queue qstats; @@ -150,7 +149,7 @@ static int drr_delete_class(struct Qdisc *sch, unsigned long arg, struct drr_sched *q = qdisc_priv(sch); struct drr_class *cl = (struct drr_class *)arg; - if (cl->filter_cnt > 0) + if (qdisc_class_in_use(&cl->common)) return -EBUSY; sch_tree_lock(sch); @@ -187,8 +186,8 @@ static unsigned long drr_bind_tcf(struct Qdisc *sch, unsigned long parent, { struct drr_class *cl = drr_find_class(sch, classid); - if (cl != NULL) - cl->filter_cnt++; + if (cl) + qdisc_class_get(&cl->common); return (unsigned long)cl; } @@ -197,7 +196,7 @@ static void drr_unbind_tcf(struct Qdisc *sch, unsigned long arg) { struct drr_class *cl = (struct drr_class *)arg; - cl->filter_cnt--; + qdisc_class_put(&cl->common); } static int drr_graft_class(struct Qdisc *sch, unsigned long arg, -- cgit v1.2.3-70-g09d2 From daf8d9181b9b4b58d3b182d1fea10dec75c5de88 Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Fri, 28 Jul 2023 12:35:34 -0300 Subject: net/sched: sch_drr: warn about class in use while deleting Add extack to warn that delete was rejected because the class is still in use Acked-by: Jamal Hadi Salim Signed-off-by: Pedro Tammela Reviewed-by: Simon Horman Signed-off-by: Paolo Abeni --- net/sched/sch_drr.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'net/sched/sch_drr.c') diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c index 1b22b3b741c9..19901e77cd3b 100644 --- a/net/sched/sch_drr.c +++ b/net/sched/sch_drr.c @@ -149,8 +149,10 @@ static int drr_delete_class(struct Qdisc *sch, unsigned long arg, struct drr_sched *q = qdisc_priv(sch); struct drr_class *cl = (struct drr_class *)arg; - if (qdisc_class_in_use(&cl->common)) + if (qdisc_class_in_use(&cl->common)) { + NL_SET_ERR_MSG(extack, "DRR class is in use"); return -EBUSY; + } sch_tree_lock(sch); -- cgit v1.2.3-70-g09d2