forked from mirrors/linux
		
	net: Fix ip_mc_{dec,inc}_group allocation context
After4effd28c12("bridge: join all-snoopers multicast address"), I started seeing the following sleep in atomic warnings: [ 26.763893] BUG: sleeping function called from invalid context at mm/slab.h:421 [ 26.771425] in_atomic(): 1, irqs_disabled(): 0, pid: 1658, name: sh [ 26.777855] INFO: lockdep is turned off. [ 26.781916] CPU: 0 PID: 1658 Comm: sh Not tainted 5.0.0-rc4 #20 [ 26.787943] Hardware name: BCM97278SV (DT) [ 26.792118] Call trace: [ 26.794645] dump_backtrace+0x0/0x170 [ 26.798391] show_stack+0x24/0x30 [ 26.801787] dump_stack+0xa4/0xe4 [ 26.805182] ___might_sleep+0x208/0x218 [ 26.809102] __might_sleep+0x78/0x88 [ 26.812762] kmem_cache_alloc_trace+0x64/0x28c [ 26.817301] igmp_group_dropped+0x150/0x230 [ 26.821573] ip_mc_dec_group+0x1b0/0x1f8 [ 26.825585] br_ip4_multicast_leave_snoopers.isra.11+0x174/0x190 [ 26.831704] br_multicast_toggle+0x78/0xcc [ 26.835887] store_bridge_parm+0xc4/0xfc [ 26.839894] multicast_snooping_store+0x3c/0x4c [ 26.844517] dev_attr_store+0x44/0x5c [ 26.848262] sysfs_kf_write+0x50/0x68 [ 26.852006] kernfs_fop_write+0x14c/0x1b4 [ 26.856102] __vfs_write+0x60/0x190 [ 26.859668] vfs_write+0xc8/0x168 [ 26.863059] ksys_write+0x70/0xc8 [ 26.866449] __arm64_sys_write+0x24/0x30 [ 26.870458] el0_svc_common+0xa0/0x11c [ 26.874291] el0_svc_handler+0x38/0x70 [ 26.878120] el0_svc+0x8/0xc while toggling the bridge's multicast_snooping attribute dynamically. Pass a gfp_t down to igmpv3_add_delrec(), introduce __igmp_group_dropped() and introduce __ip_mc_dec_group() to take a gfp_t argument. Similarly introduce ____ip_mc_inc_group() and __ip_mc_inc_group() to allow caller to specify gfp_t. IPv6 part of the patch appears fine. Fixes:4effd28c12("bridge: join all-snoopers multicast address") Signed-off-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									bff5731d43
								
							
						
					
					
						commit
						9fb20801da
					
				
					 3 changed files with 33 additions and 14 deletions
				
			
		| 
						 | 
				
			
			@ -137,7 +137,13 @@ extern void ip_mc_up(struct in_device *);
 | 
			
		|||
extern void ip_mc_down(struct in_device *);
 | 
			
		||||
extern void ip_mc_unmap(struct in_device *);
 | 
			
		||||
extern void ip_mc_remap(struct in_device *);
 | 
			
		||||
extern void ip_mc_dec_group(struct in_device *in_dev, __be32 addr);
 | 
			
		||||
extern void __ip_mc_dec_group(struct in_device *in_dev, __be32 addr, gfp_t gfp);
 | 
			
		||||
static inline void ip_mc_dec_group(struct in_device *in_dev, __be32 addr)
 | 
			
		||||
{
 | 
			
		||||
	return __ip_mc_dec_group(in_dev, addr, GFP_KERNEL);
 | 
			
		||||
}
 | 
			
		||||
extern void __ip_mc_inc_group(struct in_device *in_dev, __be32 addr,
 | 
			
		||||
			      gfp_t gfp);
 | 
			
		||||
extern void ip_mc_inc_group(struct in_device *in_dev, __be32 addr);
 | 
			
		||||
int ip_mc_check_igmp(struct sk_buff *skb);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1841,7 +1841,7 @@ static void br_ip4_multicast_join_snoopers(struct net_bridge *br)
 | 
			
		|||
	if (!in_dev)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	ip_mc_inc_group(in_dev, htonl(INADDR_ALLSNOOPERS_GROUP));
 | 
			
		||||
	__ip_mc_inc_group(in_dev, htonl(INADDR_ALLSNOOPERS_GROUP), GFP_ATOMIC);
 | 
			
		||||
	in_dev_put(in_dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1872,7 +1872,7 @@ static void br_ip4_multicast_leave_snoopers(struct net_bridge *br)
 | 
			
		|||
	if (WARN_ON(!in_dev))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	ip_mc_dec_group(in_dev, htonl(INADDR_ALLSNOOPERS_GROUP));
 | 
			
		||||
	__ip_mc_dec_group(in_dev, htonl(INADDR_ALLSNOOPERS_GROUP), GFP_ATOMIC);
 | 
			
		||||
	in_dev_put(in_dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -159,7 +159,8 @@ static int unsolicited_report_interval(struct in_device *in_dev)
 | 
			
		|||
	return interval_jiffies;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im);
 | 
			
		||||
static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im,
 | 
			
		||||
			      gfp_t gfp);
 | 
			
		||||
static void igmpv3_del_delrec(struct in_device *in_dev, struct ip_mc_list *im);
 | 
			
		||||
static void igmpv3_clear_delrec(struct in_device *in_dev);
 | 
			
		||||
static int sf_setstate(struct ip_mc_list *pmc);
 | 
			
		||||
| 
						 | 
				
			
			@ -1145,7 +1146,8 @@ static void ip_mc_filter_del(struct in_device *in_dev, __be32 addr)
 | 
			
		|||
/*
 | 
			
		||||
 * deleted ip_mc_list manipulation
 | 
			
		||||
 */
 | 
			
		||||
static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im)
 | 
			
		||||
static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im,
 | 
			
		||||
			      gfp_t gfp)
 | 
			
		||||
{
 | 
			
		||||
	struct ip_mc_list *pmc;
 | 
			
		||||
	struct net *net = dev_net(in_dev->dev);
 | 
			
		||||
| 
						 | 
				
			
			@ -1156,7 +1158,7 @@ static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im)
 | 
			
		|||
	 * for deleted items allows change reports to use common code with
 | 
			
		||||
	 * non-deleted or query-response MCA's.
 | 
			
		||||
	 */
 | 
			
		||||
	pmc = kzalloc(sizeof(*pmc), GFP_KERNEL);
 | 
			
		||||
	pmc = kzalloc(sizeof(*pmc), gfp);
 | 
			
		||||
	if (!pmc)
 | 
			
		||||
		return;
 | 
			
		||||
	spin_lock_init(&pmc->lock);
 | 
			
		||||
| 
						 | 
				
			
			@ -1261,7 +1263,7 @@ static void igmpv3_clear_delrec(struct in_device *in_dev)
 | 
			
		|||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void igmp_group_dropped(struct ip_mc_list *im)
 | 
			
		||||
static void __igmp_group_dropped(struct ip_mc_list *im, gfp_t gfp)
 | 
			
		||||
{
 | 
			
		||||
	struct in_device *in_dev = im->interface;
 | 
			
		||||
#ifdef CONFIG_IP_MULTICAST
 | 
			
		||||
| 
						 | 
				
			
			@ -1292,13 +1294,18 @@ static void igmp_group_dropped(struct ip_mc_list *im)
 | 
			
		|||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		/* IGMPv3 */
 | 
			
		||||
		igmpv3_add_delrec(in_dev, im);
 | 
			
		||||
		igmpv3_add_delrec(in_dev, im, gfp);
 | 
			
		||||
 | 
			
		||||
		igmp_ifc_event(in_dev);
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void igmp_group_dropped(struct ip_mc_list *im)
 | 
			
		||||
{
 | 
			
		||||
	__igmp_group_dropped(im, GFP_KERNEL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void igmp_group_added(struct ip_mc_list *im)
 | 
			
		||||
{
 | 
			
		||||
	struct in_device *in_dev = im->interface;
 | 
			
		||||
| 
						 | 
				
			
			@ -1400,8 +1407,8 @@ static void ip_mc_hash_remove(struct in_device *in_dev,
 | 
			
		|||
/*
 | 
			
		||||
 *	A socket has joined a multicast group on device dev.
 | 
			
		||||
 */
 | 
			
		||||
static void __ip_mc_inc_group(struct in_device *in_dev, __be32 addr,
 | 
			
		||||
			      unsigned int mode)
 | 
			
		||||
static void ____ip_mc_inc_group(struct in_device *in_dev, __be32 addr,
 | 
			
		||||
				unsigned int mode, gfp_t gfp)
 | 
			
		||||
{
 | 
			
		||||
	struct ip_mc_list *im;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1415,7 +1422,7 @@ static void __ip_mc_inc_group(struct in_device *in_dev, __be32 addr,
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	im = kzalloc(sizeof(*im), GFP_KERNEL);
 | 
			
		||||
	im = kzalloc(sizeof(*im), gfp);
 | 
			
		||||
	if (!im)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1448,6 +1455,12 @@ static void __ip_mc_inc_group(struct in_device *in_dev, __be32 addr,
 | 
			
		|||
	return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void __ip_mc_inc_group(struct in_device *in_dev, __be32 addr, gfp_t gfp)
 | 
			
		||||
{
 | 
			
		||||
	____ip_mc_inc_group(in_dev, addr, MCAST_EXCLUDE, gfp);
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL(__ip_mc_inc_group);
 | 
			
		||||
 | 
			
		||||
void ip_mc_inc_group(struct in_device *in_dev, __be32 addr)
 | 
			
		||||
{
 | 
			
		||||
	__ip_mc_inc_group(in_dev, addr, MCAST_EXCLUDE);
 | 
			
		||||
| 
						 | 
				
			
			@ -1634,7 +1647,7 @@ static void ip_mc_rejoin_groups(struct in_device *in_dev)
 | 
			
		|||
 *	A socket has left a multicast group on device dev
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
void ip_mc_dec_group(struct in_device *in_dev, __be32 addr)
 | 
			
		||||
void __ip_mc_dec_group(struct in_device *in_dev, __be32 addr, gfp_t gfp)
 | 
			
		||||
{
 | 
			
		||||
	struct ip_mc_list *i;
 | 
			
		||||
	struct ip_mc_list __rcu **ip;
 | 
			
		||||
| 
						 | 
				
			
			@ -1649,7 +1662,7 @@ void ip_mc_dec_group(struct in_device *in_dev, __be32 addr)
 | 
			
		|||
				ip_mc_hash_remove(in_dev, i);
 | 
			
		||||
				*ip = i->next_rcu;
 | 
			
		||||
				in_dev->mc_count--;
 | 
			
		||||
				igmp_group_dropped(i);
 | 
			
		||||
				__igmp_group_dropped(i, gfp);
 | 
			
		||||
				ip_mc_clear_src(i);
 | 
			
		||||
 | 
			
		||||
				if (!in_dev->dead)
 | 
			
		||||
| 
						 | 
				
			
			@ -1662,7 +1675,7 @@ void ip_mc_dec_group(struct in_device *in_dev, __be32 addr)
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL(ip_mc_dec_group);
 | 
			
		||||
EXPORT_SYMBOL(__ip_mc_dec_group);
 | 
			
		||||
 | 
			
		||||
/* Device changing type */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue