@@ -178,8 +178,7 @@ static int __ipv6_sock_mc_join(struct sock *sk, int ifindex,
178
178
179
179
mc_lst -> ifindex = dev -> ifindex ;
180
180
mc_lst -> sfmode = mode ;
181
- rwlock_init (& mc_lst -> sflock );
182
- mc_lst -> sflist = NULL ;
181
+ RCU_INIT_POINTER (mc_lst -> sflist , NULL );
183
182
184
183
/*
185
184
* now add/increase the group membership on the device
@@ -335,7 +334,6 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
335
334
struct net * net = sock_net (sk );
336
335
int i , j , rv ;
337
336
int leavegroup = 0 ;
338
- int pmclocked = 0 ;
339
337
int err ;
340
338
341
339
source = & ((struct sockaddr_in6 * )& pgsr -> gsr_source )-> sin6_addr ;
@@ -364,7 +362,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
364
362
goto done ;
365
363
}
366
364
/* if a source filter was set, must be the same mode as before */
367
- if (pmc -> sflist ) {
365
+ if (rcu_access_pointer ( pmc -> sflist ) ) {
368
366
if (pmc -> sfmode != omode ) {
369
367
err = - EINVAL ;
370
368
goto done ;
@@ -376,10 +374,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
376
374
pmc -> sfmode = omode ;
377
375
}
378
376
379
- write_lock (& pmc -> sflock );
380
- pmclocked = 1 ;
381
-
382
- psl = pmc -> sflist ;
377
+ psl = rtnl_dereference (pmc -> sflist );
383
378
if (!add ) {
384
379
if (!psl )
385
380
goto done ; /* err = -EADDRNOTAVAIL */
@@ -429,9 +424,11 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
429
424
if (psl ) {
430
425
for (i = 0 ; i < psl -> sl_count ; i ++ )
431
426
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 );
433
429
}
434
- pmc -> sflist = psl = newpsl ;
430
+ psl = newpsl ;
431
+ rcu_assign_pointer (pmc -> sflist , psl );
435
432
}
436
433
rv = 1 ; /* > 0 for insert logic below if sl_count is 0 */
437
434
for (i = 0 ; i < psl -> sl_count ; i ++ ) {
@@ -447,8 +444,6 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
447
444
/* update the interface list */
448
445
ip6_mc_add_src (idev , group , omode , 1 , source , 1 );
449
446
done :
450
- if (pmclocked )
451
- write_unlock (& pmc -> sflock );
452
447
read_unlock_bh (& idev -> lock );
453
448
rcu_read_unlock ();
454
449
if (leavegroup )
@@ -526,17 +521,16 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf,
526
521
(void ) ip6_mc_add_src (idev , group , gsf -> gf_fmode , 0 , NULL , 0 );
527
522
}
528
523
529
- write_lock (& pmc -> sflock );
530
- psl = pmc -> sflist ;
524
+ psl = rtnl_dereference (pmc -> sflist );
531
525
if (psl ) {
532
526
(void ) ip6_mc_del_src (idev , group , pmc -> sfmode ,
533
527
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 );
535
530
} else
536
531
(void ) ip6_mc_del_src (idev , group , pmc -> sfmode , 0 , NULL , 0 );
537
- pmc -> sflist = newpsl ;
532
+ rcu_assign_pointer ( pmc -> sflist , newpsl ) ;
538
533
pmc -> sfmode = gsf -> gf_fmode ;
539
- write_unlock (& pmc -> sflock );
540
534
err = 0 ;
541
535
done :
542
536
read_unlock_bh (& idev -> lock );
@@ -585,16 +579,14 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
585
579
if (!pmc ) /* must have a prior join */
586
580
goto done ;
587
581
gsf -> gf_fmode = pmc -> sfmode ;
588
- psl = pmc -> sflist ;
582
+ psl = rtnl_dereference ( pmc -> sflist ) ;
589
583
count = psl ? psl -> sl_count : 0 ;
590
584
read_unlock_bh (& idev -> lock );
591
585
rcu_read_unlock ();
592
586
593
587
copycount = count < gsf -> gf_numsrc ? count : gsf -> gf_numsrc ;
594
588
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
+
598
590
for (i = 0 ; i < copycount ; i ++ , p ++ ) {
599
591
struct sockaddr_in6 * psin6 ;
600
592
struct sockaddr_storage ss ;
@@ -630,8 +622,7 @@ bool inet6_mc_check(struct sock *sk, const struct in6_addr *mc_addr,
630
622
rcu_read_unlock ();
631
623
return np -> mc_all ;
632
624
}
633
- read_lock (& mc -> sflock );
634
- psl = mc -> sflist ;
625
+ psl = rcu_dereference (mc -> sflist );
635
626
if (!psl ) {
636
627
rv = mc -> sfmode == MCAST_EXCLUDE ;
637
628
} else {
@@ -646,7 +637,6 @@ bool inet6_mc_check(struct sock *sk, const struct in6_addr *mc_addr,
646
637
if (mc -> sfmode == MCAST_EXCLUDE && i < psl -> sl_count )
647
638
rv = false;
648
639
}
649
- read_unlock (& mc -> sflock );
650
640
rcu_read_unlock ();
651
641
652
642
return rv ;
@@ -2422,19 +2412,21 @@ static void igmp6_join_group(struct ifmcaddr6 *ma)
2422
2412
static int ip6_mc_leave_src (struct sock * sk , struct ipv6_mc_socklist * iml ,
2423
2413
struct inet6_dev * idev )
2424
2414
{
2415
+ struct ip6_sf_socklist * psl ;
2425
2416
int err ;
2426
2417
2427
- write_lock_bh (& iml -> sflock );
2428
- if (!iml -> sflist ) {
2418
+ psl = rtnl_dereference (iml -> sflist );
2419
+
2420
+ if (!psl ) {
2429
2421
/* any-source empty exclude case */
2430
2422
err = ip6_mc_del_src (idev , & iml -> addr , iml -> sfmode , 0 , NULL , 0 );
2431
2423
} else {
2432
2424
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 );
2436
2429
}
2437
- write_unlock_bh (& iml -> sflock );
2438
2430
return err ;
2439
2431
}
2440
2432
0 commit comments