Skip to content

Commit

Permalink
mld: convert ifmcaddr6 to RCU
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Taehee Yoo authored and David S. Miller committed Mar 26, 2021
1 parent 4b200e3 commit 88e2ca3
Showing 7 changed files with 140 additions and 188 deletions.
6 changes: 3 additions & 3 deletions drivers/s390/net/qeth_l3_main.c
Original file line number Diff line number Diff line change
@@ -1098,8 +1098,9 @@ static int qeth_l3_add_mcast_rtnl(struct net_device *dev, int vid, void *arg)
tmp.disp_flag = QETH_DISP_ADDR_ADD;
tmp.is_multicast = 1;

read_lock_bh(&in6_dev->lock);
for (im6 = in6_dev->mc_list; im6 != NULL; im6 = im6->next) {
for (im6 = rtnl_dereference(in6_dev->mc_list);
im6;
im6 = rtnl_dereference(im6->next)) {
tmp.u.a6.addr = im6->mca_addr;

ipm = qeth_l3_find_addr_by_ip(card, &tmp);
@@ -1117,7 +1118,6 @@ static int qeth_l3_add_mcast_rtnl(struct net_device *dev, int vid, void *arg)
qeth_l3_ipaddr_hash(ipm));

}
read_unlock_bh(&in6_dev->lock);

out:
return 0;
7 changes: 4 additions & 3 deletions include/net/if_inet6.h
Original file line number Diff line number Diff line change
@@ -115,7 +115,7 @@ struct ip6_sf_list {
struct ifmcaddr6 {
struct in6_addr mca_addr;
struct inet6_dev *idev;
struct ifmcaddr6 *next;
struct ifmcaddr6 __rcu *next;
struct ip6_sf_list __rcu *mca_sources;
struct ip6_sf_list __rcu *mca_tomb;
unsigned int mca_sfmode;
@@ -128,6 +128,7 @@ struct ifmcaddr6 {
spinlock_t mca_lock;
unsigned long mca_cstamp;
unsigned long mca_tstamp;
struct rcu_head rcu;
};

/* Anycast stuff */
@@ -166,8 +167,8 @@ struct inet6_dev {

struct list_head addr_list;

struct ifmcaddr6 *mc_list;
struct ifmcaddr6 *mc_tomb;
struct ifmcaddr6 __rcu *mc_list;
struct ifmcaddr6 __rcu *mc_tomb;

unsigned char mc_qrv; /* Query Robustness Variable */
unsigned char mc_gq_running;
6 changes: 3 additions & 3 deletions net/batman-adv/multicast.c
Original file line number Diff line number Diff line change
@@ -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;
9 changes: 5 additions & 4 deletions net/ipv6/addrconf.c
Original file line number Diff line number Diff line change
@@ -5107,17 +5107,20 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb,
break;
}
case MULTICAST_ADDR:
read_unlock_bh(&idev->lock);
fillargs->event = RTM_GETMULTICAST;

/* multicast address */
for (ifmca = idev->mc_list; ifmca;
ifmca = ifmca->next, ip_idx++) {
for (ifmca = rcu_dereference(idev->mc_list);
ifmca;
ifmca = rcu_dereference(ifmca->next), ip_idx++) {
if (ip_idx < s_ip_idx)
continue;
err = inet6_fill_ifmcaddr(skb, ifmca, fillargs);
if (err < 0)
break;
}
read_lock_bh(&idev->lock);
break;
case ANYCAST_ADDR:
fillargs->event = RTM_GETANYCAST;
@@ -6093,10 +6096,8 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)

static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
{
rcu_read_lock_bh();
if (likely(ifp->idev->dead == 0))
__ipv6_ifa_notify(event, ifp);
rcu_read_unlock_bh();
}

#ifdef CONFIG_SYSCTL
2 changes: 1 addition & 1 deletion net/ipv6/addrconf_core.c
Original file line number Diff line number Diff line change
@@ -250,7 +250,7 @@ void in6_dev_finish_destroy(struct inet6_dev *idev)
struct net_device *dev = idev->dev;

WARN_ON(!list_empty(&idev->addr_list));
WARN_ON(idev->mc_list);
WARN_ON(rcu_access_pointer(idev->mc_list));
WARN_ON(timer_pending(&idev->rs_timer));

#ifdef NET_REFCNT_DEBUG
2 changes: 1 addition & 1 deletion net/ipv6/af_inet6.c
Original file line number Diff line number Diff line change
@@ -222,7 +222,7 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol,
inet->mc_loop = 1;
inet->mc_ttl = 1;
inet->mc_index = 0;
inet->mc_list = NULL;
RCU_INIT_POINTER(inet->mc_list, NULL);
inet->rcv_tos = 0;

if (net->ipv4.sysctl_ip_no_pmtu_disc)
Loading

0 comments on commit 88e2ca3

Please sign in to comment.