@@ -127,7 +127,7 @@ static int ipv6_count_addresses(struct inet6_dev *idev);
127127 * Configured unicast address hash table
128128 */
129129static struct hlist_head inet6_addr_lst [IN6_ADDR_HSIZE ];
130- static DEFINE_RWLOCK (addrconf_hash_lock );
130+ static DEFINE_SPINLOCK (addrconf_hash_lock );
131131
132132static void addrconf_verify (unsigned long );
133133
@@ -523,8 +523,13 @@ static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int old)
523523}
524524#endif
525525
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+ }
527531
532+ /* Nobody refers to this ifaddr, destroy it */
528533void inet6_ifa_finish_destroy (struct inet6_ifaddr * ifp )
529534{
530535 WARN_ON (ifp -> if_next != NULL );
@@ -545,7 +550,7 @@ void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp)
545550 }
546551 dst_release (& ifp -> rt -> u .dst );
547552
548- kfree ( ifp );
553+ call_rcu ( & ifp -> rcu , inet6_ifa_finish_destroy_rcu );
549554}
550555
551556static void
@@ -616,7 +621,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
616621 goto out2 ;
617622 }
618623
619- write_lock (& addrconf_hash_lock );
624+ spin_lock (& addrconf_hash_lock );
620625
621626 /* Ignore adding duplicate addresses on an interface */
622627 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,
670675 /* Add to big hash table */
671676 hash = ipv6_addr_hash (addr );
672677
673- hlist_add_head (& ifa -> addr_lst , & inet6_addr_lst [hash ]);
678+ hlist_add_head_rcu (& ifa -> addr_lst , & inet6_addr_lst [hash ]);
674679 in6_ifa_hold (ifa );
675- write_unlock (& addrconf_hash_lock );
680+ spin_unlock (& addrconf_hash_lock );
676681
677682 write_lock (& idev -> lock );
678683 /* 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,
699704
700705 return ifa ;
701706out :
702- write_unlock (& addrconf_hash_lock );
707+ spin_unlock (& addrconf_hash_lock );
703708 goto out2 ;
704709}
705710
@@ -717,10 +722,10 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
717722
718723 ifp -> dead = 1 ;
719724
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 );
722727 __in6_ifa_put (ifp );
723- write_unlock_bh (& addrconf_hash_lock );
728+ spin_unlock_bh (& addrconf_hash_lock );
724729
725730 write_lock_bh (& idev -> lock );
726731#ifdef CONFIG_IPV6_PRIVACY
@@ -1274,8 +1279,8 @@ int ipv6_chk_addr(struct net *net, struct in6_addr *addr,
12741279 struct hlist_node * node ;
12751280 u8 hash = ipv6_addr_hash (addr );
12761281
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 ) {
12791284 if (!net_eq (dev_net (ifp -> idev -> dev ), net ))
12801285 continue ;
12811286 if (ipv6_addr_equal (& ifp -> addr , addr ) &&
@@ -1285,7 +1290,8 @@ int ipv6_chk_addr(struct net *net, struct in6_addr *addr,
12851290 break ;
12861291 }
12871292 }
1288- read_unlock_bh (& addrconf_hash_lock );
1293+ rcu_read_unlock_bh ();
1294+
12891295 return ifp != NULL ;
12901296}
12911297EXPORT_SYMBOL (ipv6_chk_addr );
@@ -1341,8 +1347,8 @@ struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, const struct in6_addr *add
13411347 struct hlist_node * node ;
13421348 u8 hash = ipv6_addr_hash (addr );
13431349
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 ) {
13461352 if (!net_eq (dev_net (ifp -> idev -> dev ), net ))
13471353 continue ;
13481354 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
13531359 }
13541360 }
13551361 }
1356- read_unlock_bh ( & addrconf_hash_lock );
1362+ rcu_read_unlock_bh ( );
13571363
13581364 return ifp ;
13591365}
@@ -2698,10 +2704,10 @@ static int addrconf_ifdown(struct net_device *dev, int how)
26982704 write_unlock_bh (& idev -> lock );
26992705
27002706 /* 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 );
27032709 __in6_ifa_put (ifa );
2704- write_unlock_bh (& addrconf_hash_lock );
2710+ spin_unlock_bh (& addrconf_hash_lock );
27052711
27062712 __ipv6_ifa_notify (RTM_DELADDR , ifa );
27072713 atomic_notifier_call_chain (& inet6addr_chain , NETDEV_DOWN , ifa );
@@ -2946,11 +2952,10 @@ static struct inet6_ifaddr *if6_get_first(struct seq_file *seq)
29462952
29472953 for (state -> bucket = 0 ; state -> bucket < IN6_ADDR_HSIZE ; ++ state -> bucket ) {
29482954 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 )
29512957 if (net_eq (dev_net (ifa -> idev -> dev ), net ))
29522958 return ifa ;
2953- }
29542959 }
29552960 return NULL ;
29562961}
@@ -2962,10 +2967,9 @@ static struct inet6_ifaddr *if6_get_next(struct seq_file *seq,
29622967 struct net * net = seq_file_net (seq );
29632968 struct hlist_node * n = & ifa -> addr_lst ;
29642969
2965- hlist_for_each_entry_continue (ifa , n , addr_lst ) {
2970+ hlist_for_each_entry_continue_rcu (ifa , n , addr_lst )
29662971 if (net_eq (dev_net (ifa -> idev -> dev ), net ))
29672972 return ifa ;
2968- }
29692973
29702974 while (++ state -> bucket < IN6_ADDR_HSIZE ) {
29712975 hlist_for_each_entry (ifa , n ,
@@ -2989,9 +2993,9 @@ static struct inet6_ifaddr *if6_get_idx(struct seq_file *seq, loff_t pos)
29892993}
29902994
29912995static void * if6_seq_start (struct seq_file * seq , loff_t * pos )
2992- __acquires (addrconf_hash_lock )
2996+ __acquires (rcu )
29932997{
2994- read_lock_bh ( & addrconf_hash_lock );
2998+ rcu_read_lock_bh ( );
29952999 return if6_get_idx (seq , * pos );
29963000}
29973001
@@ -3005,9 +3009,9 @@ static void *if6_seq_next(struct seq_file *seq, void *v, loff_t *pos)
30053009}
30063010
30073011static void if6_seq_stop (struct seq_file * seq , void * v )
3008- __releases (addrconf_hash_lock )
3012+ __releases (rcu )
30093013{
3010- read_unlock_bh ( & addrconf_hash_lock );
3014+ rcu_read_unlock_bh ( );
30113015}
30123016
30133017static 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)
30813085 struct hlist_node * n ;
30823086 u8 hash = ipv6_addr_hash (addr );
30833087
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 ) {
30863090 if (!net_eq (dev_net (ifp -> idev -> dev ), net ))
30873091 continue ;
30883092 if (ipv6_addr_equal (& ifp -> addr , addr ) &&
@@ -3091,7 +3095,7 @@ int ipv6_chk_home_addr(struct net *net, struct in6_addr *addr)
30913095 break ;
30923096 }
30933097 }
3094- read_unlock_bh ( & addrconf_hash_lock );
3098+ rcu_read_unlock_bh ( );
30953099 return ret ;
30963100}
30973101#endif
@@ -3107,7 +3111,8 @@ static void addrconf_verify(unsigned long foo)
31073111 unsigned long now , next ;
31083112 int i ;
31093113
3110- spin_lock_bh (& addrconf_verify_lock );
3114+ rcu_read_lock_bh ();
3115+ spin_lock (& addrconf_verify_lock );
31113116 now = jiffies ;
31123117 next = now + ADDR_CHECK_FREQUENCY ;
31133118
@@ -3116,8 +3121,8 @@ static void addrconf_verify(unsigned long foo)
31163121 for (i = 0 ; i < IN6_ADDR_HSIZE ; i ++ ) {
31173122
31183123restart :
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 ) {
31213126 unsigned long age ;
31223127#ifdef CONFIG_IPV6_PRIVACY
31233128 unsigned long regen_advance ;
@@ -3139,7 +3144,6 @@ static void addrconf_verify(unsigned long foo)
31393144 age >= ifp -> valid_lft ) {
31403145 spin_unlock (& ifp -> lock );
31413146 in6_ifa_hold (ifp );
3142- read_unlock (& addrconf_hash_lock );
31433147 ipv6_del_addr (ifp );
31443148 goto restart ;
31453149 } else if (ifp -> prefered_lft == INFINITY_LIFE_TIME ) {
@@ -3161,7 +3165,6 @@ static void addrconf_verify(unsigned long foo)
31613165
31623166 if (deprecate ) {
31633167 in6_ifa_hold (ifp );
3164- read_unlock (& addrconf_hash_lock );
31653168
31663169 ipv6_ifa_notify (0 , ifp );
31673170 in6_ifa_put (ifp );
@@ -3179,7 +3182,7 @@ static void addrconf_verify(unsigned long foo)
31793182 in6_ifa_hold (ifp );
31803183 in6_ifa_hold (ifpub );
31813184 spin_unlock (& ifp -> lock );
3182- read_unlock ( & addrconf_hash_lock );
3185+
31833186 spin_lock (& ifpub -> lock );
31843187 ifpub -> regen_count = 0 ;
31853188 spin_unlock (& ifpub -> lock );
@@ -3199,12 +3202,12 @@ static void addrconf_verify(unsigned long foo)
31993202 spin_unlock (& ifp -> lock );
32003203 }
32013204 }
3202- read_unlock (& addrconf_hash_lock );
32033205 }
32043206
32053207 addr_chk_timer .expires = time_before (next , jiffies + HZ ) ? jiffies + HZ : next ;
32063208 add_timer (& addr_chk_timer );
3207- spin_unlock_bh (& addrconf_verify_lock );
3209+ spin_unlock (& addrconf_verify_lock );
3210+ rcu_read_unlock_bh ();
32083211}
32093212
32103213static struct in6_addr * extract_addr (struct nlattr * addr , struct nlattr * local )
@@ -4621,10 +4624,10 @@ void addrconf_cleanup(void)
46214624 /*
46224625 * Check hash table.
46234626 */
4624- write_lock_bh (& addrconf_hash_lock );
4627+ spin_lock_bh (& addrconf_hash_lock );
46254628 for (i = 0 ; i < IN6_ADDR_HSIZE ; i ++ )
46264629 WARN_ON (!hlist_empty (& inet6_addr_lst [i ]));
4627- write_unlock_bh (& addrconf_hash_lock );
4630+ spin_unlock_bh (& addrconf_hash_lock );
46284631
46294632 del_timer (& addr_chk_timer );
46304633 rtnl_unlock ();
0 commit comments