Skip to content

Commit 5720a32

Browse files
q2venPaolo Abeni
authored andcommitted
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 <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
1 parent c4837b9 commit 5720a32

File tree

1 file changed

+22
-3
lines changed

1 file changed

+22
-3
lines changed

net/ipv6/route.c

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3665,10 +3665,12 @@ int fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh,
36653665
goto out;
36663666

36673667
pcpu_alloc:
3668-
fib6_nh->rt6i_pcpu = alloc_percpu_gfp(struct rt6_info *, gfp_flags);
36693668
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+
}
36723674
}
36733675

36743676
fib6_nh->fib_nh_dev = dev;
@@ -3728,6 +3730,15 @@ void fib6_nh_release_dsts(struct fib6_nh *fib6_nh)
37283730
}
37293731
}
37303732

3733+
static int fib6_nh_prealloc_percpu(struct fib6_nh *fib6_nh, gfp_t gfp_flags)
3734+
{
3735+
fib6_nh->rt6i_pcpu = alloc_percpu_gfp(struct rt6_info *, gfp_flags);
3736+
if (!fib6_nh->rt6i_pcpu)
3737+
return -ENOMEM;
3738+
3739+
return 0;
3740+
}
3741+
37313742
static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg,
37323743
gfp_t gfp_flags,
37333744
struct netlink_ext_ack *extack)
@@ -3765,6 +3776,12 @@ static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg,
37653776
goto free;
37663777
}
37673778

3779+
if (!cfg->fc_nh_id) {
3780+
err = fib6_nh_prealloc_percpu(&rt->fib6_nh[0], gfp_flags);
3781+
if (err)
3782+
goto free_metrics;
3783+
}
3784+
37683785
if (cfg->fc_flags & RTF_ADDRCONF)
37693786
rt->dst_nocount = true;
37703787

@@ -3789,6 +3806,8 @@ static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg,
37893806
rt->fib6_src.plen = cfg->fc_src_len;
37903807
#endif
37913808
return rt;
3809+
free_metrics:
3810+
ip_fib_metrics_put(rt->fib6_metrics);
37923811
free:
37933812
kfree(rt);
37943813
err:

0 commit comments

Comments
 (0)