@@ -576,7 +576,7 @@ static struct sock *udp4_lib_lookup4(const struct net *net,
576576 return NULL ;
577577}
578578
579- /* In hash4, rehash can happen in connect(), where hash4_cnt keeps unchanged . */
579+ /* udp_rehash4() only checks hslot4, and hash4_cnt is not processed . */
580580static void udp_rehash4 (struct udp_table * udptable , struct sock * sk ,
581581 u16 newhash4 )
582582{
@@ -625,15 +625,13 @@ void udp_lib_hash4(struct sock *sk, u16 hash)
625625 struct net * net = sock_net (sk );
626626 struct udp_table * udptable ;
627627
628- /* Connected udp socket can re-connect to another remote address,
629- * so rehash4 is needed .
628+ /* Connected udp socket can re-connect to another remote address, which
629+ * will be handled by rehash. Thus no need to redo hash4 here .
630630 */
631- udptable = net -> ipv4 .udp_table ;
632- if (udp_hashed4 (sk )) {
633- udp_rehash4 (udptable , sk , hash );
631+ if (udp_hashed4 (sk ))
634632 return ;
635- }
636633
634+ udptable = net -> ipv4 .udp_table ;
637635 hslot = udp_hashslot (udptable , net , udp_sk (sk )-> udp_port_hash );
638636 hslot2 = udp_hashslot2 (udptable , udp_sk (sk )-> udp_portaddr_hash );
639637 hslot4 = udp_hashslot4 (udptable , hash );
@@ -2229,14 +2227,14 @@ void udp_lib_rehash(struct sock *sk, u16 newhash, u16 newhash4)
22292227 struct udp_table * udptable = udp_get_table_prot (sk );
22302228 struct udp_hslot * hslot , * hslot2 , * nhslot2 ;
22312229
2230+ hslot = udp_hashslot (udptable , sock_net (sk ),
2231+ udp_sk (sk )-> udp_port_hash );
22322232 hslot2 = udp_hashslot2 (udptable , udp_sk (sk )-> udp_portaddr_hash );
22332233 nhslot2 = udp_hashslot2 (udptable , newhash );
22342234 udp_sk (sk )-> udp_portaddr_hash = newhash ;
22352235
22362236 if (hslot2 != nhslot2 ||
22372237 rcu_access_pointer (sk -> sk_reuseport_cb )) {
2238- hslot = udp_hashslot (udptable , sock_net (sk ),
2239- udp_sk (sk )-> udp_port_hash );
22402238 /* we must lock primary chain too */
22412239 spin_lock_bh (& hslot -> lock );
22422240 if (rcu_access_pointer (sk -> sk_reuseport_cb ))
@@ -2255,19 +2253,29 @@ void udp_lib_rehash(struct sock *sk, u16 newhash, u16 newhash4)
22552253 spin_unlock (& nhslot2 -> lock );
22562254 }
22572255
2258- if (udp_hashed4 (sk )) {
2259- udp_rehash4 (udptable , sk , newhash4 );
2256+ spin_unlock_bh (& hslot -> lock );
2257+ }
2258+
2259+ /* Now process hash4 if necessary:
2260+ * (1) update hslot4;
2261+ * (2) update hslot2->hash4_cnt.
2262+ * Note that hslot2/hslot4 should be checked separately, as
2263+ * either of them may change with the other unchanged.
2264+ */
2265+ if (udp_hashed4 (sk )) {
2266+ spin_lock_bh (& hslot -> lock );
22602267
2261- if (hslot2 != nhslot2 ) {
2262- spin_lock (& hslot2 -> lock );
2263- udp_hash4_dec (hslot2 );
2264- spin_unlock (& hslot2 -> lock );
2268+ udp_rehash4 (udptable , sk , newhash4 );
2269+ if (hslot2 != nhslot2 ) {
2270+ spin_lock (& hslot2 -> lock );
2271+ udp_hash4_dec (hslot2 );
2272+ spin_unlock (& hslot2 -> lock );
22652273
2266- spin_lock (& nhslot2 -> lock );
2267- udp_hash4_inc (nhslot2 );
2268- spin_unlock (& nhslot2 -> lock );
2269- }
2274+ spin_lock (& nhslot2 -> lock );
2275+ udp_hash4_inc (nhslot2 );
2276+ spin_unlock (& nhslot2 -> lock );
22702277 }
2278+
22712279 spin_unlock_bh (& hslot -> lock );
22722280 }
22732281 }
0 commit comments