Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

inet: drop prev pointer handling in request sock

When request sock are put in ehash table, the whole notion
of having a previous request to update dl_next is pointless.

Also, following patch will get rid of big purge timer,
so we want to delete a request sock without holding listener lock.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Eric Dumazet and committed by
David S. Miller
52452c54 a998f712

+67 -74
-1
include/net/inet6_connection_sock.h
··· 29 29 const struct request_sock *req); 30 30 31 31 struct request_sock *inet6_csk_search_req(const struct sock *sk, 32 - struct request_sock ***prevp, 33 32 const __be16 rport, 34 33 const struct in6_addr *raddr, 35 34 const struct in6_addr *laddr,
+4 -7
include/net/inet_connection_sock.h
··· 257 257 struct sock *inet_csk_accept(struct sock *sk, int flags, int *err); 258 258 259 259 struct request_sock *inet_csk_search_req(const struct sock *sk, 260 - struct request_sock ***prevp, 261 260 const __be16 rport, 262 261 const __be32 raddr, 263 262 const __be32 laddr); ··· 309 310 } 310 311 311 312 static inline void inet_csk_reqsk_queue_unlink(struct sock *sk, 312 - struct request_sock *req, 313 - struct request_sock **prev) 313 + struct request_sock *req) 314 314 { 315 - reqsk_queue_unlink(&inet_csk(sk)->icsk_accept_queue, req, prev); 315 + reqsk_queue_unlink(&inet_csk(sk)->icsk_accept_queue, req); 316 316 } 317 317 318 318 static inline void inet_csk_reqsk_queue_drop(struct sock *sk, 319 - struct request_sock *req, 320 - struct request_sock **prev) 319 + struct request_sock *req) 321 320 { 322 - inet_csk_reqsk_queue_unlink(sk, req, prev); 321 + inet_csk_reqsk_queue_unlink(sk, req); 323 322 inet_csk_reqsk_queue_removed(sk, req); 324 323 reqsk_free(req); 325 324 }
+11 -4
include/net/request_sock.h
··· 50 50 struct request_sock { 51 51 struct sock_common __req_common; 52 52 #define rsk_refcnt __req_common.skc_refcnt 53 + #define rsk_hash __req_common.skc_hash 53 54 54 55 struct request_sock *dl_next; 55 56 struct sock *rsk_listener; ··· 217 216 } 218 217 219 218 static inline void reqsk_queue_unlink(struct request_sock_queue *queue, 220 - struct request_sock *req, 221 - struct request_sock **prev_req) 219 + struct request_sock *req) 222 220 { 221 + struct listen_sock *lopt = queue->listen_opt; 222 + struct request_sock **prev; 223 + 223 224 write_lock(&queue->syn_wait_lock); 224 - *prev_req = req->dl_next; 225 + prev = &lopt->syn_table[req->rsk_hash]; 226 + while (*prev != req) 227 + prev = &(*prev)->dl_next; 228 + *prev = req->dl_next; 225 229 write_unlock(&queue->syn_wait_lock); 226 230 } 227 231 ··· 306 300 req->num_retrans = 0; 307 301 req->num_timeout = 0; 308 302 req->sk = NULL; 309 - req->dl_next = lopt->syn_table[hash]; 310 303 311 304 /* before letting lookups find us, make sure all req fields 312 305 * are committed to memory and refcnt initialized. ··· 313 308 smp_wmb(); 314 309 atomic_set(&req->rsk_refcnt, 1); 315 310 311 + req->rsk_hash = hash; 316 312 write_lock(&queue->syn_wait_lock); 313 + req->dl_next = lopt->syn_table[hash]; 317 314 lopt->syn_table[hash] = req; 318 315 write_unlock(&queue->syn_wait_lock); 319 316 }
+1 -2
include/net/tcp.h
··· 406 406 struct sk_buff *skb, 407 407 const struct tcphdr *th); 408 408 struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, 409 - struct request_sock *req, struct request_sock **prev, 410 - bool fastopen); 409 + struct request_sock *req, bool fastopen); 411 410 int tcp_child_process(struct sock *parent, struct sock *child, 412 411 struct sk_buff *skb); 413 412 void tcp_enter_loss(struct sock *sk);
+1 -2
net/dccp/dccp.h
··· 280 280 struct request_sock *req, 281 281 struct dst_entry *dst); 282 282 struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb, 283 - struct request_sock *req, 284 - struct request_sock **prev); 283 + struct request_sock *req); 285 284 286 285 int dccp_child_process(struct sock *parent, struct sock *child, 287 286 struct sk_buff *skb);
+6 -8
net/dccp/ipv4.c
··· 288 288 } 289 289 290 290 switch (sk->sk_state) { 291 - struct request_sock *req , **prev; 291 + struct request_sock *req; 292 292 case DCCP_LISTEN: 293 293 if (sock_owned_by_user(sk)) 294 294 goto out; 295 - req = inet_csk_search_req(sk, &prev, dh->dccph_dport, 295 + req = inet_csk_search_req(sk, dh->dccph_dport, 296 296 iph->daddr, iph->saddr); 297 297 if (!req) 298 298 goto out; ··· 314 314 * created socket, and POSIX does not want network 315 315 * errors returned from accept(). 316 316 */ 317 - inet_csk_reqsk_queue_drop(sk, req, prev); 317 + inet_csk_reqsk_queue_drop(sk, req); 318 318 goto out; 319 319 320 320 case DCCP_REQUESTING: ··· 448 448 const struct dccp_hdr *dh = dccp_hdr(skb); 449 449 const struct iphdr *iph = ip_hdr(skb); 450 450 struct sock *nsk; 451 - struct request_sock **prev; 452 451 /* Find possible connection requests. */ 453 - struct request_sock *req = inet_csk_search_req(sk, &prev, 454 - dh->dccph_sport, 452 + struct request_sock *req = inet_csk_search_req(sk, dh->dccph_sport, 455 453 iph->saddr, iph->daddr); 456 - if (req != NULL) 457 - return dccp_check_req(sk, skb, req, prev); 454 + if (req) 455 + return dccp_check_req(sk, skb, req); 458 456 459 457 nsk = inet_lookup_established(sock_net(sk), &dccp_hashinfo, 460 458 iph->saddr, dh->dccph_sport,
+8 -11
net/dccp/ipv6.c
··· 149 149 150 150 /* Might be for an request_sock */ 151 151 switch (sk->sk_state) { 152 - struct request_sock *req, **prev; 152 + struct request_sock *req; 153 153 case DCCP_LISTEN: 154 154 if (sock_owned_by_user(sk)) 155 155 goto out; 156 156 157 - req = inet6_csk_search_req(sk, &prev, dh->dccph_dport, 157 + req = inet6_csk_search_req(sk, dh->dccph_dport, 158 158 &hdr->daddr, &hdr->saddr, 159 159 inet6_iif(skb)); 160 160 if (req == NULL) ··· 172 172 goto out; 173 173 } 174 174 175 - inet_csk_reqsk_queue_drop(sk, req, prev); 175 + inet_csk_reqsk_queue_drop(sk, req); 176 176 goto out; 177 177 178 178 case DCCP_REQUESTING: ··· 317 317 { 318 318 const struct dccp_hdr *dh = dccp_hdr(skb); 319 319 const struct ipv6hdr *iph = ipv6_hdr(skb); 320 + struct request_sock *req; 320 321 struct sock *nsk; 321 - struct request_sock **prev; 322 - /* Find possible connection requests. */ 323 - struct request_sock *req = inet6_csk_search_req(sk, &prev, 324 - dh->dccph_sport, 325 - &iph->saddr, 326 - &iph->daddr, 327 - inet6_iif(skb)); 322 + 323 + req = inet6_csk_search_req(sk, dh->dccph_sport, &iph->saddr, 324 + &iph->daddr, inet6_iif(skb)); 328 325 if (req != NULL) 329 - return dccp_check_req(sk, skb, req, prev); 326 + return dccp_check_req(sk, skb, req); 330 327 331 328 nsk = __inet6_lookup_established(sock_net(sk), &dccp_hashinfo, 332 329 &iph->saddr, dh->dccph_sport,
+3 -4
net/dccp/minisocks.c
··· 152 152 * as an request_sock. 153 153 */ 154 154 struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb, 155 - struct request_sock *req, 156 - struct request_sock **prev) 155 + struct request_sock *req) 157 156 { 158 157 struct sock *child = NULL; 159 158 struct dccp_request_sock *dreq = dccp_rsk(req); ··· 199 200 if (child == NULL) 200 201 goto listen_overflow; 201 202 202 - inet_csk_reqsk_queue_unlink(sk, req, prev); 203 + inet_csk_reqsk_queue_unlink(sk, req); 203 204 inet_csk_reqsk_queue_removed(sk, req); 204 205 inet_csk_reqsk_queue_add(sk, req, child); 205 206 out: ··· 211 212 if (dccp_hdr(skb)->dccph_type != DCCP_PKT_RESET) 212 213 req->rsk_ops->send_reset(sk, skb); 213 214 214 - inet_csk_reqsk_queue_drop(sk, req, prev); 215 + inet_csk_reqsk_queue_drop(sk, req); 215 216 goto out; 216 217 } 217 218
+12 -10
net/ipv4/inet_connection_sock.c
··· 480 480 #endif 481 481 482 482 struct request_sock *inet_csk_search_req(const struct sock *sk, 483 - struct request_sock ***prevp, 484 483 const __be16 rport, const __be32 raddr, 485 484 const __be32 laddr) 486 485 { 487 486 const struct inet_connection_sock *icsk = inet_csk(sk); 488 487 struct listen_sock *lopt = icsk->icsk_accept_queue.listen_opt; 489 - struct request_sock *req, **prev; 488 + struct request_sock *req; 490 489 491 - for (prev = &lopt->syn_table[inet_synq_hash(raddr, rport, lopt->hash_rnd, 492 - lopt->nr_table_entries)]; 493 - (req = *prev) != NULL; 494 - prev = &req->dl_next) { 490 + for (req = lopt->syn_table[inet_synq_hash(raddr, rport, lopt->hash_rnd, 491 + lopt->nr_table_entries)]; 492 + req != NULL; 493 + req = req->dl_next) { 495 494 const struct inet_request_sock *ireq = inet_rsk(req); 496 495 497 496 if (ireq->ir_rmt_port == rport && ··· 498 499 ireq->ir_loc_addr == laddr && 499 500 AF_INET_FAMILY(req->rsk_ops->family)) { 500 501 WARN_ON(req->sk); 501 - *prevp = prev; 502 502 break; 503 503 } 504 504 } ··· 608 610 i = lopt->clock_hand; 609 611 610 612 do { 611 - reqp=&lopt->syn_table[i]; 613 + reqp = &lopt->syn_table[i]; 614 + if (!*reqp) 615 + goto next_bucket; 616 + write_lock(&queue->syn_wait_lock); 612 617 while ((req = *reqp) != NULL) { 613 618 if (time_after_eq(now, req->expires)) { 614 619 int expire = 0, resend = 0; ··· 636 635 } 637 636 638 637 /* Drop this request */ 639 - inet_csk_reqsk_queue_unlink(parent, req, reqp); 638 + *reqp = req->dl_next; 640 639 reqsk_queue_removed(queue, req); 641 640 reqsk_put(req); 642 641 continue; 643 642 } 644 643 reqp = &req->dl_next; 645 644 } 646 - 645 + write_unlock(&queue->syn_wait_lock); 646 + next_bucket: 647 647 i = (i + 1) & (lopt->nr_table_entries - 1); 648 648 649 649 } while (--budget > 0);
+1 -1
net/ipv4/tcp_input.c
··· 5694 5694 WARN_ON_ONCE(sk->sk_state != TCP_SYN_RECV && 5695 5695 sk->sk_state != TCP_FIN_WAIT1); 5696 5696 5697 - if (tcp_check_req(sk, skb, req, NULL, true) == NULL) 5697 + if (tcp_check_req(sk, skb, req, true) == NULL) 5698 5698 goto discard; 5699 5699 } 5700 5700
+8 -9
net/ipv4/tcp_ipv4.c
··· 458 458 } 459 459 460 460 switch (sk->sk_state) { 461 - struct request_sock *req, **prev; 461 + struct request_sock *req; 462 462 case TCP_LISTEN: 463 463 if (sock_owned_by_user(sk)) 464 464 goto out; 465 465 466 - req = inet_csk_search_req(sk, &prev, th->dest, 466 + req = inet_csk_search_req(sk, th->dest, 467 467 iph->daddr, iph->saddr); 468 468 if (!req) 469 469 goto out; ··· 484 484 * created socket, and POSIX does not want network 485 485 * errors returned from accept(). 486 486 */ 487 - inet_csk_reqsk_queue_drop(sk, req, prev); 487 + inet_csk_reqsk_queue_drop(sk, req); 488 488 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); 489 489 goto out; 490 490 ··· 1392 1392 1393 1393 static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) 1394 1394 { 1395 - struct tcphdr *th = tcp_hdr(skb); 1395 + const struct tcphdr *th = tcp_hdr(skb); 1396 1396 const struct iphdr *iph = ip_hdr(skb); 1397 + struct request_sock *req; 1397 1398 struct sock *nsk; 1398 - struct request_sock **prev; 1399 - /* Find possible connection requests. */ 1400 - struct request_sock *req = inet_csk_search_req(sk, &prev, th->source, 1401 - iph->saddr, iph->daddr); 1399 + 1400 + req = inet_csk_search_req(sk, th->source, iph->saddr, iph->daddr); 1402 1401 if (req) 1403 - return tcp_check_req(sk, skb, req, prev, false); 1402 + return tcp_check_req(sk, skb, req, false); 1404 1403 1405 1404 nsk = inet_lookup_established(sock_net(sk), &tcp_hashinfo, iph->saddr, 1406 1405 th->source, iph->daddr, th->dest, inet_iif(skb));
+2 -3
net/ipv4/tcp_minisocks.c
··· 572 572 573 573 struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, 574 574 struct request_sock *req, 575 - struct request_sock **prev, 576 575 bool fastopen) 577 576 { 578 577 struct tcp_options_received tmp_opt; ··· 765 766 if (child == NULL) 766 767 goto listen_overflow; 767 768 768 - inet_csk_reqsk_queue_unlink(sk, req, prev); 769 + inet_csk_reqsk_queue_unlink(sk, req); 769 770 inet_csk_reqsk_queue_removed(sk, req); 770 771 771 772 inet_csk_reqsk_queue_add(sk, req, child); ··· 790 791 tcp_reset(sk); 791 792 } 792 793 if (!fastopen) { 793 - inet_csk_reqsk_queue_drop(sk, req, prev); 794 + inet_csk_reqsk_queue_drop(sk, req); 794 795 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_EMBRYONICRSTS); 795 796 } 796 797 return NULL;
+4 -6
net/ipv6/inet6_connection_sock.c
··· 113 113 } 114 114 115 115 struct request_sock *inet6_csk_search_req(const struct sock *sk, 116 - struct request_sock ***prevp, 117 116 const __be16 rport, 118 117 const struct in6_addr *raddr, 119 118 const struct in6_addr *laddr, ··· 120 121 { 121 122 const struct inet_connection_sock *icsk = inet_csk(sk); 122 123 struct listen_sock *lopt = icsk->icsk_accept_queue.listen_opt; 123 - struct request_sock *req, **prev; 124 + struct request_sock *req; 124 125 125 - for (prev = &lopt->syn_table[inet6_synq_hash(raddr, rport, 126 + for (req = lopt->syn_table[inet6_synq_hash(raddr, rport, 126 127 lopt->hash_rnd, 127 128 lopt->nr_table_entries)]; 128 - (req = *prev) != NULL; 129 - prev = &req->dl_next) { 129 + req != NULL; 130 + req = req->dl_next) { 130 131 const struct inet_request_sock *ireq = inet_rsk(req); 131 132 132 133 if (ireq->ir_rmt_port == rport && ··· 135 136 ipv6_addr_equal(&ireq->ir_v6_loc_addr, laddr) && 136 137 (!ireq->ir_iif || ireq->ir_iif == iif)) { 137 138 WARN_ON(req->sk != NULL); 138 - *prevp = prev; 139 139 return req; 140 140 } 141 141 }
+6 -6
net/ipv6/tcp_ipv6.c
··· 403 403 404 404 /* Might be for an request_sock */ 405 405 switch (sk->sk_state) { 406 - struct request_sock *req, **prev; 406 + struct request_sock *req; 407 407 case TCP_LISTEN: 408 408 if (sock_owned_by_user(sk)) 409 409 goto out; 410 410 411 411 /* Note : We use inet6_iif() here, not tcp_v6_iif() */ 412 - req = inet6_csk_search_req(sk, &prev, th->dest, &hdr->daddr, 412 + req = inet6_csk_search_req(sk, th->dest, &hdr->daddr, 413 413 &hdr->saddr, inet6_iif(skb)); 414 414 if (!req) 415 415 goto out; ··· 424 424 goto out; 425 425 } 426 426 427 - inet_csk_reqsk_queue_drop(sk, req, prev); 427 + inet_csk_reqsk_queue_drop(sk, req); 428 428 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); 429 429 goto out; 430 430 ··· 980 980 981 981 static struct sock *tcp_v6_hnd_req(struct sock *sk, struct sk_buff *skb) 982 982 { 983 - struct request_sock *req, **prev; 984 983 const struct tcphdr *th = tcp_hdr(skb); 984 + struct request_sock *req; 985 985 struct sock *nsk; 986 986 987 987 /* Find possible connection requests. */ 988 - req = inet6_csk_search_req(sk, &prev, th->source, 988 + req = inet6_csk_search_req(sk, th->source, 989 989 &ipv6_hdr(skb)->saddr, 990 990 &ipv6_hdr(skb)->daddr, tcp_v6_iif(skb)); 991 991 if (req) 992 - return tcp_check_req(sk, skb, req, prev, false); 992 + return tcp_check_req(sk, skb, req, false); 993 993 994 994 nsk = __inet6_lookup_established(sock_net(sk), &tcp_hashinfo, 995 995 &ipv6_hdr(skb)->saddr, th->source,