Commit 84a7d679 authored by Eric Dumazet's avatar Eric Dumazet Committed by Paolo Abeni
Browse files

net/sched: acp_api: no longer acquire RTNL in tc_action_net_exit()



tc_action_net_exit() got an rtnl exclusion in commit
a159d3c4 ("net_sched: acquire RTNL in tc_action_net_exit()")

Since then, commit 16af6067 ("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: default avatarEric 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: default avatarPaolo Abeni <pabeni@redhat.com>
parent d23647fd
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -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,
+8 −1
Original line number Diff line number Diff line
@@ -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);