Skip to content

Commit 2ceb71c

Browse files
q2venkuba-moo
authored andcommitted
ipv6: mcast: Don't hold RTNL for IPV6_DROP_MEMBERSHIP and MCAST_LEAVE_GROUP.
In __ipv6_sock_mc_drop(), per-socket mld data is protected by lock_sock(), and only __dev_get_by_index() and __in6_dev_get() require RTNL. Let's use dev_get_by_index() and in6_dev_get() and drop RTNL for IPV6_ADD_MEMBERSHIP and MCAST_JOIN_GROUP. Note that __ipv6_sock_mc_drop() is factorised to reuse in the next patch. Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com> Reviewed-by: Eric Dumazet <edumazet@google.com> Link: https://patch.msgid.link/20250702230210.3115355-8-kuni1840@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
1 parent 1767bb2 commit 2ceb71c

File tree

2 files changed

+27
-22
lines changed

2 files changed

+27
-22
lines changed

net/ipv6/ipv6_sockglue.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,8 @@ static bool setsockopt_needs_rtnl(int optname)
121121
{
122122
switch (optname) {
123123
case IPV6_ADDRFORM:
124-
case IPV6_DROP_MEMBERSHIP:
125124
case IPV6_JOIN_ANYCAST:
126125
case IPV6_LEAVE_ANYCAST:
127-
case MCAST_LEAVE_GROUP:
128126
case MCAST_JOIN_SOURCE_GROUP:
129127
case MCAST_LEAVE_SOURCE_GROUP:
130128
case MCAST_BLOCK_SOURCE:

net/ipv6/mcast.c

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -253,14 +253,36 @@ int ipv6_sock_mc_join_ssm(struct sock *sk, int ifindex,
253253
/*
254254
* socket leave on multicast group
255255
*/
256+
static void __ipv6_sock_mc_drop(struct sock *sk, struct ipv6_mc_socklist *mc_lst)
257+
{
258+
struct net *net = sock_net(sk);
259+
struct net_device *dev;
260+
261+
dev = dev_get_by_index(net, mc_lst->ifindex);
262+
if (dev) {
263+
struct inet6_dev *idev = in6_dev_get(dev);
264+
265+
ip6_mc_leave_src(sk, mc_lst, idev);
266+
267+
if (idev) {
268+
__ipv6_dev_mc_dec(idev, &mc_lst->addr);
269+
in6_dev_put(idev);
270+
}
271+
272+
dev_put(dev);
273+
} else {
274+
ip6_mc_leave_src(sk, mc_lst, NULL);
275+
}
276+
277+
atomic_sub(sizeof(*mc_lst), &sk->sk_omem_alloc);
278+
kfree_rcu(mc_lst, rcu);
279+
}
280+
256281
int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
257282
{
258283
struct ipv6_pinfo *np = inet6_sk(sk);
259-
struct ipv6_mc_socklist *mc_lst;
260284
struct ipv6_mc_socklist __rcu **lnk;
261-
struct net *net = sock_net(sk);
262-
263-
ASSERT_RTNL();
285+
struct ipv6_mc_socklist *mc_lst;
264286

265287
if (!ipv6_addr_is_multicast(addr))
266288
return -EINVAL;
@@ -270,23 +292,8 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
270292
lnk = &mc_lst->next) {
271293
if ((ifindex == 0 || mc_lst->ifindex == ifindex) &&
272294
ipv6_addr_equal(&mc_lst->addr, addr)) {
273-
struct net_device *dev;
274-
275295
*lnk = mc_lst->next;
276-
277-
dev = __dev_get_by_index(net, mc_lst->ifindex);
278-
if (dev) {
279-
struct inet6_dev *idev = __in6_dev_get(dev);
280-
281-
ip6_mc_leave_src(sk, mc_lst, idev);
282-
if (idev)
283-
__ipv6_dev_mc_dec(idev, &mc_lst->addr);
284-
} else {
285-
ip6_mc_leave_src(sk, mc_lst, NULL);
286-
}
287-
288-
atomic_sub(sizeof(*mc_lst), &sk->sk_omem_alloc);
289-
kfree_rcu(mc_lst, rcu);
296+
__ipv6_sock_mc_drop(sk, mc_lst);
290297
return 0;
291298
}
292299
}

0 commit comments

Comments
 (0)