MINOR: muxes: enforce thread-safety for private idle conns

When a backend connnection becomes idle, muxes must activate some
protection to mark future access on it as dangerous. Indeed, once a
connection is inserted in an idle list, it may be manipulated by another
thread, either via takeover or scheduled for purging.

Private idle connections are stored into a session instead of the server
tree. They are never subject to a takeover for reuse or purge mechanism.
As such, currently they do not require the same level of protection.

However, a new patch will introduce support for private idle connections
purging. Thus, the purpose of this patch is to ensure protection is
activated as well now.

TASK_F_USR1 was already set on them as an anticipation for such need.
Only some extra operations were missing, most notably xprt_set_idle()
invokation. Also, return path of muxes detach operation is adjusted to
ensure such connection are never accessed after insertion.
This commit is contained in:
Amaury Denoyelle 2025-08-18 15:24:05 +02:00
parent b18b5e2f74
commit 9574867358
4 changed files with 32 additions and 0 deletions

View File

@ -3748,6 +3748,7 @@ static void fcgi_detach(struct sedesc *sd)
* that the handler needs to check it under the idle conns lock.
*/
HA_ATOMIC_OR(&fconn->wait_event.tasklet->state, TASK_F_USR1);
xprt_set_idle(fconn->conn, fconn->conn->xprt, fconn->conn->xprt_ctx);
/* Ensure session can keep a new idle connection. */
if (session_check_idle_conn(sess, fconn->conn) != 0) {
@ -3755,6 +3756,13 @@ static void fcgi_detach(struct sedesc *sd)
TRACE_DEVEL("outgoing connection killed", FCGI_EV_STRM_END|FCGI_EV_FCONN_ERR);
return;
}
/* At this point, the connection is inserted into
* session list and marked as idle, so it may already
* have been purged from another thread.
*/
TRACE_DEVEL("private connection marked as idle", FCGI_EV_STRM_END, fconn->conn);
return;
}
}
else {

View File

@ -1151,6 +1151,8 @@ static int h1s_finish_detach(struct h1s *h1s)
* that the handler needs to check it under the idle conns lock.
*/
HA_ATOMIC_OR(&h1c->wait_event.tasklet->state, TASK_F_USR1);
h1c->conn->xprt->subscribe(h1c->conn, h1c->conn->xprt_ctx, SUB_RETRY_RECV, &h1c->wait_event);
xprt_set_idle(h1c->conn, h1c->conn->xprt, h1c->conn->xprt_ctx);
/* Ensure session can keep a new idle connection. */
if (session_check_idle_conn(sess, h1c->conn)) {
@ -1158,6 +1160,12 @@ static int h1s_finish_detach(struct h1s *h1s)
h1c->conn->mux->destroy(h1c);
goto released;
}
/* At this point, the connection is inserted into
* session list and marked as idle, so it may already
* have been purged from another thread.
*/
goto end;
}
else {
if (h1c->conn->owner == sess)

View File

@ -5558,6 +5558,7 @@ static void h2_detach(struct sedesc *sd)
* that the handler needs to check it under the idle conns lock.
*/
HA_ATOMIC_OR(&h2c->wait_event.tasklet->state, TASK_F_USR1);
xprt_set_idle(h2c->conn, h2c->conn->xprt, h2c->conn->xprt_ctx);
/* Ensure session can keep a new idle connection. */
if (session_check_idle_conn(sess, h2c->conn) != 0) {
@ -5565,6 +5566,13 @@ static void h2_detach(struct sedesc *sd)
TRACE_DEVEL("leaving without reusable idle connection", H2_EV_STRM_END);
return;
}
/* At this point, the connection is inserted into
* session list and marked as idle, so it may already
* have been purged from another thread.
*/
TRACE_DEVEL("private connection marked as idle", H2_EV_STRM_END);
return;
}
}
else {

View File

@ -3005,6 +3005,7 @@ static void spop_detach(struct sedesc *sd)
* that the handler needs to check it under the idle conns lock.
*/
HA_ATOMIC_OR(&spop_conn->wait_event.tasklet->state, TASK_F_USR1);
xprt_set_idle(spop_conn->conn, spop_conn->conn->xprt, spop_conn->conn->xprt_ctx);
/* Ensure session can keep a new idle connection. */
if (session_check_idle_conn(sess, spop_conn->conn) != 0) {
@ -3012,6 +3013,13 @@ static void spop_detach(struct sedesc *sd)
TRACE_DEVEL("leaving without reusable idle connection", SPOP_EV_STRM_END);
return;
}
/* At this point, the connection is inserted into
* session list and marked as idle, so it may already
* have been purged from another thread.
*/
TRACE_DEVEL("private connection marked as idle", SPOP_EV_STRM_END);
return;
}
}
else {