]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
net/sched: acp_api: no longer acquire RTNL in tc_action_net_exit()
authorEric Dumazet <edumazet@google.com>
Wed, 2 Jul 2025 07:12:30 +0000 (07:12 +0000)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 8 Jul 2025 11:00:24 +0000 (13:00 +0200)
tc_action_net_exit() got an rtnl exclusion in commit
a159d3c4b829 ("net_sched: acquire RTNL in tc_action_net_exit()")

Since then, commit 16af6067392c ("net: sched: implement reference
counted action release") made this RTNL exclusion obsolete for
most cases.

Only tcf_action_offload_del() might still require it.

Move the rtnl locking into tcf_idrinfo_destroy() when
an offload action is found.

Most netns do not have actions, yet deleting them is adding a lot
of pressure on RTNL, which is for many the most contended mutex
in the kernel.

We are moving to a per-netns 'rtnl', so tc_action_net_exit()
will not be able to grab 'rtnl' a single time for a batch of netns.

Before the patch:

perf probe -a rtnl_lock

perf record -e probe:rtnl_lock -a /bin/bash -c 'unshare -n "/bin/true"; sleep 1'
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.305 MB perf.data (25 samples) ]

After the patch:

perf record -e probe:rtnl_lock -a /bin/bash -c 'unshare -n "/bin/true"; sleep 1'
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.304 MB perf.data (9 samples) ]

Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Vlad Buslov <vladbu@nvidia.com>
Cc: Jiri Pirko <jiri@resnulli.us>
Cc: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Link: https://patch.msgid.link/20250702071230.1892674-1-edumazet@google.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
include/net/act_api.h
net/sched/act_api.c

index 404df8557f6a13420b18d9c52b9710fe86d084aa..04781c92b43d6ab9cc6c81a88d5c6fe8c282c590 100644 (file)
@@ -170,14 +170,12 @@ static inline void tc_action_net_exit(struct list_head *net_list,
 {
        struct net *net;
 
-       rtnl_lock();
        list_for_each_entry(net, net_list, exit_list) {
                struct tc_action_net *tn = net_generic(net, id);
 
                tcf_idrinfo_destroy(tn->ops, tn->idrinfo);
                kfree(tn->idrinfo);
        }
-       rtnl_unlock();
 }
 
 int tcf_generic_walker(struct tc_action_net *tn, struct sk_buff *skb,
index 057e20cef3754f33357c4c1e30034f6b9b872d91..9e468e46346710c85c3a85b905d27dfe3972916a 100644 (file)
@@ -933,18 +933,25 @@ void tcf_idrinfo_destroy(const struct tc_action_ops *ops,
                         struct tcf_idrinfo *idrinfo)
 {
        struct idr *idr = &idrinfo->action_idr;
+       bool mutex_taken = false;
        struct tc_action *p;
-       int ret;
        unsigned long id = 1;
        unsigned long tmp;
+       int ret;
 
        idr_for_each_entry_ul(idr, p, tmp, id) {
+               if (tc_act_in_hw(p) && !mutex_taken) {
+                       rtnl_lock();
+                       mutex_taken = true;
+               }
                ret = __tcf_idr_release(p, false, true);
                if (ret == ACT_P_DELETED)
                        module_put(ops->owner);
                else if (ret < 0)
                        return;
        }
+       if (mutex_taken)
+               rtnl_unlock();
        idr_destroy(&idrinfo->action_idr);
 }
 EXPORT_SYMBOL(tcf_idrinfo_destroy);