@@ -296,7 +296,8 @@ int __ipv6_dev_ac_inc(struct inet6_dev *idev, const struct in6_addr *addr)
296
296
goto out ;
297
297
}
298
298
299
- for (aca = idev -> ac_list ; aca ; aca = aca -> aca_next ) {
299
+ for (aca = rtnl_dereference (idev -> ac_list ); aca ;
300
+ aca = rtnl_dereference (aca -> aca_next )) {
300
301
if (ipv6_addr_equal (& aca -> aca_addr , addr )) {
301
302
aca -> aca_users ++ ;
302
303
err = 0 ;
@@ -317,13 +318,13 @@ int __ipv6_dev_ac_inc(struct inet6_dev *idev, const struct in6_addr *addr)
317
318
goto out ;
318
319
}
319
320
320
- aca -> aca_next = idev -> ac_list ;
321
- idev -> ac_list = aca ;
322
-
323
321
/* Hold this for addrconf_join_solict() below before we unlock,
324
322
* it is already exposed via idev->ac_list.
325
323
*/
326
324
aca_get (aca );
325
+ aca -> aca_next = idev -> ac_list ;
326
+ rcu_assign_pointer (idev -> ac_list , aca );
327
+
327
328
write_unlock_bh (& idev -> lock );
328
329
329
330
ipv6_add_acaddr_hash (net , aca );
@@ -350,7 +351,8 @@ int __ipv6_dev_ac_dec(struct inet6_dev *idev, const struct in6_addr *addr)
350
351
351
352
write_lock_bh (& idev -> lock );
352
353
prev_aca = NULL ;
353
- for (aca = idev -> ac_list ; aca ; aca = aca -> aca_next ) {
354
+ for (aca = rtnl_dereference (idev -> ac_list ); aca ;
355
+ aca = rtnl_dereference (aca -> aca_next )) {
354
356
if (ipv6_addr_equal (& aca -> aca_addr , addr ))
355
357
break ;
356
358
prev_aca = aca ;
@@ -364,9 +366,9 @@ int __ipv6_dev_ac_dec(struct inet6_dev *idev, const struct in6_addr *addr)
364
366
return 0 ;
365
367
}
366
368
if (prev_aca )
367
- prev_aca -> aca_next = aca -> aca_next ;
369
+ rcu_assign_pointer ( prev_aca -> aca_next , aca -> aca_next ) ;
368
370
else
369
- idev -> ac_list = aca -> aca_next ;
371
+ rcu_assign_pointer ( idev -> ac_list , aca -> aca_next ) ;
370
372
write_unlock_bh (& idev -> lock );
371
373
ipv6_del_acaddr_hash (aca );
372
374
addrconf_leave_solict (idev , & aca -> aca_addr );
@@ -392,8 +394,8 @@ void ipv6_ac_destroy_dev(struct inet6_dev *idev)
392
394
struct ifacaddr6 * aca ;
393
395
394
396
write_lock_bh (& idev -> lock );
395
- while ((aca = idev -> ac_list ) != NULL ) {
396
- idev -> ac_list = aca -> aca_next ;
397
+ while ((aca = rtnl_dereference ( idev -> ac_list ) ) != NULL ) {
398
+ rcu_assign_pointer ( idev -> ac_list , aca -> aca_next ) ;
397
399
write_unlock_bh (& idev -> lock );
398
400
399
401
ipv6_del_acaddr_hash (aca );
@@ -420,11 +422,10 @@ static bool ipv6_chk_acast_dev(struct net_device *dev, const struct in6_addr *ad
420
422
421
423
idev = __in6_dev_get (dev );
422
424
if (idev ) {
423
- read_lock_bh ( & idev -> lock ) ;
424
- for ( aca = idev -> ac_list ; aca ; aca = aca -> aca_next )
425
+ for ( aca = rcu_dereference ( idev -> ac_list ); aca ;
426
+ aca = rcu_dereference ( aca -> aca_next ) )
425
427
if (ipv6_addr_equal (& aca -> aca_addr , addr ))
426
428
break ;
427
- read_unlock_bh (& idev -> lock );
428
429
return aca != NULL ;
429
430
}
430
431
return false;
@@ -477,53 +478,43 @@ bool ipv6_chk_acast_addr_src(struct net *net, struct net_device *dev,
477
478
struct ac6_iter_state {
478
479
struct seq_net_private p ;
479
480
struct net_device * dev ;
480
- struct inet6_dev * idev ;
481
481
};
482
482
483
483
#define ac6_seq_private (seq ) ((struct ac6_iter_state *)(seq)->private)
484
484
485
485
static inline struct ifacaddr6 * ac6_get_first (struct seq_file * seq )
486
486
{
487
- struct ifacaddr6 * im = NULL ;
488
487
struct ac6_iter_state * state = ac6_seq_private (seq );
489
488
struct net * net = seq_file_net (seq );
489
+ struct ifacaddr6 * im = NULL ;
490
490
491
- state -> idev = NULL ;
492
491
for_each_netdev_rcu (net , state -> dev ) {
493
492
struct inet6_dev * idev ;
493
+
494
494
idev = __in6_dev_get (state -> dev );
495
495
if (!idev )
496
496
continue ;
497
- read_lock_bh (& idev -> lock );
498
- im = idev -> ac_list ;
499
- if (im ) {
500
- state -> idev = idev ;
497
+ im = rcu_dereference (idev -> ac_list );
498
+ if (im )
501
499
break ;
502
- }
503
- read_unlock_bh (& idev -> lock );
504
500
}
505
501
return im ;
506
502
}
507
503
508
504
static struct ifacaddr6 * ac6_get_next (struct seq_file * seq , struct ifacaddr6 * im )
509
505
{
510
506
struct ac6_iter_state * state = ac6_seq_private (seq );
507
+ struct inet6_dev * idev ;
511
508
512
- im = im -> aca_next ;
509
+ im = rcu_dereference ( im -> aca_next ) ;
513
510
while (!im ) {
514
- if (likely (state -> idev != NULL ))
515
- read_unlock_bh (& state -> idev -> lock );
516
-
517
511
state -> dev = next_net_device_rcu (state -> dev );
518
- if (!state -> dev ) {
519
- state -> idev = NULL ;
512
+ if (!state -> dev )
520
513
break ;
521
- }
522
- state -> idev = __in6_dev_get (state -> dev );
523
- if (!state -> idev )
514
+ idev = __in6_dev_get (state -> dev );
515
+ if (!idev )
524
516
continue ;
525
- read_lock_bh (& state -> idev -> lock );
526
- im = state -> idev -> ac_list ;
517
+ im = rcu_dereference (idev -> ac_list );
527
518
}
528
519
return im ;
529
520
}
@@ -555,12 +546,6 @@ static void *ac6_seq_next(struct seq_file *seq, void *v, loff_t *pos)
555
546
static void ac6_seq_stop (struct seq_file * seq , void * v )
556
547
__releases (RCU )
557
548
{
558
- struct ac6_iter_state * state = ac6_seq_private (seq );
559
-
560
- if (likely (state -> idev != NULL )) {
561
- read_unlock_bh (& state -> idev -> lock );
562
- state -> idev = NULL ;
563
- }
564
549
rcu_read_unlock ();
565
550
}
566
551
0 commit comments