From 6c08eb71738af42f93590d0cd59ffc077df485fa Mon Sep 17 00:00:00 2001 From: Amaury Denoyelle Date: Tue, 25 Nov 2025 14:37:50 +0100 Subject: [PATCH] BUG/MINOR: quic: release BE quic_conn on connect failure If quic_connect_server() fails, quic_conn FD will remain unopened as set to -1. Backend connections do not have a fallback socket for future exchange, contrary to frontend one which can use the listener FD. As such, it is better to release these connections early. This patch adjusts such failure by extending quic_close(). This function is called by the upper layer immediately after a connect issue. In this case, release immediately a quic_conn backend instance if the FD is unset, which means that connect has previously failed. Also, quic_conn_release() is extended to ensure that such faulty connections are immediately freed and not converted into a quic_conn_closed instance. Prior to this patch, a backend quic_conn without any FD would remain allocated and possibly active. If its tasklet is executed, this resulted in a crash due to access to an invalid FD. No need to backport. --- src/quic_conn.c | 9 ++++++++- src/xprt_quic.c | 10 +++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/quic_conn.c b/src/quic_conn.c index ea9a55b97..f13f474d0 100644 --- a/src/quic_conn.c +++ b/src/quic_conn.c @@ -1548,9 +1548,16 @@ int quic_conn_release(struct quic_conn *qc) BUG_ON(qc->conn); cc_qc = NULL; + /* Convert to quic_conn_closed if entering in CLOSING state, except in + * the following case : + * - idle timeout already expired + * - no FD available for a backend connection (after connect() failure) + */ if ((qc->flags & QUIC_FL_CONN_CLOSING) && !(qc->flags & QUIC_FL_CONN_EXP_TIMER) && - qc->tx.cc_buf_area) + qc->tx.cc_buf_area && + (!qc_is_back(qc) || qc_test_fd(qc))) { cc_qc = qc_new_cc_conn(qc); + } if (!cc_qc) { task_destroy(qc->idle_timer_task); diff --git a/src/xprt_quic.c b/src/xprt_quic.c index c21b1b551..e6ca5a361 100644 --- a/src/xprt_quic.c +++ b/src/xprt_quic.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -42,10 +43,13 @@ static void quic_close(struct connection *conn, void *xprt_ctx) qc->flags |= QUIC_FL_CONN_XPRT_CLOSED; qc->conn = NULL; - /* If the quic-conn timer has already expired or if already in "connection close" - * state, free the quic-conn. + /* Immediately release the connection in the following cases : + * - idle timeout already expired + * - connection in closing state + * - backend conn with no FD avail (after connect() failure) */ - if (qc->flags & (QUIC_FL_CONN_EXP_TIMER|QUIC_FL_CONN_CLOSING)) { + if (qc->flags & (QUIC_FL_CONN_EXP_TIMER|QUIC_FL_CONN_CLOSING) || + (qc_is_back(qc) && !qc_test_fd(qc))) { quic_conn_release(qc); qc = NULL; goto leave;