Commit 6676d5e4 authored by Vlad Buslov's avatar Vlad Buslov Committed by David S. Miller

net: sched: set dedicated tcf_walker flag when tp is empty

Using tcf_walker->stop flag to determine when tcf_walker->fn() was called
at least once is unreliable. Some classifiers set 'stop' flag on error
before calling walker callback, other classifiers used to call it with NULL
filter pointer when empty. In order to prevent further regressions, extend
tcf_walker structure with dedicated 'nonempty' flag. Set this flag in
tcf_walker->fn() implementation that is used to check if classifier has
filters configured.

Fixes: 8b64678e ("net: sched: refactor tp insert/delete for concurrent execution")
Signed-off-by: default avatarVlad Buslov <vladbu@mellanox.com>
Suggested-by: default avatarCong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e3af71a3
...@@ -17,6 +17,7 @@ struct tcf_walker { ...@@ -17,6 +17,7 @@ struct tcf_walker {
int stop; int stop;
int skip; int skip;
int count; int count;
bool nonempty;
unsigned long cookie; unsigned long cookie;
int (*fn)(struct tcf_proto *, void *node, struct tcf_walker *); int (*fn)(struct tcf_proto *, void *node, struct tcf_walker *);
}; };
......
...@@ -238,18 +238,23 @@ static void tcf_proto_put(struct tcf_proto *tp, bool rtnl_held, ...@@ -238,18 +238,23 @@ static void tcf_proto_put(struct tcf_proto *tp, bool rtnl_held,
tcf_proto_destroy(tp, rtnl_held, extack); tcf_proto_destroy(tp, rtnl_held, extack);
} }
static int walker_noop(struct tcf_proto *tp, void *d, struct tcf_walker *arg) static int walker_check_empty(struct tcf_proto *tp, void *d,
struct tcf_walker *arg)
{ {
return -1; if (tp) {
arg->nonempty = true;
return -1;
}
return 0;
} }
static bool tcf_proto_is_empty(struct tcf_proto *tp, bool rtnl_held) static bool tcf_proto_is_empty(struct tcf_proto *tp, bool rtnl_held)
{ {
struct tcf_walker walker = { .fn = walker_noop, }; struct tcf_walker walker = { .fn = walker_check_empty, };
if (tp->ops->walk) { if (tp->ops->walk) {
tp->ops->walk(tp, &walker, rtnl_held); tp->ops->walk(tp, &walker, rtnl_held);
return !walker.stop; return !walker.nonempty;
} }
return true; return true;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment