Skip to content

Commit 882ba1f

Browse files
TaeheeYoodavem330
authored andcommitted
mld: convert ipv6_mc_socklist->sflist to RCU
The sflist has been protected by rwlock so that the critical section is atomic context. In order to switch this context, changing locking is needed. The sflist 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 <[email protected]> Signed-off-by: Taehee Yoo <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent cf2ce33 commit 882ba1f

File tree

2 files changed

+24
-32
lines changed

2 files changed

+24
-32
lines changed

include/net/if_inet6.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ struct inet6_ifaddr {
7878
struct ip6_sf_socklist {
7979
unsigned int sl_max;
8080
unsigned int sl_count;
81+
struct rcu_head rcu;
8182
struct in6_addr sl_addr[];
8283
};
8384

@@ -91,8 +92,7 @@ struct ipv6_mc_socklist {
9192
int ifindex;
9293
unsigned int sfmode; /* MCAST_{INCLUDE,EXCLUDE} */
9394
struct ipv6_mc_socklist __rcu *next;
94-
rwlock_t sflock;
95-
struct ip6_sf_socklist *sflist;
95+
struct ip6_sf_socklist __rcu *sflist;
9696
struct rcu_head rcu;
9797
};
9898

net/ipv6/mcast.c

Lines changed: 22 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -178,8 +178,7 @@ static int __ipv6_sock_mc_join(struct sock *sk, int ifindex,
178178

179179
mc_lst->ifindex = dev->ifindex;
180180
mc_lst->sfmode = mode;
181-
rwlock_init(&mc_lst->sflock);
182-
mc_lst->sflist = NULL;
181+
RCU_INIT_POINTER(mc_lst->sflist, NULL);
183182

184183
/*
185184
* now add/increase the group membership on the device
@@ -335,7 +334,6 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
335334
struct net *net = sock_net(sk);
336335
int i, j, rv;
337336
int leavegroup = 0;
338-
int pmclocked = 0;
339337
int err;
340338

341339
source = &((struct sockaddr_in6 *)&pgsr->gsr_source)->sin6_addr;
@@ -364,7 +362,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
364362
goto done;
365363
}
366364
/* if a source filter was set, must be the same mode as before */
367-
if (pmc->sflist) {
365+
if (rcu_access_pointer(pmc->sflist)) {
368366
if (pmc->sfmode != omode) {
369367
err = -EINVAL;
370368
goto done;
@@ -376,10 +374,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
376374
pmc->sfmode = omode;
377375
}
378376

379-
write_lock(&pmc->sflock);
380-
pmclocked = 1;
381-
382-
psl = pmc->sflist;
377+
psl = rtnl_dereference(pmc->sflist);
383378
if (!add) {
384379
if (!psl)
385380
goto done; /* err = -EADDRNOTAVAIL */
@@ -429,9 +424,11 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
429424
if (psl) {
430425
for (i = 0; i < psl->sl_count; i++)
431426
newpsl->sl_addr[i] = psl->sl_addr[i];
432-
sock_kfree_s(sk, psl, IP6_SFLSIZE(psl->sl_max));
427+
atomic_sub(IP6_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc);
428+
kfree_rcu(psl, rcu);
433429
}
434-
pmc->sflist = psl = newpsl;
430+
psl = newpsl;
431+
rcu_assign_pointer(pmc->sflist, psl);
435432
}
436433
rv = 1; /* > 0 for insert logic below if sl_count is 0 */
437434
for (i = 0; i < psl->sl_count; i++) {
@@ -447,8 +444,6 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
447444
/* update the interface list */
448445
ip6_mc_add_src(idev, group, omode, 1, source, 1);
449446
done:
450-
if (pmclocked)
451-
write_unlock(&pmc->sflock);
452447
read_unlock_bh(&idev->lock);
453448
rcu_read_unlock();
454449
if (leavegroup)
@@ -526,17 +521,16 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf,
526521
(void) ip6_mc_add_src(idev, group, gsf->gf_fmode, 0, NULL, 0);
527522
}
528523

529-
write_lock(&pmc->sflock);
530-
psl = pmc->sflist;
524+
psl = rtnl_dereference(pmc->sflist);
531525
if (psl) {
532526
(void) ip6_mc_del_src(idev, group, pmc->sfmode,
533527
psl->sl_count, psl->sl_addr, 0);
534-
sock_kfree_s(sk, psl, IP6_SFLSIZE(psl->sl_max));
528+
atomic_sub(IP6_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc);
529+
kfree_rcu(psl, rcu);
535530
} else
536531
(void) ip6_mc_del_src(idev, group, pmc->sfmode, 0, NULL, 0);
537-
pmc->sflist = newpsl;
532+
rcu_assign_pointer(pmc->sflist, newpsl);
538533
pmc->sfmode = gsf->gf_fmode;
539-
write_unlock(&pmc->sflock);
540534
err = 0;
541535
done:
542536
read_unlock_bh(&idev->lock);
@@ -585,16 +579,14 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
585579
if (!pmc) /* must have a prior join */
586580
goto done;
587581
gsf->gf_fmode = pmc->sfmode;
588-
psl = pmc->sflist;
582+
psl = rtnl_dereference(pmc->sflist);
589583
count = psl ? psl->sl_count : 0;
590584
read_unlock_bh(&idev->lock);
591585
rcu_read_unlock();
592586

593587
copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc;
594588
gsf->gf_numsrc = count;
595-
/* changes to psl require the socket lock, and a write lock
596-
* on pmc->sflock. We have the socket lock so reading here is safe.
597-
*/
589+
598590
for (i = 0; i < copycount; i++, p++) {
599591
struct sockaddr_in6 *psin6;
600592
struct sockaddr_storage ss;
@@ -630,8 +622,7 @@ bool inet6_mc_check(struct sock *sk, const struct in6_addr *mc_addr,
630622
rcu_read_unlock();
631623
return np->mc_all;
632624
}
633-
read_lock(&mc->sflock);
634-
psl = mc->sflist;
625+
psl = rcu_dereference(mc->sflist);
635626
if (!psl) {
636627
rv = mc->sfmode == MCAST_EXCLUDE;
637628
} else {
@@ -646,7 +637,6 @@ bool inet6_mc_check(struct sock *sk, const struct in6_addr *mc_addr,
646637
if (mc->sfmode == MCAST_EXCLUDE && i < psl->sl_count)
647638
rv = false;
648639
}
649-
read_unlock(&mc->sflock);
650640
rcu_read_unlock();
651641

652642
return rv;
@@ -2422,19 +2412,21 @@ static void igmp6_join_group(struct ifmcaddr6 *ma)
24222412
static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml,
24232413
struct inet6_dev *idev)
24242414
{
2415+
struct ip6_sf_socklist *psl;
24252416
int err;
24262417

2427-
write_lock_bh(&iml->sflock);
2428-
if (!iml->sflist) {
2418+
psl = rtnl_dereference(iml->sflist);
2419+
2420+
if (!psl) {
24292421
/* any-source empty exclude case */
24302422
err = ip6_mc_del_src(idev, &iml->addr, iml->sfmode, 0, NULL, 0);
24312423
} else {
24322424
err = ip6_mc_del_src(idev, &iml->addr, iml->sfmode,
2433-
iml->sflist->sl_count, iml->sflist->sl_addr, 0);
2434-
sock_kfree_s(sk, iml->sflist, IP6_SFLSIZE(iml->sflist->sl_max));
2435-
iml->sflist = NULL;
2425+
psl->sl_count, psl->sl_addr, 0);
2426+
RCU_INIT_POINTER(iml->sflist, NULL);
2427+
atomic_sub(IP6_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc);
2428+
kfree_rcu(psl, rcu);
24362429
}
2437-
write_unlock_bh(&iml->sflock);
24382430
return err;
24392431
}
24402432

0 commit comments

Comments
 (0)