These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / net / ipv4 / tcp_fastopen.c
index f9c0fb8..55be6ac 100644 (file)
@@ -124,27 +124,29 @@ static bool tcp_fastopen_cookie_gen(struct request_sock *req,
        return false;
 }
 
-static bool tcp_fastopen_create_child(struct sock *sk,
-                                     struct sk_buff *skb,
-                                     struct dst_entry *dst,
-                                     struct request_sock *req)
+static struct sock *tcp_fastopen_create_child(struct sock *sk,
+                                             struct sk_buff *skb,
+                                             struct dst_entry *dst,
+                                             struct request_sock *req)
 {
        struct tcp_sock *tp;
        struct request_sock_queue *queue = &inet_csk(sk)->icsk_accept_queue;
        struct sock *child;
        u32 end_seq;
+       bool own_req;
 
        req->num_retrans = 0;
        req->num_timeout = 0;
        req->sk = NULL;
 
-       child = inet_csk(sk)->icsk_af_ops->syn_recv_sock(sk, skb, req, NULL);
+       child = inet_csk(sk)->icsk_af_ops->syn_recv_sock(sk, skb, req, NULL,
+                                                        NULL, &own_req);
        if (!child)
-               return false;
+               return NULL;
 
-       spin_lock(&queue->fastopenq->lock);
-       queue->fastopenq->qlen++;
-       spin_unlock(&queue->fastopenq->lock);
+       spin_lock(&queue->fastopenq.lock);
+       queue->fastopenq.qlen++;
+       spin_unlock(&queue->fastopenq.lock);
 
        /* Initialize the child socket. Have to fix some values to take
         * into account the child is a Fast Open socket and is created
@@ -161,15 +163,13 @@ static bool tcp_fastopen_create_child(struct sock *sk,
        tp->snd_wnd = ntohs(tcp_hdr(skb)->window);
 
        /* Activate the retrans timer so that SYNACK can be retransmitted.
-        * The request socket is not added to the SYN table of the parent
+        * The request socket is not added to the ehash
         * because it's been added to the accept queue directly.
         */
        inet_csk_reset_xmit_timer(child, ICSK_TIME_RETRANS,
                                  TCP_TIMEOUT_INIT, TCP_RTO_MAX);
 
-       atomic_set(&req->rsk_refcnt, 1);
-       /* Add the child socket directly into the accept queue */
-       inet_csk_reqsk_queue_add(sk, req, child);
+       atomic_set(&req->rsk_refcnt, 2);
 
        /* Now finish processing the fastopen child socket. */
        inet_csk(child)->icsk_af_ops->rebuild_header(child);
@@ -178,12 +178,10 @@ static bool tcp_fastopen_create_child(struct sock *sk,
        tcp_init_metrics(child);
        tcp_init_buffer_space(child);
 
-       /* Queue the data carried in the SYN packet. We need to first
-        * bump skb's refcnt because the caller will attempt to free it.
-        * Note that IPv6 might also have used skb_get() trick
-        * in tcp_v6_conn_request() to keep this SYN around (treq->pktopts)
-        * So we need to eventually get a clone of the packet,
-        * before inserting it in sk_receive_queue.
+       /* Queue the data carried in the SYN packet.
+        * We used to play tricky games with skb_get().
+        * With lockless listener, it is a dead end.
+        * Do not think about it.
         *
         * XXX (TFO) - we honor a zero-payload TFO request for now,
         * (any reason not to?) but no need to queue the skb since
@@ -191,12 +189,7 @@ static bool tcp_fastopen_create_child(struct sock *sk,
         */
        end_seq = TCP_SKB_CB(skb)->end_seq;
        if (end_seq != TCP_SKB_CB(skb)->seq + 1) {
-               struct sk_buff *skb2;
-
-               if (unlikely(skb_shared(skb)))
-                       skb2 = skb_clone(skb, GFP_ATOMIC);
-               else
-                       skb2 = skb_get(skb);
+               struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
 
                if (likely(skb2)) {
                        skb_dst_drop(skb2);
@@ -214,11 +207,10 @@ static bool tcp_fastopen_create_child(struct sock *sk,
                }
        }
        tcp_rsk(req)->rcv_nxt = tp->rcv_nxt = end_seq;
-       sk->sk_data_ready(sk);
-       bh_unlock_sock(child);
-       sock_put(child);
-       WARN_ON(!req->sk);
-       return true;
+       /* tcp_conn_request() is sending the SYNACK,
+        * and queues the child into listener accept queue.
+        */
+       return child;
 }
 
 static bool tcp_fastopen_queue_check(struct sock *sk)
@@ -235,8 +227,8 @@ static bool tcp_fastopen_queue_check(struct sock *sk)
         * between qlen overflow causing Fast Open to be disabled
         * temporarily vs a server not supporting Fast Open at all.
         */
-       fastopenq = inet_csk(sk)->icsk_accept_queue.fastopenq;
-       if (!fastopenq || fastopenq->max_qlen == 0)
+       fastopenq = &inet_csk(sk)->icsk_accept_queue.fastopenq;
+       if (fastopenq->max_qlen == 0)
                return false;
 
        if (fastopenq->qlen >= fastopenq->max_qlen) {
@@ -261,13 +253,14 @@ static bool tcp_fastopen_queue_check(struct sock *sk)
  * may be updated and return the client in the SYN-ACK later. E.g., Fast Open
  * cookie request (foc->len == 0).
  */
-bool tcp_try_fastopen(struct sock *sk, struct sk_buff *skb,
-                     struct request_sock *req,
-                     struct tcp_fastopen_cookie *foc,
-                     struct dst_entry *dst)
+struct sock *tcp_try_fastopen(struct sock *sk, struct sk_buff *skb,
+                             struct request_sock *req,
+                             struct tcp_fastopen_cookie *foc,
+                             struct dst_entry *dst)
 {
        struct tcp_fastopen_cookie valid_foc = { .len = -1 };
        bool syn_data = TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq + 1;
+       struct sock *child;
 
        if (foc->len == 0) /* Client requests a cookie */
                NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPFASTOPENCOOKIEREQD);
@@ -276,7 +269,7 @@ bool tcp_try_fastopen(struct sock *sk, struct sk_buff *skb,
              (syn_data || foc->len >= 0) &&
              tcp_fastopen_queue_check(sk))) {
                foc->len = -1;
-               return false;
+               return NULL;
        }
 
        if (syn_data && (sysctl_tcp_fastopen & TFO_SERVER_COOKIE_NOT_REQD))
@@ -296,11 +289,12 @@ bool tcp_try_fastopen(struct sock *sk, struct sk_buff *skb,
                 * data in SYN_RECV state.
                 */
 fastopen:
-               if (tcp_fastopen_create_child(sk, skb, dst, req)) {
+               child = tcp_fastopen_create_child(sk, skb, dst, req);
+               if (child) {
                        foc->len = -1;
                        NET_INC_STATS_BH(sock_net(sk),
                                         LINUX_MIB_TCPFASTOPENPASSIVE);
-                       return true;
+                       return child;
                }
                NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPFASTOPENPASSIVEFAIL);
        } else if (foc->len > 0) /* Client presents an invalid cookie */
@@ -308,6 +302,5 @@ fastopen:
 
        valid_foc.exp = foc->exp;
        *foc = valid_foc;
-       return false;
+       return NULL;
 }
-EXPORT_SYMBOL(tcp_try_fastopen);