Skip to content

Commit

Permalink
inet: drop prev pointer handling in request sock
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Eric Dumazet authored and David S. Miller committed Mar 20, 2015
1 parent a998f71 commit 52452c5
Show file tree
Hide file tree
Showing 14 changed files with 67 additions and 74 deletions.
1 change: 0 additions & 1 deletion include/net/inet6_connection_sock.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ struct dst_entry *inet6_csk_route_req(struct sock *sk, struct flowi6 *fl6,
const struct request_sock *req);

struct request_sock *inet6_csk_search_req(const struct sock *sk,
struct request_sock ***prevp,
const __be16 rport,
const struct in6_addr *raddr,
const struct in6_addr *laddr,
Expand Down
11 changes: 4 additions & 7 deletions include/net/inet_connection_sock.h
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,6 @@ inet_csk_rto_backoff(const struct inet_connection_sock *icsk,
struct sock *inet_csk_accept(struct sock *sk, int flags, int *err);

struct request_sock *inet_csk_search_req(const struct sock *sk,
struct request_sock ***prevp,
const __be16 rport,
const __be32 raddr,
const __be32 laddr);
Expand Down Expand Up @@ -310,17 +309,15 @@ static inline int inet_csk_reqsk_queue_is_full(const struct sock *sk)
}

static inline void inet_csk_reqsk_queue_unlink(struct sock *sk,
struct request_sock *req,
struct request_sock **prev)
struct request_sock *req)
{
reqsk_queue_unlink(&inet_csk(sk)->icsk_accept_queue, req, prev);
reqsk_queue_unlink(&inet_csk(sk)->icsk_accept_queue, req);
}

static inline void inet_csk_reqsk_queue_drop(struct sock *sk,
struct request_sock *req,
struct request_sock **prev)
struct request_sock *req)
{
inet_csk_reqsk_queue_unlink(sk, req, prev);
inet_csk_reqsk_queue_unlink(sk, req);
inet_csk_reqsk_queue_removed(sk, req);
reqsk_free(req);
}
Expand Down
15 changes: 11 additions & 4 deletions include/net/request_sock.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ int inet_rtx_syn_ack(struct sock *parent, struct request_sock *req);
struct request_sock {
struct sock_common __req_common;
#define rsk_refcnt __req_common.skc_refcnt
#define rsk_hash __req_common.skc_hash

struct request_sock *dl_next;
struct sock *rsk_listener;
Expand Down Expand Up @@ -216,11 +217,16 @@ static inline int reqsk_queue_empty(struct request_sock_queue *queue)
}

static inline void reqsk_queue_unlink(struct request_sock_queue *queue,
struct request_sock *req,
struct request_sock **prev_req)
struct request_sock *req)
{
struct listen_sock *lopt = queue->listen_opt;
struct request_sock **prev;

write_lock(&queue->syn_wait_lock);
*prev_req = req->dl_next;
prev = &lopt->syn_table[req->rsk_hash];
while (*prev != req)
prev = &(*prev)->dl_next;
*prev = req->dl_next;
write_unlock(&queue->syn_wait_lock);
}

Expand Down Expand Up @@ -300,15 +306,16 @@ static inline void reqsk_queue_hash_req(struct request_sock_queue *queue,
req->num_retrans = 0;
req->num_timeout = 0;
req->sk = NULL;
req->dl_next = lopt->syn_table[hash];

/* before letting lookups find us, make sure all req fields
* are committed to memory and refcnt initialized.
*/
smp_wmb();
atomic_set(&req->rsk_refcnt, 1);

req->rsk_hash = hash;
write_lock(&queue->syn_wait_lock);
req->dl_next = lopt->syn_table[hash];
lopt->syn_table[hash] = req;
write_unlock(&queue->syn_wait_lock);
}
Expand Down
3 changes: 1 addition & 2 deletions include/net/tcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -406,8 +406,7 @@ enum tcp_tw_status tcp_timewait_state_process(struct inet_timewait_sock *tw,
struct sk_buff *skb,
const struct tcphdr *th);
struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
struct request_sock *req, struct request_sock **prev,
bool fastopen);
struct request_sock *req, bool fastopen);
int tcp_child_process(struct sock *parent, struct sock *child,
struct sk_buff *skb);
void tcp_enter_loss(struct sock *sk);
Expand Down
3 changes: 1 addition & 2 deletions net/dccp/dccp.h
Original file line number Diff line number Diff line change
Expand Up @@ -280,8 +280,7 @@ struct sock *dccp_v4_request_recv_sock(struct sock *sk, struct sk_buff *skb,
struct request_sock *req,
struct dst_entry *dst);
struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb,
struct request_sock *req,
struct request_sock **prev);
struct request_sock *req);

int dccp_child_process(struct sock *parent, struct sock *child,
struct sk_buff *skb);
Expand Down
14 changes: 6 additions & 8 deletions net/dccp/ipv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -288,11 +288,11 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info)
}

switch (sk->sk_state) {
struct request_sock *req , **prev;
struct request_sock *req;
case DCCP_LISTEN:
if (sock_owned_by_user(sk))
goto out;
req = inet_csk_search_req(sk, &prev, dh->dccph_dport,
req = inet_csk_search_req(sk, dh->dccph_dport,
iph->daddr, iph->saddr);
if (!req)
goto out;
Expand All @@ -314,7 +314,7 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info)
* created socket, and POSIX does not want network
* errors returned from accept().
*/
inet_csk_reqsk_queue_drop(sk, req, prev);
inet_csk_reqsk_queue_drop(sk, req);
goto out;

case DCCP_REQUESTING:
Expand Down Expand Up @@ -448,13 +448,11 @@ static struct sock *dccp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
const struct dccp_hdr *dh = dccp_hdr(skb);
const struct iphdr *iph = ip_hdr(skb);
struct sock *nsk;
struct request_sock **prev;
/* Find possible connection requests. */
struct request_sock *req = inet_csk_search_req(sk, &prev,
dh->dccph_sport,
struct request_sock *req = inet_csk_search_req(sk, dh->dccph_sport,
iph->saddr, iph->daddr);
if (req != NULL)
return dccp_check_req(sk, skb, req, prev);
if (req)
return dccp_check_req(sk, skb, req);

nsk = inet_lookup_established(sock_net(sk), &dccp_hashinfo,
iph->saddr, dh->dccph_sport,
Expand Down
19 changes: 8 additions & 11 deletions net/dccp/ipv6.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,12 +149,12 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,

/* Might be for an request_sock */
switch (sk->sk_state) {
struct request_sock *req, **prev;
struct request_sock *req;
case DCCP_LISTEN:
if (sock_owned_by_user(sk))
goto out;

req = inet6_csk_search_req(sk, &prev, dh->dccph_dport,
req = inet6_csk_search_req(sk, dh->dccph_dport,
&hdr->daddr, &hdr->saddr,
inet6_iif(skb));
if (req == NULL)
Expand All @@ -172,7 +172,7 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
goto out;
}

inet_csk_reqsk_queue_drop(sk, req, prev);
inet_csk_reqsk_queue_drop(sk, req);
goto out;

case DCCP_REQUESTING:
Expand Down Expand Up @@ -317,16 +317,13 @@ static struct sock *dccp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
{
const struct dccp_hdr *dh = dccp_hdr(skb);
const struct ipv6hdr *iph = ipv6_hdr(skb);
struct request_sock *req;
struct sock *nsk;
struct request_sock **prev;
/* Find possible connection requests. */
struct request_sock *req = inet6_csk_search_req(sk, &prev,
dh->dccph_sport,
&iph->saddr,
&iph->daddr,
inet6_iif(skb));

req = inet6_csk_search_req(sk, dh->dccph_sport, &iph->saddr,
&iph->daddr, inet6_iif(skb));
if (req != NULL)
return dccp_check_req(sk, skb, req, prev);
return dccp_check_req(sk, skb, req);

nsk = __inet6_lookup_established(sock_net(sk), &dccp_hashinfo,
&iph->saddr, dh->dccph_sport,
Expand Down
7 changes: 3 additions & 4 deletions net/dccp/minisocks.c
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,7 @@ EXPORT_SYMBOL_GPL(dccp_create_openreq_child);
* as an request_sock.
*/
struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb,
struct request_sock *req,
struct request_sock **prev)
struct request_sock *req)
{
struct sock *child = NULL;
struct dccp_request_sock *dreq = dccp_rsk(req);
Expand Down Expand Up @@ -200,7 +199,7 @@ struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb,
if (child == NULL)
goto listen_overflow;

inet_csk_reqsk_queue_unlink(sk, req, prev);
inet_csk_reqsk_queue_unlink(sk, req);
inet_csk_reqsk_queue_removed(sk, req);
inet_csk_reqsk_queue_add(sk, req, child);
out:
Expand All @@ -212,7 +211,7 @@ struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb,
if (dccp_hdr(skb)->dccph_type != DCCP_PKT_RESET)
req->rsk_ops->send_reset(sk, skb);

inet_csk_reqsk_queue_drop(sk, req, prev);
inet_csk_reqsk_queue_drop(sk, req);
goto out;
}

Expand Down
22 changes: 12 additions & 10 deletions net/ipv4/inet_connection_sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -480,26 +480,24 @@ static inline u32 inet_synq_hash(const __be32 raddr, const __be16 rport,
#endif

struct request_sock *inet_csk_search_req(const struct sock *sk,
struct request_sock ***prevp,
const __be16 rport, const __be32 raddr,
const __be32 laddr)
{
const struct inet_connection_sock *icsk = inet_csk(sk);
struct listen_sock *lopt = icsk->icsk_accept_queue.listen_opt;
struct request_sock *req, **prev;
struct request_sock *req;

for (prev = &lopt->syn_table[inet_synq_hash(raddr, rport, lopt->hash_rnd,
lopt->nr_table_entries)];
(req = *prev) != NULL;
prev = &req->dl_next) {
for (req = lopt->syn_table[inet_synq_hash(raddr, rport, lopt->hash_rnd,
lopt->nr_table_entries)];
req != NULL;
req = req->dl_next) {
const struct inet_request_sock *ireq = inet_rsk(req);

if (ireq->ir_rmt_port == rport &&
ireq->ir_rmt_addr == raddr &&
ireq->ir_loc_addr == laddr &&
AF_INET_FAMILY(req->rsk_ops->family)) {
WARN_ON(req->sk);
*prevp = prev;
break;
}
}
Expand Down Expand Up @@ -610,7 +608,10 @@ void inet_csk_reqsk_queue_prune(struct sock *parent,
i = lopt->clock_hand;

do {
reqp=&lopt->syn_table[i];
reqp = &lopt->syn_table[i];
if (!*reqp)
goto next_bucket;
write_lock(&queue->syn_wait_lock);
while ((req = *reqp) != NULL) {
if (time_after_eq(now, req->expires)) {
int expire = 0, resend = 0;
Expand All @@ -635,14 +636,15 @@ void inet_csk_reqsk_queue_prune(struct sock *parent,
}

/* Drop this request */
inet_csk_reqsk_queue_unlink(parent, req, reqp);
*reqp = req->dl_next;
reqsk_queue_removed(queue, req);
reqsk_put(req);
continue;
}
reqp = &req->dl_next;
}

write_unlock(&queue->syn_wait_lock);
next_bucket:
i = (i + 1) & (lopt->nr_table_entries - 1);

} while (--budget > 0);
Expand Down
2 changes: 1 addition & 1 deletion net/ipv4/tcp_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -5694,7 +5694,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
WARN_ON_ONCE(sk->sk_state != TCP_SYN_RECV &&
sk->sk_state != TCP_FIN_WAIT1);

if (tcp_check_req(sk, skb, req, NULL, true) == NULL)
if (tcp_check_req(sk, skb, req, true) == NULL)
goto discard;
}

Expand Down
17 changes: 8 additions & 9 deletions net/ipv4/tcp_ipv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -458,12 +458,12 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
}

switch (sk->sk_state) {
struct request_sock *req, **prev;
struct request_sock *req;
case TCP_LISTEN:
if (sock_owned_by_user(sk))
goto out;

req = inet_csk_search_req(sk, &prev, th->dest,
req = inet_csk_search_req(sk, th->dest,
iph->daddr, iph->saddr);
if (!req)
goto out;
Expand All @@ -484,7 +484,7 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
* created socket, and POSIX does not want network
* errors returned from accept().
*/
inet_csk_reqsk_queue_drop(sk, req, prev);
inet_csk_reqsk_queue_drop(sk, req);
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
goto out;

Expand Down Expand Up @@ -1392,15 +1392,14 @@ EXPORT_SYMBOL(tcp_v4_syn_recv_sock);

static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
{
struct tcphdr *th = tcp_hdr(skb);
const struct tcphdr *th = tcp_hdr(skb);
const struct iphdr *iph = ip_hdr(skb);
struct request_sock *req;
struct sock *nsk;
struct request_sock **prev;
/* Find possible connection requests. */
struct request_sock *req = inet_csk_search_req(sk, &prev, th->source,
iph->saddr, iph->daddr);

req = inet_csk_search_req(sk, th->source, iph->saddr, iph->daddr);
if (req)
return tcp_check_req(sk, skb, req, prev, false);
return tcp_check_req(sk, skb, req, false);

nsk = inet_lookup_established(sock_net(sk), &tcp_hashinfo, iph->saddr,
th->source, iph->daddr, th->dest, inet_iif(skb));
Expand Down
5 changes: 2 additions & 3 deletions net/ipv4/tcp_minisocks.c
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,6 @@ EXPORT_SYMBOL(tcp_create_openreq_child);

struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
struct request_sock *req,
struct request_sock **prev,
bool fastopen)
{
struct tcp_options_received tmp_opt;
Expand Down Expand Up @@ -766,7 +765,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
if (child == NULL)
goto listen_overflow;

inet_csk_reqsk_queue_unlink(sk, req, prev);
inet_csk_reqsk_queue_unlink(sk, req);
inet_csk_reqsk_queue_removed(sk, req);

inet_csk_reqsk_queue_add(sk, req, child);
Expand All @@ -791,7 +790,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
tcp_reset(sk);
}
if (!fastopen) {
inet_csk_reqsk_queue_drop(sk, req, prev);
inet_csk_reqsk_queue_drop(sk, req);
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_EMBRYONICRSTS);
}
return NULL;
Expand Down
10 changes: 4 additions & 6 deletions net/ipv6/inet6_connection_sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,21 +113,20 @@ static u32 inet6_synq_hash(const struct in6_addr *raddr, const __be16 rport,
}

struct request_sock *inet6_csk_search_req(const struct sock *sk,
struct request_sock ***prevp,
const __be16 rport,
const struct in6_addr *raddr,
const struct in6_addr *laddr,
const int iif)
{
const struct inet_connection_sock *icsk = inet_csk(sk);
struct listen_sock *lopt = icsk->icsk_accept_queue.listen_opt;
struct request_sock *req, **prev;
struct request_sock *req;

for (prev = &lopt->syn_table[inet6_synq_hash(raddr, rport,
for (req = lopt->syn_table[inet6_synq_hash(raddr, rport,
lopt->hash_rnd,
lopt->nr_table_entries)];
(req = *prev) != NULL;
prev = &req->dl_next) {
req != NULL;
req = req->dl_next) {
const struct inet_request_sock *ireq = inet_rsk(req);

if (ireq->ir_rmt_port == rport &&
Expand All @@ -136,7 +135,6 @@ struct request_sock *inet6_csk_search_req(const struct sock *sk,
ipv6_addr_equal(&ireq->ir_v6_loc_addr, laddr) &&
(!ireq->ir_iif || ireq->ir_iif == iif)) {
WARN_ON(req->sk != NULL);
*prevp = prev;
return req;
}
}
Expand Down
Loading

0 comments on commit 52452c5

Please sign in to comment.