Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ipv6: Preallocate rt->fib6_nh->rt6i_pcpu in ip6_route_info_create().

ip6_route_info_create_nh() will be called under RCU.

Then, fib6_nh_init() is also under RCU, but per-cpu memory allocation
is very likely to fail with GFP_ATOMIC while bulk-adding IPv6 routes
and we would see a bunch of this message in dmesg.

percpu: allocation failed, size=8 align=8 atomic=1, atomic alloc failed, no space left
percpu: allocation failed, size=8 align=8 atomic=1, atomic alloc failed, no space left

Let's preallocate rt->fib6_nh->rt6i_pcpu in ip6_route_info_create().

If something fails before the original memory allocation in
fib6_nh_init(), ip6_route_info_create_nh() calls fib6_info_release(),
which releases the preallocated per-cpu memory.

Note that rt->fib6_nh->rt6i_pcpu is not preallocated when called via
ipv6_stub, so we still need alloc_percpu_gfp() in fib6_nh_init().

Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Link: https://patch.msgid.link/20250418000443.43734-8-kuniyu@amazon.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

authored by

Kuniyuki Iwashima and committed by
Paolo Abeni
5720a328 c4837b98

+22 -3
+22 -3
net/ipv6/route.c
··· 3665 3665 goto out; 3666 3666 3667 3667 pcpu_alloc: 3668 - fib6_nh->rt6i_pcpu = alloc_percpu_gfp(struct rt6_info *, gfp_flags); 3669 3668 if (!fib6_nh->rt6i_pcpu) { 3670 - err = -ENOMEM; 3671 - goto out; 3669 + fib6_nh->rt6i_pcpu = alloc_percpu_gfp(struct rt6_info *, gfp_flags); 3670 + if (!fib6_nh->rt6i_pcpu) { 3671 + err = -ENOMEM; 3672 + goto out; 3673 + } 3672 3674 } 3673 3675 3674 3676 fib6_nh->fib_nh_dev = dev; ··· 3730 3728 } 3731 3729 } 3732 3730 3731 + static int fib6_nh_prealloc_percpu(struct fib6_nh *fib6_nh, gfp_t gfp_flags) 3732 + { 3733 + fib6_nh->rt6i_pcpu = alloc_percpu_gfp(struct rt6_info *, gfp_flags); 3734 + if (!fib6_nh->rt6i_pcpu) 3735 + return -ENOMEM; 3736 + 3737 + return 0; 3738 + } 3739 + 3733 3740 static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg, 3734 3741 gfp_t gfp_flags, 3735 3742 struct netlink_ext_ack *extack) ··· 3776 3765 goto free; 3777 3766 } 3778 3767 3768 + if (!cfg->fc_nh_id) { 3769 + err = fib6_nh_prealloc_percpu(&rt->fib6_nh[0], gfp_flags); 3770 + if (err) 3771 + goto free_metrics; 3772 + } 3773 + 3779 3774 if (cfg->fc_flags & RTF_ADDRCONF) 3780 3775 rt->dst_nocount = true; 3781 3776 ··· 3806 3789 rt->fib6_src.plen = cfg->fc_src_len; 3807 3790 #endif 3808 3791 return rt; 3792 + free_metrics: 3793 + ip_fib_metrics_put(rt->fib6_metrics); 3809 3794 free: 3810 3795 kfree(rt); 3811 3796 err: