mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
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>
This commit is contained in:
parent
c4837b9853
commit
5720a328c3
1 changed files with 22 additions and 3 deletions
|
@ -3665,10 +3665,12 @@ int fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh,
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
pcpu_alloc:
|
pcpu_alloc:
|
||||||
fib6_nh->rt6i_pcpu = alloc_percpu_gfp(struct rt6_info *, gfp_flags);
|
|
||||||
if (!fib6_nh->rt6i_pcpu) {
|
if (!fib6_nh->rt6i_pcpu) {
|
||||||
err = -ENOMEM;
|
fib6_nh->rt6i_pcpu = alloc_percpu_gfp(struct rt6_info *, gfp_flags);
|
||||||
goto out;
|
if (!fib6_nh->rt6i_pcpu) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fib6_nh->fib_nh_dev = dev;
|
fib6_nh->fib_nh_dev = dev;
|
||||||
|
@ -3728,6 +3730,15 @@ void fib6_nh_release_dsts(struct fib6_nh *fib6_nh)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int fib6_nh_prealloc_percpu(struct fib6_nh *fib6_nh, gfp_t gfp_flags)
|
||||||
|
{
|
||||||
|
fib6_nh->rt6i_pcpu = alloc_percpu_gfp(struct rt6_info *, gfp_flags);
|
||||||
|
if (!fib6_nh->rt6i_pcpu)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg,
|
static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg,
|
||||||
gfp_t gfp_flags,
|
gfp_t gfp_flags,
|
||||||
struct netlink_ext_ack *extack)
|
struct netlink_ext_ack *extack)
|
||||||
|
@ -3765,6 +3776,12 @@ static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg,
|
||||||
goto free;
|
goto free;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!cfg->fc_nh_id) {
|
||||||
|
err = fib6_nh_prealloc_percpu(&rt->fib6_nh[0], gfp_flags);
|
||||||
|
if (err)
|
||||||
|
goto free_metrics;
|
||||||
|
}
|
||||||
|
|
||||||
if (cfg->fc_flags & RTF_ADDRCONF)
|
if (cfg->fc_flags & RTF_ADDRCONF)
|
||||||
rt->dst_nocount = true;
|
rt->dst_nocount = true;
|
||||||
|
|
||||||
|
@ -3789,6 +3806,8 @@ static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg,
|
||||||
rt->fib6_src.plen = cfg->fc_src_len;
|
rt->fib6_src.plen = cfg->fc_src_len;
|
||||||
#endif
|
#endif
|
||||||
return rt;
|
return rt;
|
||||||
|
free_metrics:
|
||||||
|
ip_fib_metrics_put(rt->fib6_metrics);
|
||||||
free:
|
free:
|
||||||
kfree(rt);
|
kfree(rt);
|
||||||
err:
|
err:
|
||||||
|
|
Loading…
Add table
Reference in a new issue