213 lines
8.4 KiB
Diff
213 lines
8.4 KiB
Diff
From a53fdaf7203e45f67c44d7e250cec36875ea8e01 Mon Sep 17 00:00:00 2001
|
|
From: Christopher Faulet <cfaulet@haproxy.com>
|
|
Date: Thu, 16 Mar 2023 11:43:05 +0100
|
|
Subject: [PATCH] BUG/MEDIUM: connection: Preserve flags when a conn is removed
|
|
from an idle list
|
|
|
|
The commit 5e1b0e7bf ("BUG/MEDIUM: connection: Clear flags when a conn is
|
|
removed from an idle list") introduced a regression. CO_FL_SAFE_LIST and
|
|
CO_FL_IDLE_LIST flags are used when the connection is released to properly
|
|
decrement used/idle connection counters. if a connection is idle, these
|
|
flags must be preserved till the connection is really released. It may be
|
|
removed from the list but not immediately released. If these flags are lost
|
|
when it is finally released, the current number of used connections is
|
|
erroneously decremented. If means this counter may become negative and the
|
|
counters tracking the number of idle connecitons is not decremented,
|
|
suggesting a leak.
|
|
|
|
So, the above commit is reverted and instead we improve a bit the way to
|
|
detect an idle connection. The function conn_get_idle_flag() must now be
|
|
used to know if a connection is in an idle list. It returns the connection
|
|
flag corresponding to the idle list if the connection is idle
|
|
(CO_FL_SAFE_LIST or CO_FL_IDLE_LIST) or 0 otherwise. But if the connection
|
|
is scheduled to be removed, 0 is also returned, regardless the connection
|
|
flags.
|
|
|
|
This new function is used when the connection is temporarily removed from
|
|
the list to be used, mainly in muxes.
|
|
|
|
This patch should fix #2078 and #2057. It must be backported as far as 2.2.
|
|
|
|
(cherry picked from commit 3a7b539b124bccaa57478e0a5a6d66338594615a)
|
|
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
|
|
(cherry picked from commit a81a1e2aea0793aa624565a14cb7579b907f116a)
|
|
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
|
|
|
|
Conflict: NA
|
|
Reference: https://git.haproxy.org/?p=haproxy-2.6.git;a=commit;h=a53fdaf7203e45f67c44d7e250cec36875ea8e01
|
|
---
|
|
include/haproxy/connection.h | 10 ++++++++++
|
|
src/connection.c | 2 +-
|
|
src/mux_fcgi.c | 6 ++----
|
|
src/mux_h1.c | 6 ++----
|
|
src/mux_h2.c | 10 ++--------
|
|
src/server.c | 1 -
|
|
src/ssl_sock.c | 2 +-
|
|
7 files changed, 18 insertions(+), 19 deletions(-)
|
|
|
|
diff --git a/include/haproxy/connection.h b/include/haproxy/connection.h
|
|
index 4d289e7b3..8cf22ef4f 100644
|
|
--- a/include/haproxy/connection.h
|
|
+++ b/include/haproxy/connection.h
|
|
@@ -316,6 +316,16 @@ static inline void conn_set_private(struct connection *conn)
|
|
}
|
|
}
|
|
|
|
+/* Used to know if a connection is in an idle list. It returns connection flag
|
|
+ * corresponding to the idle list if the connection is idle (CO_FL_SAFE_LIST or
|
|
+ * CO_FL_IDLE_LIST) or 0 otherwise. Note that if the connection is scheduled to
|
|
+ * be removed, 0 is returned, regardless the connection flags.
|
|
+ */
|
|
+static inline unsigned int conn_get_idle_flag(const struct connection *conn)
|
|
+{
|
|
+ return (!MT_LIST_INLIST(&conn->toremove_list) ? conn->flags & CO_FL_LIST_MASK : 0);
|
|
+}
|
|
+
|
|
static inline void conn_force_unsubscribe(struct connection *conn)
|
|
{
|
|
if (!conn->subs)
|
|
diff --git a/src/connection.c b/src/connection.c
|
|
index 4a73dbcc8..5a459fd98 100644
|
|
--- a/src/connection.c
|
|
+++ b/src/connection.c
|
|
@@ -146,7 +146,7 @@ int conn_notify_mux(struct connection *conn, int old_flags, int forced_wake)
|
|
((conn->flags ^ old_flags) & CO_FL_NOTIFY_DONE) ||
|
|
((old_flags & CO_FL_WAIT_XPRT) && !(conn->flags & CO_FL_WAIT_XPRT))) &&
|
|
conn->mux && conn->mux->wake) {
|
|
- uint conn_in_list = conn->flags & CO_FL_LIST_MASK;
|
|
+ uint conn_in_list = conn_get_idle_flag(conn);
|
|
struct server *srv = objt_server(conn->target);
|
|
|
|
if (conn_in_list) {
|
|
diff --git a/src/mux_fcgi.c b/src/mux_fcgi.c
|
|
index 4981f6bab..2c417dd1f 100644
|
|
--- a/src/mux_fcgi.c
|
|
+++ b/src/mux_fcgi.c
|
|
@@ -3043,7 +3043,7 @@ struct task *fcgi_io_cb(struct task *t, void *ctx, unsigned int state)
|
|
conn = fconn->conn;
|
|
TRACE_POINT(FCGI_EV_FCONN_WAKE, conn);
|
|
|
|
- conn_in_list = conn->flags & CO_FL_LIST_MASK;
|
|
+ conn_in_list = conn_get_idle_flag(conn);
|
|
if (conn_in_list)
|
|
conn_delete_from_tree(&conn->hash_node->node);
|
|
|
|
@@ -3227,10 +3227,8 @@ struct task *fcgi_timeout_task(struct task *t, void *context, unsigned int state
|
|
/* We're about to destroy the connection, so make sure nobody attempts
|
|
* to steal it from us.
|
|
*/
|
|
- if (fconn->conn->flags & CO_FL_LIST_MASK) {
|
|
+ if (fconn->conn->flags & CO_FL_LIST_MASK)
|
|
conn_delete_from_tree(&fconn->conn->hash_node->node);
|
|
- fconn->conn->flags &= ~CO_FL_LIST_MASK;
|
|
- }
|
|
|
|
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
|
|
}
|
|
diff --git a/src/mux_h1.c b/src/mux_h1.c
|
|
index 56b08a77e..6f59b3112 100644
|
|
--- a/src/mux_h1.c
|
|
+++ b/src/mux_h1.c
|
|
@@ -3158,7 +3158,7 @@ struct task *h1_io_cb(struct task *t, void *ctx, unsigned int state)
|
|
/* Remove the connection from the list, to be sure nobody attempts
|
|
* to use it while we handle the I/O events
|
|
*/
|
|
- conn_in_list = conn->flags & CO_FL_LIST_MASK;
|
|
+ conn_in_list = conn_get_idle_flag(conn);
|
|
if (conn_in_list)
|
|
conn_delete_from_tree(&conn->hash_node->node);
|
|
|
|
@@ -3282,10 +3282,8 @@ struct task *h1_timeout_task(struct task *t, void *context, unsigned int state)
|
|
/* We're about to destroy the connection, so make sure nobody attempts
|
|
* to steal it from us.
|
|
*/
|
|
- if (h1c->conn->flags & CO_FL_LIST_MASK) {
|
|
+ if (h1c->conn->flags & CO_FL_LIST_MASK)
|
|
conn_delete_from_tree(&h1c->conn->hash_node->node);
|
|
- h1c->conn->flags &= ~CO_FL_LIST_MASK;
|
|
- }
|
|
|
|
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
|
|
}
|
|
diff --git a/src/mux_h2.c b/src/mux_h2.c
|
|
index f4cb5b188..b62a8f60e 100644
|
|
--- a/src/mux_h2.c
|
|
+++ b/src/mux_h2.c
|
|
@@ -4027,11 +4027,10 @@ struct task *h2_io_cb(struct task *t, void *ctx, unsigned int state)
|
|
conn = h2c->conn;
|
|
TRACE_ENTER(H2_EV_H2C_WAKE, conn);
|
|
|
|
- conn_in_list = conn->flags & CO_FL_LIST_MASK;
|
|
-
|
|
/* Remove the connection from the list, to be sure nobody attempts
|
|
* to use it while we handle the I/O events
|
|
*/
|
|
+ conn_in_list = conn_get_idle_flag(conn);
|
|
if (conn_in_list)
|
|
conn_delete_from_tree(&conn->hash_node->node);
|
|
|
|
@@ -4163,7 +4162,6 @@ static int h2_process(struct h2c *h2c)
|
|
if (conn->flags & CO_FL_LIST_MASK) {
|
|
HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
|
|
conn_delete_from_tree(&conn->hash_node->node);
|
|
- conn->flags &= ~CO_FL_LIST_MASK;
|
|
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
|
|
}
|
|
}
|
|
@@ -4172,7 +4170,6 @@ static int h2_process(struct h2c *h2c)
|
|
if (conn->flags & CO_FL_LIST_MASK) {
|
|
HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
|
|
conn_delete_from_tree(&conn->hash_node->node);
|
|
- conn->flags &= ~CO_FL_LIST_MASK;
|
|
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
|
|
}
|
|
}
|
|
@@ -4253,10 +4250,8 @@ struct task *h2_timeout_task(struct task *t, void *context, unsigned int state)
|
|
/* We're about to destroy the connection, so make sure nobody attempts
|
|
* to steal it from us.
|
|
*/
|
|
- if (h2c->conn->flags & CO_FL_LIST_MASK) {
|
|
+ if (h2c->conn->flags & CO_FL_LIST_MASK)
|
|
conn_delete_from_tree(&h2c->conn->hash_node->node);
|
|
- h2c->conn->flags &= ~CO_FL_LIST_MASK;
|
|
- }
|
|
|
|
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
|
|
}
|
|
@@ -4309,7 +4304,6 @@ struct task *h2_timeout_task(struct task *t, void *context, unsigned int state)
|
|
if (h2c->conn->flags & CO_FL_LIST_MASK) {
|
|
HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
|
|
conn_delete_from_tree(&h2c->conn->hash_node->node);
|
|
- h2c->conn->flags &= ~CO_FL_LIST_MASK;
|
|
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
|
|
}
|
|
|
|
diff --git a/src/server.c b/src/server.c
|
|
index 8a282bcf9..d701eaeab 100644
|
|
--- a/src/server.c
|
|
+++ b/src/server.c
|
|
@@ -5717,7 +5717,6 @@ static int srv_migrate_conns_to_remove(struct eb_root *idle_tree, struct mt_list
|
|
|
|
hash_node = ebmb_entry(node, struct conn_hash_node, node);
|
|
eb_delete(node);
|
|
- hash_node->conn->flags &= ~CO_FL_LIST_MASK;
|
|
MT_LIST_APPEND(toremove_list, &hash_node->conn->toremove_list);
|
|
i++;
|
|
|
|
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
|
|
index 919a08a88..b2f937487 100644
|
|
--- a/src/ssl_sock.c
|
|
+++ b/src/ssl_sock.c
|
|
@@ -6481,7 +6481,7 @@ struct task *ssl_sock_io_cb(struct task *t, void *context, unsigned int state)
|
|
return NULL;
|
|
}
|
|
conn = ctx->conn;
|
|
- conn_in_list = conn->flags & CO_FL_LIST_MASK;
|
|
+ conn_in_list = conn_get_idle_flag(conn);
|
|
if (conn_in_list)
|
|
conn_delete_from_tree(&conn->hash_node->node);
|
|
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
|
|
--
|
|
2.33.0
|
|
|