summaryrefslogtreecommitdiff
path: root/net/ipv4/nexthop.c
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-03-19 16:15:33 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-03-19 16:15:33 +0100
commit7e2dc8ed7862ac622b5a59953b679de97001dc83 (patch)
treed2d2cf61a22f5a6404000ee007c5e80bc2d9eca9 /net/ipv4/nexthop.c
parenta7e8c9cc3a13baf3dcf9734dd55609aa7ff9a1a0 (diff)
parent4a2b0ed2ac7abe9743e1559d212075a0ebac96b3 (diff)
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'net/ipv4/nexthop.c')
-rw-r--r--net/ipv4/nexthop.c14
1 files changed, 11 insertions, 3 deletions
diff --git a/net/ipv4/nexthop.c b/net/ipv4/nexthop.c
index 7b9d70f9b31c..427c20117594 100644
--- a/net/ipv4/nexthop.c
+++ b/net/ipv4/nexthop.c
@@ -2005,7 +2005,8 @@ static void nh_hthr_group_rebalance(struct nh_group *nhg)
}
static void remove_nh_grp_entry(struct net *net, struct nh_grp_entry *nhge,
- struct nl_info *nlinfo)
+ struct nl_info *nlinfo,
+ struct list_head *deferred_free)
{
struct nh_grp_entry *nhges, *new_nhges;
struct nexthop *nhp = nhge->nh_parent;
@@ -2065,8 +2066,8 @@ static void remove_nh_grp_entry(struct net *net, struct nh_grp_entry *nhge,
rcu_assign_pointer(nhp->nh_grp, newg);
list_del(&nhge->nh_list);
- free_percpu(nhge->stats);
nexthop_put(nhge->nh);
+ list_add(&nhge->nh_list, deferred_free);
/* Removal of a NH from a resilient group is notified through
* bucket notifications.
@@ -2086,6 +2087,7 @@ static void remove_nexthop_from_groups(struct net *net, struct nexthop *nh,
struct nl_info *nlinfo)
{
struct nh_grp_entry *nhge, *tmp;
+ LIST_HEAD(deferred_free);
/* If there is nothing to do, let's avoid the costly call to
* synchronize_net()
@@ -2094,10 +2096,16 @@ static void remove_nexthop_from_groups(struct net *net, struct nexthop *nh,
return;
list_for_each_entry_safe(nhge, tmp, &nh->grp_list, nh_list)
- remove_nh_grp_entry(net, nhge, nlinfo);
+ remove_nh_grp_entry(net, nhge, nlinfo, &deferred_free);
/* make sure all see the newly published array before releasing rtnl */
synchronize_net();
+
+ /* Now safe to free percpu stats — all RCU readers have finished */
+ list_for_each_entry_safe(nhge, tmp, &deferred_free, nh_list) {
+ list_del(&nhge->nh_list);
+ free_percpu(nhge->stats);
+ }
}
static void remove_nexthop_group(struct nexthop *nh, struct nl_info *nlinfo)