forked from mirrors/linux
		
	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,11 +3665,13 @@ int fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh, | ||||||
| 		goto out; | 		goto out; | ||||||
| 
 | 
 | ||||||
| pcpu_alloc: | pcpu_alloc: | ||||||
|  | 	if (!fib6_nh->rt6i_pcpu) { | ||||||
| 		fib6_nh->rt6i_pcpu = alloc_percpu_gfp(struct rt6_info *, gfp_flags); | 		fib6_nh->rt6i_pcpu = alloc_percpu_gfp(struct rt6_info *, gfp_flags); | ||||||
| 		if (!fib6_nh->rt6i_pcpu) { | 		if (!fib6_nh->rt6i_pcpu) { | ||||||
| 			err = -ENOMEM; | 			err = -ENOMEM; | ||||||
| 			goto out; | 			goto out; | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	fib6_nh->fib_nh_dev = dev; | 	fib6_nh->fib_nh_dev = dev; | ||||||
| 	fib6_nh->fib_nh_oif = dev->ifindex; | 	fib6_nh->fib_nh_oif = dev->ifindex; | ||||||
|  | @ -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…
	
		Reference in a new issue
	
	 Kuniyuki Iwashima
						Kuniyuki Iwashima