diff --git a/include/haproxy/session-t.h b/include/haproxy/session-t.h index aa2bf1e82..8c59477df 100644 --- a/include/haproxy/session-t.h +++ b/include/haproxy/session-t.h @@ -72,6 +72,8 @@ struct sess_priv_conns { struct list sess_el; /* Element of session.priv_conns */ struct mt_list srv_el; /* Element of server.sess_conns */ + + int tid; }; #endif /* _HAPROXY_SESSION_T_H */ diff --git a/include/haproxy/session.h b/include/haproxy/session.h index d9ff726a9..b70a5a89c 100644 --- a/include/haproxy/session.h +++ b/include/haproxy/session.h @@ -204,6 +204,8 @@ static inline int session_add_conn(struct session *sess, struct connection *conn MT_LIST_INIT(&pconns->srv_el); if (srv) MT_LIST_APPEND(&srv->sess_conns, &pconns->srv_el); + + pconns->tid = tid; } LIST_APPEND(&pconns->conn_list, &conn->sess_el); diff --git a/src/server.c b/src/server.c index 92d3fee94..badcf3851 100644 --- a/src/server.c +++ b/src/server.c @@ -5830,7 +5830,6 @@ int srv_check_for_deletion(const char *bename, const char *svname, struct proxy /* Ensure that there is no active/pending connection on the server. */ if (srv->curr_used_conns || - !MT_LIST_ISEMPTY(&srv->sess_conns) || !eb_is_empty(&srv->queue.head) || srv_has_streams(srv)) { msg = "Server still has connections attached to it, cannot remove it."; goto leave; @@ -5857,6 +5856,8 @@ static int cli_parse_delete_server(char **args, char *payload, struct appctx *ap struct server *srv; struct server *prev_del; struct ist be_name, sv_name; + struct mt_list *elt1, elt2; + struct sess_priv_conns *sess_conns = NULL; const char *msg; int ret, i; @@ -5910,6 +5911,31 @@ static int cli_parse_delete_server(char **args, char *payload, struct appctx *ap /* All idle connections should be removed now. */ BUG_ON(srv->curr_idle_conns); + /* Close idle private connections attached to this server. */ + mt_list_for_each_entry_safe(sess_conns, &srv->sess_conns, srv_el, elt1, elt2) { + struct connection *conn, *conn_back; + list_for_each_entry_safe(conn, conn_back, &sess_conns->conn_list, sess_el) { + + /* Only idle connections should be present if srv_check_for_deletion() is true. */ + BUG_ON(!(conn->flags & CO_FL_SESS_IDLE)); + + LIST_DEL_INIT(&conn->sess_el); + conn->owner = NULL; + conn->flags &= ~CO_FL_SESS_IDLE; + if (sess_conns->tid != tid) { + if (conn->mux && conn->mux->takeover) + conn->mux->takeover(conn, sess_conns->tid, 1); + else if (conn->xprt && conn->xprt->takeover) + conn->xprt->takeover(conn, conn->ctx, sess_conns->tid, 1); + } + conn_release(conn); + } + + LIST_DELETE(&sess_conns->sess_el); + MT_LIST_DELETE_SAFE(elt1); + pool_free(pool_head_sess_priv_conns, sess_conns); + } + /* removing cannot fail anymore when we reach this: * publishing EVENT_HDL_SUB_SERVER_DEL */