forked from luck/tmp_suning_uos_patched
9fb20801da
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>
151 lines
4.6 KiB
C
151 lines
4.6 KiB
C
/*
|
|
* Linux NET3: Internet Group Management Protocol [IGMP]
|
|
*
|
|
* Authors:
|
|
* Alan Cox <alan@lxorguk.ukuu.org.uk>
|
|
*
|
|
* Extended to talk the BSD extended IGMP protocol of mrouted 3.6
|
|
*
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version
|
|
* 2 of the License, or (at your option) any later version.
|
|
*/
|
|
#ifndef _LINUX_IGMP_H
|
|
#define _LINUX_IGMP_H
|
|
|
|
#include <linux/skbuff.h>
|
|
#include <linux/timer.h>
|
|
#include <linux/in.h>
|
|
#include <linux/ip.h>
|
|
#include <linux/refcount.h>
|
|
#include <uapi/linux/igmp.h>
|
|
|
|
static inline struct igmphdr *igmp_hdr(const struct sk_buff *skb)
|
|
{
|
|
return (struct igmphdr *)skb_transport_header(skb);
|
|
}
|
|
|
|
static inline struct igmpv3_report *
|
|
igmpv3_report_hdr(const struct sk_buff *skb)
|
|
{
|
|
return (struct igmpv3_report *)skb_transport_header(skb);
|
|
}
|
|
|
|
static inline struct igmpv3_query *
|
|
igmpv3_query_hdr(const struct sk_buff *skb)
|
|
{
|
|
return (struct igmpv3_query *)skb_transport_header(skb);
|
|
}
|
|
|
|
struct ip_sf_socklist {
|
|
unsigned int sl_max;
|
|
unsigned int sl_count;
|
|
struct rcu_head rcu;
|
|
__be32 sl_addr[0];
|
|
};
|
|
|
|
#define IP_SFLSIZE(count) (sizeof(struct ip_sf_socklist) + \
|
|
(count) * sizeof(__be32))
|
|
|
|
#define IP_SFBLOCK 10 /* allocate this many at once */
|
|
|
|
/* ip_mc_socklist is real list now. Speed is not argument;
|
|
this list never used in fast path code
|
|
*/
|
|
|
|
struct ip_mc_socklist {
|
|
struct ip_mc_socklist __rcu *next_rcu;
|
|
struct ip_mreqn multi;
|
|
unsigned int sfmode; /* MCAST_{INCLUDE,EXCLUDE} */
|
|
struct ip_sf_socklist __rcu *sflist;
|
|
struct rcu_head rcu;
|
|
};
|
|
|
|
struct ip_sf_list {
|
|
struct ip_sf_list *sf_next;
|
|
__be32 sf_inaddr;
|
|
unsigned long sf_count[2]; /* include/exclude counts */
|
|
unsigned char sf_gsresp; /* include in g & s response? */
|
|
unsigned char sf_oldin; /* change state */
|
|
unsigned char sf_crcount; /* retrans. left to send */
|
|
};
|
|
|
|
struct ip_mc_list {
|
|
struct in_device *interface;
|
|
__be32 multiaddr;
|
|
unsigned int sfmode;
|
|
struct ip_sf_list *sources;
|
|
struct ip_sf_list *tomb;
|
|
unsigned long sfcount[2];
|
|
union {
|
|
struct ip_mc_list *next;
|
|
struct ip_mc_list __rcu *next_rcu;
|
|
};
|
|
struct ip_mc_list __rcu *next_hash;
|
|
struct timer_list timer;
|
|
int users;
|
|
refcount_t refcnt;
|
|
spinlock_t lock;
|
|
char tm_running;
|
|
char reporter;
|
|
char unsolicit_count;
|
|
char loaded;
|
|
unsigned char gsquery; /* check source marks? */
|
|
unsigned char crcount;
|
|
struct rcu_head rcu;
|
|
};
|
|
|
|
/* V3 exponential field decoding */
|
|
#define IGMPV3_MASK(value, nb) ((nb)>=32 ? (value) : ((1<<(nb))-1) & (value))
|
|
#define IGMPV3_EXP(thresh, nbmant, nbexp, value) \
|
|
((value) < (thresh) ? (value) : \
|
|
((IGMPV3_MASK(value, nbmant) | (1<<(nbmant))) << \
|
|
(IGMPV3_MASK((value) >> (nbmant), nbexp) + (nbexp))))
|
|
|
|
#define IGMPV3_QQIC(value) IGMPV3_EXP(0x80, 4, 3, value)
|
|
#define IGMPV3_MRC(value) IGMPV3_EXP(0x80, 4, 3, value)
|
|
|
|
static inline int ip_mc_may_pull(struct sk_buff *skb, unsigned int len)
|
|
{
|
|
if (skb_transport_offset(skb) + ip_transport_len(skb) < len)
|
|
return -EINVAL;
|
|
|
|
return pskb_may_pull(skb, len);
|
|
}
|
|
|
|
extern int ip_check_mc_rcu(struct in_device *dev, __be32 mc_addr, __be32 src_addr, u8 proto);
|
|
extern int igmp_rcv(struct sk_buff *);
|
|
extern int ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr);
|
|
extern int ip_mc_join_group_ssm(struct sock *sk, struct ip_mreqn *imr,
|
|
unsigned int mode);
|
|
extern int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr);
|
|
extern void ip_mc_drop_socket(struct sock *sk);
|
|
extern int ip_mc_source(int add, int omode, struct sock *sk,
|
|
struct ip_mreq_source *mreqs, int ifindex);
|
|
extern int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf,int ifindex);
|
|
extern int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf,
|
|
struct ip_msfilter __user *optval, int __user *optlen);
|
|
extern int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf,
|
|
struct group_filter __user *optval, int __user *optlen);
|
|
extern int ip_mc_sf_allow(struct sock *sk, __be32 local, __be32 rmt,
|
|
int dif, int sdif);
|
|
extern void ip_mc_init_dev(struct in_device *);
|
|
extern void ip_mc_destroy_dev(struct in_device *);
|
|
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, 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);
|
|
|
|
#endif
|