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
Show file tree
Hide file tree
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
Expand Up @@ -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);
Expand All @@ -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;
Expand Down
7 changes: 4 additions & 3 deletions include/net/if_inet6.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -128,6 +128,7 @@ struct ifmcaddr6 {
spinlock_t mca_lock;
unsigned long mca_cstamp;
unsigned long mca_tstamp;
struct rcu_head rcu;
};

/* Anycast stuff */
Expand Down Expand Up @@ -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;
Expand Down
6 changes: 3 additions & 3 deletions net/batman-adv/multicast.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
9 changes: 5 additions & 4 deletions net/ipv6/addrconf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion net/ipv6/addrconf_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion net/ipv6/af_inet6.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Loading

0 comments on commit 88e2ca3

Please sign in to comment.