@@ -127,7 +127,7 @@ static int ipv6_count_addresses(struct inet6_dev *idev);
127
127
* Configured unicast address hash table
128
128
*/
129
129
static struct hlist_head inet6_addr_lst [IN6_ADDR_HSIZE ];
130
- static DEFINE_RWLOCK (addrconf_hash_lock );
130
+ static DEFINE_SPINLOCK (addrconf_hash_lock );
131
131
132
132
static void addrconf_verify (unsigned long );
133
133
@@ -523,8 +523,13 @@ static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int old)
523
523
}
524
524
#endif
525
525
526
- /* Nobody refers to this ifaddr, destroy it */
526
+ static void inet6_ifa_finish_destroy_rcu (struct rcu_head * head )
527
+ {
528
+ struct inet6_ifaddr * ifp = container_of (head , struct inet6_ifaddr , rcu );
529
+ kfree (ifp );
530
+ }
527
531
532
+ /* Nobody refers to this ifaddr, destroy it */
528
533
void inet6_ifa_finish_destroy (struct inet6_ifaddr * ifp )
529
534
{
530
535
WARN_ON (ifp -> if_next != NULL );
@@ -545,7 +550,7 @@ void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp)
545
550
}
546
551
dst_release (& ifp -> rt -> u .dst );
547
552
548
- kfree ( ifp );
553
+ call_rcu ( & ifp -> rcu , inet6_ifa_finish_destroy_rcu );
549
554
}
550
555
551
556
static void
@@ -616,7 +621,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
616
621
goto out2 ;
617
622
}
618
623
619
- write_lock (& addrconf_hash_lock );
624
+ spin_lock (& addrconf_hash_lock );
620
625
621
626
/* Ignore adding duplicate addresses on an interface */
622
627
if (ipv6_chk_same_addr (dev_net (idev -> dev ), addr , idev -> dev )) {
@@ -670,9 +675,9 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
670
675
/* Add to big hash table */
671
676
hash = ipv6_addr_hash (addr );
672
677
673
- hlist_add_head (& ifa -> addr_lst , & inet6_addr_lst [hash ]);
678
+ hlist_add_head_rcu (& ifa -> addr_lst , & inet6_addr_lst [hash ]);
674
679
in6_ifa_hold (ifa );
675
- write_unlock (& addrconf_hash_lock );
680
+ spin_unlock (& addrconf_hash_lock );
676
681
677
682
write_lock (& idev -> lock );
678
683
/* Add to inet6_dev unicast addr list. */
@@ -699,7 +704,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
699
704
700
705
return ifa ;
701
706
out :
702
- write_unlock (& addrconf_hash_lock );
707
+ spin_unlock (& addrconf_hash_lock );
703
708
goto out2 ;
704
709
}
705
710
@@ -717,10 +722,10 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
717
722
718
723
ifp -> dead = 1 ;
719
724
720
- write_lock_bh (& addrconf_hash_lock );
721
- hlist_del_init (& ifp -> addr_lst );
725
+ spin_lock_bh (& addrconf_hash_lock );
726
+ hlist_del_init_rcu (& ifp -> addr_lst );
722
727
__in6_ifa_put (ifp );
723
- write_unlock_bh (& addrconf_hash_lock );
728
+ spin_unlock_bh (& addrconf_hash_lock );
724
729
725
730
write_lock_bh (& idev -> lock );
726
731
#ifdef CONFIG_IPV6_PRIVACY
@@ -1274,8 +1279,8 @@ int ipv6_chk_addr(struct net *net, struct in6_addr *addr,
1274
1279
struct hlist_node * node ;
1275
1280
u8 hash = ipv6_addr_hash (addr );
1276
1281
1277
- read_lock_bh ( & addrconf_hash_lock );
1278
- hlist_for_each_entry (ifp , node , & inet6_addr_lst [hash ], addr_lst ) {
1282
+ rcu_read_lock_bh ( );
1283
+ hlist_for_each_entry_rcu (ifp , node , & inet6_addr_lst [hash ], addr_lst ) {
1279
1284
if (!net_eq (dev_net (ifp -> idev -> dev ), net ))
1280
1285
continue ;
1281
1286
if (ipv6_addr_equal (& ifp -> addr , addr ) &&
@@ -1285,7 +1290,8 @@ int ipv6_chk_addr(struct net *net, struct in6_addr *addr,
1285
1290
break ;
1286
1291
}
1287
1292
}
1288
- read_unlock_bh (& addrconf_hash_lock );
1293
+ rcu_read_unlock_bh ();
1294
+
1289
1295
return ifp != NULL ;
1290
1296
}
1291
1297
EXPORT_SYMBOL (ipv6_chk_addr );
@@ -1341,8 +1347,8 @@ struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, const struct in6_addr *add
1341
1347
struct hlist_node * node ;
1342
1348
u8 hash = ipv6_addr_hash (addr );
1343
1349
1344
- read_lock_bh ( & addrconf_hash_lock );
1345
- hlist_for_each_entry (ifp , node , & inet6_addr_lst [hash ], addr_lst ) {
1350
+ rcu_read_lock_bh ( );
1351
+ hlist_for_each_entry_rcu (ifp , node , & inet6_addr_lst [hash ], addr_lst ) {
1346
1352
if (!net_eq (dev_net (ifp -> idev -> dev ), net ))
1347
1353
continue ;
1348
1354
if (ipv6_addr_equal (& ifp -> addr , addr )) {
@@ -1353,7 +1359,7 @@ struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, const struct in6_addr *add
1353
1359
}
1354
1360
}
1355
1361
}
1356
- read_unlock_bh ( & addrconf_hash_lock );
1362
+ rcu_read_unlock_bh ( );
1357
1363
1358
1364
return ifp ;
1359
1365
}
@@ -2698,10 +2704,10 @@ static int addrconf_ifdown(struct net_device *dev, int how)
2698
2704
write_unlock_bh (& idev -> lock );
2699
2705
2700
2706
/* clear hash table */
2701
- write_lock_bh (& addrconf_hash_lock );
2702
- hlist_del_init (& ifa -> addr_lst );
2707
+ spin_lock_bh (& addrconf_hash_lock );
2708
+ hlist_del_init_rcu (& ifa -> addr_lst );
2703
2709
__in6_ifa_put (ifa );
2704
- write_unlock_bh (& addrconf_hash_lock );
2710
+ spin_unlock_bh (& addrconf_hash_lock );
2705
2711
2706
2712
__ipv6_ifa_notify (RTM_DELADDR , ifa );
2707
2713
atomic_notifier_call_chain (& inet6addr_chain , NETDEV_DOWN , ifa );
@@ -2946,11 +2952,10 @@ static struct inet6_ifaddr *if6_get_first(struct seq_file *seq)
2946
2952
2947
2953
for (state -> bucket = 0 ; state -> bucket < IN6_ADDR_HSIZE ; ++ state -> bucket ) {
2948
2954
struct hlist_node * n ;
2949
- hlist_for_each_entry (ifa , n ,
2950
- & inet6_addr_lst [ state -> bucket ], addr_lst ) {
2955
+ hlist_for_each_entry_rcu (ifa , n , & inet6_addr_lst [ state -> bucket ] ,
2956
+ addr_lst )
2951
2957
if (net_eq (dev_net (ifa -> idev -> dev ), net ))
2952
2958
return ifa ;
2953
- }
2954
2959
}
2955
2960
return NULL ;
2956
2961
}
@@ -2962,10 +2967,9 @@ static struct inet6_ifaddr *if6_get_next(struct seq_file *seq,
2962
2967
struct net * net = seq_file_net (seq );
2963
2968
struct hlist_node * n = & ifa -> addr_lst ;
2964
2969
2965
- hlist_for_each_entry_continue (ifa , n , addr_lst ) {
2970
+ hlist_for_each_entry_continue_rcu (ifa , n , addr_lst )
2966
2971
if (net_eq (dev_net (ifa -> idev -> dev ), net ))
2967
2972
return ifa ;
2968
- }
2969
2973
2970
2974
while (++ state -> bucket < IN6_ADDR_HSIZE ) {
2971
2975
hlist_for_each_entry (ifa , n ,
@@ -2989,9 +2993,9 @@ static struct inet6_ifaddr *if6_get_idx(struct seq_file *seq, loff_t pos)
2989
2993
}
2990
2994
2991
2995
static void * if6_seq_start (struct seq_file * seq , loff_t * pos )
2992
- __acquires (addrconf_hash_lock )
2996
+ __acquires (rcu )
2993
2997
{
2994
- read_lock_bh ( & addrconf_hash_lock );
2998
+ rcu_read_lock_bh ( );
2995
2999
return if6_get_idx (seq , * pos );
2996
3000
}
2997
3001
@@ -3005,9 +3009,9 @@ static void *if6_seq_next(struct seq_file *seq, void *v, loff_t *pos)
3005
3009
}
3006
3010
3007
3011
static void if6_seq_stop (struct seq_file * seq , void * v )
3008
- __releases (addrconf_hash_lock )
3012
+ __releases (rcu )
3009
3013
{
3010
- read_unlock_bh ( & addrconf_hash_lock );
3014
+ rcu_read_unlock_bh ( );
3011
3015
}
3012
3016
3013
3017
static int if6_seq_show (struct seq_file * seq , void * v )
@@ -3081,8 +3085,8 @@ int ipv6_chk_home_addr(struct net *net, struct in6_addr *addr)
3081
3085
struct hlist_node * n ;
3082
3086
u8 hash = ipv6_addr_hash (addr );
3083
3087
3084
- read_lock_bh ( & addrconf_hash_lock );
3085
- hlist_for_each_entry (ifp , n , & inet6_addr_lst [hash ], addr_lst ) {
3088
+ rcu_read_lock_bh ( );
3089
+ hlist_for_each_entry_rcu (ifp , n , & inet6_addr_lst [hash ], addr_lst ) {
3086
3090
if (!net_eq (dev_net (ifp -> idev -> dev ), net ))
3087
3091
continue ;
3088
3092
if (ipv6_addr_equal (& ifp -> addr , addr ) &&
@@ -3091,7 +3095,7 @@ int ipv6_chk_home_addr(struct net *net, struct in6_addr *addr)
3091
3095
break ;
3092
3096
}
3093
3097
}
3094
- read_unlock_bh ( & addrconf_hash_lock );
3098
+ rcu_read_unlock_bh ( );
3095
3099
return ret ;
3096
3100
}
3097
3101
#endif
@@ -3107,7 +3111,8 @@ static void addrconf_verify(unsigned long foo)
3107
3111
unsigned long now , next ;
3108
3112
int i ;
3109
3113
3110
- spin_lock_bh (& addrconf_verify_lock );
3114
+ rcu_read_lock_bh ();
3115
+ spin_lock (& addrconf_verify_lock );
3111
3116
now = jiffies ;
3112
3117
next = now + ADDR_CHECK_FREQUENCY ;
3113
3118
@@ -3116,8 +3121,8 @@ static void addrconf_verify(unsigned long foo)
3116
3121
for (i = 0 ; i < IN6_ADDR_HSIZE ; i ++ ) {
3117
3122
3118
3123
restart :
3119
- read_lock ( & addrconf_hash_lock );
3120
- hlist_for_each_entry ( ifp , node , & inet6_addr_lst [i ], addr_lst ) {
3124
+ hlist_for_each_entry_rcu ( ifp , node ,
3125
+ & inet6_addr_lst [i ], addr_lst ) {
3121
3126
unsigned long age ;
3122
3127
#ifdef CONFIG_IPV6_PRIVACY
3123
3128
unsigned long regen_advance ;
@@ -3139,7 +3144,6 @@ static void addrconf_verify(unsigned long foo)
3139
3144
age >= ifp -> valid_lft ) {
3140
3145
spin_unlock (& ifp -> lock );
3141
3146
in6_ifa_hold (ifp );
3142
- read_unlock (& addrconf_hash_lock );
3143
3147
ipv6_del_addr (ifp );
3144
3148
goto restart ;
3145
3149
} else if (ifp -> prefered_lft == INFINITY_LIFE_TIME ) {
@@ -3161,7 +3165,6 @@ static void addrconf_verify(unsigned long foo)
3161
3165
3162
3166
if (deprecate ) {
3163
3167
in6_ifa_hold (ifp );
3164
- read_unlock (& addrconf_hash_lock );
3165
3168
3166
3169
ipv6_ifa_notify (0 , ifp );
3167
3170
in6_ifa_put (ifp );
@@ -3179,7 +3182,7 @@ static void addrconf_verify(unsigned long foo)
3179
3182
in6_ifa_hold (ifp );
3180
3183
in6_ifa_hold (ifpub );
3181
3184
spin_unlock (& ifp -> lock );
3182
- read_unlock ( & addrconf_hash_lock );
3185
+
3183
3186
spin_lock (& ifpub -> lock );
3184
3187
ifpub -> regen_count = 0 ;
3185
3188
spin_unlock (& ifpub -> lock );
@@ -3199,12 +3202,12 @@ static void addrconf_verify(unsigned long foo)
3199
3202
spin_unlock (& ifp -> lock );
3200
3203
}
3201
3204
}
3202
- read_unlock (& addrconf_hash_lock );
3203
3205
}
3204
3206
3205
3207
addr_chk_timer .expires = time_before (next , jiffies + HZ ) ? jiffies + HZ : next ;
3206
3208
add_timer (& addr_chk_timer );
3207
- spin_unlock_bh (& addrconf_verify_lock );
3209
+ spin_unlock (& addrconf_verify_lock );
3210
+ rcu_read_unlock_bh ();
3208
3211
}
3209
3212
3210
3213
static struct in6_addr * extract_addr (struct nlattr * addr , struct nlattr * local )
@@ -4621,10 +4624,10 @@ void addrconf_cleanup(void)
4621
4624
/*
4622
4625
* Check hash table.
4623
4626
*/
4624
- write_lock_bh (& addrconf_hash_lock );
4627
+ spin_lock_bh (& addrconf_hash_lock );
4625
4628
for (i = 0 ; i < IN6_ADDR_HSIZE ; i ++ )
4626
4629
WARN_ON (!hlist_empty (& inet6_addr_lst [i ]));
4627
- write_unlock_bh (& addrconf_hash_lock );
4630
+ spin_unlock_bh (& addrconf_hash_lock );
4628
4631
4629
4632
del_timer (& addr_chk_timer );
4630
4633
rtnl_unlock ();
0 commit comments