forked from luck/tmp_suning_uos_patched
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
|
@ -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 New Issue
Block a user