Repository : ssh://git@diktynna/batman-adv
On branch : master
commit 007b4c4b031f565205c0702af4c5b1c81d5009c4 Author: Taehee Yoo ap420073@gmail.com Date: Sun Apr 18 22:14:22 2021 +0200
batman-adv: convert ifmcaddr6 to RCU
The ifmcaddr6 has been protected by inet6_dev->lock(rwlock) so that the critical section is atomic context. In order to switch this context, changing locking is needed. The ifmcaddr6 actually already protected by RTNL So if it's converted to use RCU, its control path context can be switched to sleepable.
Suggested-by: Cong Wang xiyou.wangcong@gmail.com Signed-off-by: Taehee Yoo ap420073@gmail.com Signed-off-by: David S. Miller davem@davemloft.net [linus.luessing@c0d3.blue: Add compat code] Signed-off-by: Linus L��ssing linus.luessing@c0d3.blue Signed-off-by: Sven Eckelmann sven@narfation.org
007b4c4b031f565205c0702af4c5b1c81d5009c4 compat-include/net/addrconf.h | 85 +++++++++++++++++++++++++++++++++++++++++++ net/batman-adv/multicast.c | 6 +-- 2 files changed, 88 insertions(+), 3 deletions(-)
diff --git a/compat-include/net/addrconf.h b/compat-include/net/addrconf.h index 30124124..080e1dda 100644 --- a/compat-include/net/addrconf.h +++ b/compat-include/net/addrconf.h @@ -25,4 +25,89 @@ static inline int batadv_ipv6_mc_check_mld(struct sk_buff *skb)
#endif /* LINUX_VERSION_IS_LESS(5, 1, 0) */
+#if LINUX_VERSION_IS_LESS(5, 13, 0) + +static bool batadv_mcast_mla_is_duplicate(u8 *mcast_addr, + struct hlist_head *mcast_list); + +static inline int +compat_batadv_mcast_mla_softif_get_ipv6(struct net_device *dev, + struct hlist_head *mcast_list, + struct batadv_mcast_mla_flags *flags, + u8 *mcast_addr, + struct batadv_hw_addr *new, + struct inet6_dev *in6_dev) + +{ + struct ifmcaddr6 *pmc6; + int ret = 0; + + if (flags->tvlv_flags & BATADV_MCAST_WANT_ALL_IPV6) + return 0; + + rcu_read_lock(); + + in6_dev = __in6_dev_get(dev); + if (!in6_dev) { + rcu_read_unlock(); + return 0; + } + + read_lock_bh(&in6_dev->lock); + for (pmc6 = in6_dev->mc_list; pmc6; pmc6 = pmc6->next) { + if (IPV6_ADDR_MC_SCOPE(&pmc6->mca_addr) < + IPV6_ADDR_SCOPE_LINKLOCAL) + continue; + + if (flags->tvlv_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES && + ipv6_addr_is_ll_all_nodes(&pmc6->mca_addr)) + continue; + + if (!(flags->tvlv_flags & BATADV_MCAST_WANT_NO_RTR6) && + IPV6_ADDR_MC_SCOPE(&pmc6->mca_addr) > + IPV6_ADDR_SCOPE_LINKLOCAL) + continue; + + ipv6_eth_mc_map(&pmc6->mca_addr, mcast_addr); + + if (batadv_mcast_mla_is_duplicate(mcast_addr, mcast_list)) + continue; + + new = kmalloc(sizeof(*new), GFP_ATOMIC); + if (!new) { + ret = -ENOMEM; + break; + } + + ether_addr_copy(new->addr, mcast_addr); + hlist_add_head(&new->list, mcast_list); + ret++; + } + read_unlock_bh(&in6_dev->lock); + rcu_read_unlock(); + + return ret; +} + +#define ifmcaddr6 \ + net_device *orig_dev = dev; \ + return compat_batadv_mcast_mla_softif_get_ipv6(orig_dev, \ + mcast_list, \ + flags, \ + mcast_addr, \ + new = NULL, \ + in6_dev = NULL); \ + } \ + static inline int \ + __unused_batadv_mcast_mla_softif_get_ipv6(struct net_device *dev, \ + struct hlist_head *mcast_list, \ + struct batadv_mcast_mla_flags *flags) \ + { \ + struct batadv_hw_addr *new; \ + struct inet6_dev *in6_dev; \ + u8 mcast_addr[ETH_ALEN]; \ + struct ifmcaddr6 + +#endif /* LINUX_VERSION_IS_LESS(5, 13, 0) */ + #endif /* _NET_BATMAN_ADV_COMPAT_NET_ADDRCONF_H_ */ diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c index 28166402..1d63c8cb 100644 --- a/net/batman-adv/multicast.c +++ b/net/batman-adv/multicast.c @@ -454,8 +454,9 @@ batadv_mcast_mla_softif_get_ipv6(struct net_device *dev, return 0; }
- read_lock_bh(&in6_dev->lock); - for (pmc6 = in6_dev->mc_list; pmc6; pmc6 = pmc6->next) { + for (pmc6 = rcu_dereference(in6_dev->mc_list); + pmc6; + pmc6 = rcu_dereference(pmc6->next)) { if (IPV6_ADDR_MC_SCOPE(&pmc6->mca_addr) < IPV6_ADDR_SCOPE_LINKLOCAL) continue; @@ -484,7 +485,6 @@ batadv_mcast_mla_softif_get_ipv6(struct net_device *dev, hlist_add_head(&new->list, mcast_list); ret++; } - read_unlock_bh(&in6_dev->lock); rcu_read_unlock();
return ret;