Commit 9403cf23 authored by Guillaume Nault's avatar Guillaume Nault Committed by David S. Miller
Browse files

tcp: free request sock directly upon TFO or syncookies error



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: default avatarGuillaume Nault <gnault@redhat.com>
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 56dc6d63
Loading
Loading
Loading
Loading
+7 −3
Original line number Diff line number Diff line
@@ -106,10 +106,8 @@ reqsk_alloc(const struct request_sock_ops *ops, struct sock *sk_listener,
	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);
@@ -117,6 +115,12 @@ static inline void reqsk_free(struct request_sock *req)
	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))
+8 −9
Original line number Diff line number Diff line
@@ -216,16 +216,15 @@ struct sock *tcp_get_cookie_sock(struct sock *sk, struct sk_buff *skb,
		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)) {
		if (inet_csk_reqsk_queue_add(sk, req, child))
			return child;

		bh_unlock_sock(child);
		sock_put(child);
			child = NULL;
			reqsk_put(req);
		}
	} else {
		reqsk_free(req);
	}
	return child;
	__reqsk_free(req);

	return NULL;
}
EXPORT_SYMBOL(tcp_get_cookie_sock);

+2 −3
Original line number Diff line number Diff line
@@ -6502,8 +6502,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
			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);
@@ -6527,7 +6526,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
drop_and_release:
	dst_release(dst);
drop_and_free:
	reqsk_free(req);
	__reqsk_free(req);
drop:
	tcp_listendrop(sk);
	return 0;