Message ID | 20191118090925.2474-1-anders.roxell@linaro.org |
---|---|
State | New |
Headers | show |
Series | net: ipmr: fix suspicious RCU warning | expand |
From: Anders Roxell <anders.roxell@linaro.org> Date: Mon, 18 Nov 2019 10:09:25 +0100 > @@ -108,9 +108,18 @@ static void igmpmsg_netlink_event(struct mr_table *mrt, struct sk_buff *pkt); > static void mroute_clean_tables(struct mr_table *mrt, int flags); > static void ipmr_expire_process(struct timer_list *t); > > +#ifdef CONFIG_PROVE_LOCKING > +int ip_mr_initialized; > +void ip_mr_now_initialized(void) { ip_mr_initialized = 1; } > +#else > +const int ip_mr_initialized = 1; > +void ip_mr_now_initialized(void) { } > +#endif This seems excessive and a bit not so pretty. > + > #ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES > #define ipmr_for_each_table(mrt, net) \ > - list_for_each_entry_rcu(mrt, &net->ipv4.mr_tables, list) > + list_for_each_entry_rcu(mrt, &net->ipv4.mr_tables, list, \ > + (lockdep_rtnl_is_held() || !ip_mr_initialized)) > > static struct mr_table *ipmr_mr_table_iter(struct net *net, > struct mr_table *mrt) The problematic code path is ipmr_rules_init() done during ipmr_net_init(). You can just wrap this call around RCU locking or take the RTNL mutex. That way you don't need to rediculous ip_mr_initialized knob which frankly doesn't even seem accurate to me. It's a centralized global variable which is holding state about multiple network namespace objects which makes absolutely no sense at all, it's wrong.
On Tue, Nov 19, 2019 at 02:50:48PM -0800, David Miller wrote: > From: Anders Roxell <anders.roxell@linaro.org> > Date: Mon, 18 Nov 2019 10:09:25 +0100 > > > @@ -108,9 +108,18 @@ static void igmpmsg_netlink_event(struct mr_table *mrt, struct sk_buff *pkt); > > static void mroute_clean_tables(struct mr_table *mrt, int flags); > > static void ipmr_expire_process(struct timer_list *t); > > > > +#ifdef CONFIG_PROVE_LOCKING > > +int ip_mr_initialized; > > +void ip_mr_now_initialized(void) { ip_mr_initialized = 1; } > > +#else > > +const int ip_mr_initialized = 1; > > +void ip_mr_now_initialized(void) { } > > +#endif > > This seems excessive and a bit not so pretty. > > > + > > #ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES > > #define ipmr_for_each_table(mrt, net) \ > > - list_for_each_entry_rcu(mrt, &net->ipv4.mr_tables, list) > > + list_for_each_entry_rcu(mrt, &net->ipv4.mr_tables, list, \ > > + (lockdep_rtnl_is_held() || !ip_mr_initialized)) > > > > static struct mr_table *ipmr_mr_table_iter(struct net *net, > > struct mr_table *mrt) > > The problematic code path is ipmr_rules_init() done during ipmr_net_init(). > > You can just wrap this call around RCU locking or take the RTNL mutex. Agreed, that would work quite well. Thanx, Paul > That way you don't need to rediculous ip_mr_initialized knob which frankly > doesn't even seem accurate to me. It's a centralized global variable > which is holding state about multiple network namespace objects which makes > absolutely no sense at all, it's wrong.
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 6e68def66822..93007c429dae 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -108,9 +108,18 @@ static void igmpmsg_netlink_event(struct mr_table *mrt, struct sk_buff *pkt); static void mroute_clean_tables(struct mr_table *mrt, int flags); static void ipmr_expire_process(struct timer_list *t); +#ifdef CONFIG_PROVE_LOCKING +int ip_mr_initialized; +void ip_mr_now_initialized(void) { ip_mr_initialized = 1; } +#else +const int ip_mr_initialized = 1; +void ip_mr_now_initialized(void) { } +#endif + #ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES #define ipmr_for_each_table(mrt, net) \ - list_for_each_entry_rcu(mrt, &net->ipv4.mr_tables, list) + list_for_each_entry_rcu(mrt, &net->ipv4.mr_tables, list, \ + (lockdep_rtnl_is_held() || !ip_mr_initialized)) static struct mr_table *ipmr_mr_table_iter(struct net *net, struct mr_table *mrt) @@ -3160,6 +3169,8 @@ int __init ip_mr_init(void) rtnl_register(RTNL_FAMILY_IPMR, RTM_GETLINK, NULL, ipmr_rtm_dumplink, 0); + + ip_mr_now_initialized(); return 0; #ifdef CONFIG_IP_PIMSM_V2