Skip to content

Commit 73fd12e

Browse files
committed
MEDIUM: conn/muxes/ssl: remove BE priv idle conn from sess on IO
This is a direct follow-up of previous patch which adjust idle private connections access via input/output handlers. This patch implement the handlers prologue part. Now, private idle connections require a similar treatment with non-private idle connections. Thus, private conns are removed temporarily from its session under protection of idle_conns lock. As locking usage is already performed in input/output handler, session_unown_conn() cannot be called. Thus, a new function session_detach_idle_conn() is implemented in session module, which performs basically the same operation but relies on external locking.
1 parent 8de0807 commit 73fd12e

File tree

8 files changed

+107
-17
lines changed

8 files changed

+107
-17
lines changed

include/haproxy/session.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ int session_reinsert_idle_conn(struct session *sess, struct connection *conn);
4848
int session_check_idle_conn(struct session *sess, struct connection *conn);
4949
struct connection *session_get_conn(struct session *sess, void *target, int64_t hash);
5050
void session_unown_conn(struct session *sess, struct connection *conn);
51+
int session_detach_idle_conn(struct session *sess, struct connection *conn);
5152

5253
/* Remove the refcount from the session to the tracked counters, and clear the
5354
* pointer to ensure this is only performed once. The caller is responsible for

src/connection.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,12 +199,18 @@ int conn_notify_mux(struct connection *conn, int old_flags, int forced_wake)
199199
((conn->flags ^ old_flags) & CO_FL_NOTIFY_DONE) ||
200200
((old_flags & CO_FL_WAIT_XPRT) && !(conn->flags & CO_FL_WAIT_XPRT))) &&
201201
conn->mux && conn->mux->wake) {
202-
uint conn_in_list = conn->flags & CO_FL_LIST_MASK;
202+
uint conn_in_list = conn->flags & (CO_FL_LIST_MASK|CO_FL_SESS_IDLE);
203203
struct server *srv = objt_server(conn->target);
204204

205205
if (conn_in_list) {
206206
HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
207-
conn_delete_from_tree(conn);
207+
if (conn->flags & CO_FL_SESS_IDLE) {
208+
if (!session_detach_idle_conn(conn->owner, conn))
209+
conn_in_list = 0;
210+
}
211+
else {
212+
conn_delete_from_tree(conn);
213+
}
208214
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
209215
}
210216

src/mux_fcgi.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3061,9 +3061,16 @@ struct task *fcgi_io_cb(struct task *t, void *ctx, unsigned int state)
30613061
conn = fconn->conn;
30623062
TRACE_POINT(FCGI_EV_FCONN_WAKE, conn);
30633063

3064-
conn_in_list = conn->flags & CO_FL_LIST_MASK;
3065-
if (conn_in_list)
3066-
conn_delete_from_tree(conn);
3064+
conn_in_list = conn->flags & (CO_FL_LIST_MASK|CO_FL_SESS_IDLE);
3065+
if (conn_in_list) {
3066+
if (conn->flags & CO_FL_SESS_IDLE) {
3067+
if (!session_detach_idle_conn(conn->owner, conn))
3068+
conn_in_list = 0;
3069+
}
3070+
else {
3071+
conn_delete_from_tree(conn);
3072+
}
3073+
}
30673074

30683075
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
30693076
} else {
@@ -3322,6 +3329,8 @@ struct task *fcgi_timeout_task(struct task *t, void *context, unsigned int state
33223329
*/
33233330
if (fconn->conn->flags & CO_FL_LIST_MASK)
33243331
conn_delete_from_tree(fconn->conn);
3332+
else if (fconn->conn->flags & CO_FL_SESS_IDLE)
3333+
session_detach_idle_conn(fconn->conn->owner, fconn->conn);
33253334

33263335
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
33273336

src/mux_h1.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4306,9 +4306,16 @@ struct task *h1_io_cb(struct task *t, void *ctx, unsigned int state)
43064306
/* Remove the connection from the list, to be sure nobody attempts
43074307
* to use it while we handle the I/O events
43084308
*/
4309-
conn_in_list = conn->flags & CO_FL_LIST_MASK;
4310-
if (conn_in_list)
4311-
conn_delete_from_tree(conn);
4309+
conn_in_list = conn->flags & (CO_FL_LIST_MASK|CO_FL_SESS_IDLE);
4310+
if (conn_in_list) {
4311+
if (conn->flags & CO_FL_SESS_IDLE) {
4312+
if (!session_detach_idle_conn(conn->owner, conn))
4313+
conn_in_list = 0;
4314+
}
4315+
else {
4316+
conn_delete_from_tree(conn);
4317+
}
4318+
}
43124319

43134320
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
43144321
} else {

src/mux_h2.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4962,9 +4962,16 @@ struct task *h2_io_cb(struct task *t, void *ctx, unsigned int state)
49624962
/* Remove the connection from the list, to be sure nobody attempts
49634963
* to use it while we handle the I/O events
49644964
*/
4965-
conn_in_list = conn->flags & CO_FL_LIST_MASK;
4966-
if (conn_in_list)
4967-
conn_delete_from_tree(conn);
4965+
conn_in_list = conn->flags & (CO_FL_LIST_MASK|CO_FL_SESS_IDLE);
4966+
if (conn_in_list) {
4967+
if (conn->flags & CO_FL_SESS_IDLE) {
4968+
if (!session_detach_idle_conn(conn->owner, conn))
4969+
conn_in_list = 0;
4970+
}
4971+
else {
4972+
conn_delete_from_tree(conn);
4973+
}
4974+
}
49684975

49694976
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
49704977
} else {
@@ -5245,6 +5252,8 @@ struct task *h2_timeout_task(struct task *t, void *context, unsigned int state)
52455252
*/
52465253
if (h2c->conn->flags & CO_FL_LIST_MASK)
52475254
conn_delete_from_tree(h2c->conn);
5255+
else if (h2c->conn->flags & CO_FL_SESS_IDLE)
5256+
session_detach_idle_conn(h2c->conn->owner, h2c->conn);
52485257

52495258
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
52505259

src/mux_spop.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2557,9 +2557,16 @@ static struct task *spop_io_cb(struct task *t, void *ctx, unsigned int state)
25572557
conn = spop_conn->conn;
25582558
TRACE_POINT(SPOP_EV_SPOP_CONN_WAKE, conn);
25592559

2560-
conn_in_list = conn->flags & CO_FL_LIST_MASK;
2561-
if (conn_in_list)
2562-
conn_delete_from_tree(conn);
2560+
conn_in_list = conn->flags & (CO_FL_LIST_MASK|CO_FL_SESS_IDLE);
2561+
if (conn_in_list) {
2562+
if (conn->flags & CO_FL_SESS_IDLE) {
2563+
if (!session_detach_idle_conn(conn->owner, conn))
2564+
conn_in_list = 0;
2565+
}
2566+
else {
2567+
conn_delete_from_tree(conn);
2568+
}
2569+
}
25632570

25642571
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
25652572
} else {
@@ -2792,6 +2799,8 @@ static struct task *spop_timeout_task(struct task *t, void *context, unsigned in
27922799
*/
27932800
if (spop_conn->conn->flags & CO_FL_LIST_MASK)
27942801
conn_delete_from_tree(spop_conn->conn);
2802+
else if (spop_conn->conn->flags & CO_FL_SESS_IDLE)
2803+
session_detach_idle_conn(spop_conn->conn->owner, spop_conn->conn);
27952804

27962805
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
27972806

src/session.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -837,6 +837,43 @@ void session_unown_conn(struct session *sess, struct connection *conn)
837837
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
838838
}
839839

840+
/* Remove <conn> connection from <sess> session. Contrary to
841+
* session_unown_conn(), this function is not protected by a lock, so the
842+
* caller is responsible to properly use idle_conns_lock prior to calling it.
843+
*
844+
* Another notable difference is that <owner> member of <conn> is not resetted.
845+
* This is a convenience as this function usage is generally coupled with a
846+
* following session_reinsert_idle_conn().
847+
*
848+
* Must be called with idle_conns_lock held.
849+
*
850+
* Returns true on connection removal, false if it was already not stored.
851+
*/
852+
int session_detach_idle_conn(struct session *sess, struct connection *conn)
853+
{
854+
struct sess_priv_conns *pconns;
855+
856+
if (!LIST_INLIST(&conn->sess_el))
857+
return 0;
858+
859+
/* This function is reserved for idle private connections. */
860+
BUG_ON(!(conn->flags & CO_FL_SESS_IDLE));
861+
862+
--sess->idle_conns;
863+
LIST_DEL_INIT(&conn->sess_el);
864+
865+
pconns = sess_get_sess_conns(sess, conn->target);
866+
BUG_ON(!pconns); /* if conn is attached to session, its sess_conn must exists. */
867+
if (LIST_ISEMPTY(&pconns->conn_list)) {
868+
/* Remove sess_conn element as no connection left in it. */
869+
LIST_DELETE(&pconns->sess_el);
870+
MT_LIST_DELETE(&pconns->srv_el);
871+
pool_free(pool_head_sess_priv_conns, pconns);
872+
}
873+
874+
return 1;
875+
}
876+
840877

841878
/*
842879
* Local variables:

src/ssl_sock.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6403,9 +6403,21 @@ struct task *ssl_sock_io_cb(struct task *t, void *context, unsigned int state)
64036403
}
64046404
ctx = context;
64056405
conn = ctx->conn;
6406-
conn_in_list = conn->flags & CO_FL_LIST_MASK;
6407-
if (conn_in_list)
6408-
conn_delete_from_tree(conn);
6406+
6407+
/* Remove the connection from the list, to be sure nobody attempts
6408+
* to use it while we handle the I/O events
6409+
*/
6410+
conn_in_list = conn->flags & (CO_FL_LIST_MASK|CO_FL_SESS_IDLE);
6411+
if (conn_in_list) {
6412+
if (conn->flags & CO_FL_SESS_IDLE) {
6413+
if (!session_detach_idle_conn(conn->owner, conn))
6414+
conn_in_list = 0;
6415+
}
6416+
else {
6417+
conn_delete_from_tree(conn);
6418+
}
6419+
}
6420+
64096421
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
64106422
} else {
64116423
ctx = context;

0 commit comments

Comments
 (0)