Since the request socket is created locally, it'd make more sense to
use reqsk_free() instead of reqsk_put() in TFO and syncookies' error
path.
However, tcp_get_cookie_sock() may set ->rsk_refcnt before freeing the
socket; tcp_conn_request() may also have non-null ->rsk_refcnt because
of tcp_try_fastopen(). In both cases 'req' hasn't been exposed
to the outside world and is safe to free immediately, but that'd
trigger the WARN_ON_ONCE in reqsk_free().
Define __reqsk_free() for these situations where we know nobody's
referencing the socket, even though ->rsk_refcnt might be non-null.
Now we can consolidate the error path of tcp_get_cookie_sock() and
tcp_conn_request().
Signed-off-by: Guillaume Nault <gnault@redhat.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
        return req;
 }
 
-static inline void reqsk_free(struct request_sock *req)
+static inline void __reqsk_free(struct request_sock *req)
 {
-       WARN_ON_ONCE(refcount_read(&req->rsk_refcnt) != 0);
-
        req->rsk_ops->destructor(req);
        if (req->rsk_listener)
                sock_put(req->rsk_listener);
        kmem_cache_free(req->rsk_ops->slab, req);
 }
 
+static inline void reqsk_free(struct request_sock *req)
+{
+       WARN_ON_ONCE(refcount_read(&req->rsk_refcnt) != 0);
+       __reqsk_free(req);
+}
+
 static inline void reqsk_put(struct request_sock *req)
 {
        if (refcount_dec_and_test(&req->rsk_refcnt))
 
                refcount_set(&req->rsk_refcnt, 1);
                tcp_sk(child)->tsoffset = tsoff;
                sock_rps_save_rxhash(child, skb);
-               if (!inet_csk_reqsk_queue_add(sk, req, child)) {
-                       bh_unlock_sock(child);
-                       sock_put(child);
-                       child = NULL;
-                       reqsk_put(req);
-               }
-       } else {
-               reqsk_free(req);
+               if (inet_csk_reqsk_queue_add(sk, req, child))
+                       return child;
+
+               bh_unlock_sock(child);
+               sock_put(child);
        }
-       return child;
+       __reqsk_free(req);
+
+       return NULL;
 }
 EXPORT_SYMBOL(tcp_get_cookie_sock);
 
 
                        reqsk_fastopen_remove(fastopen_sk, req, false);
                        bh_unlock_sock(fastopen_sk);
                        sock_put(fastopen_sk);
-                       reqsk_put(req);
-                       goto drop;
+                       goto drop_and_free;
                }
                sk->sk_data_ready(sk);
                bh_unlock_sock(fastopen_sk);
 drop_and_release:
        dst_release(dst);
 drop_and_free:
-       reqsk_free(req);
+       __reqsk_free(req);
 drop:
        tcp_listendrop(sk);
        return 0;