void session_embryonic_build_legacy_err(struct session *sess, struct buffer *out);
int session_add_conn(struct session *sess, struct connection *conn);
+int session_reinsert_idle_conn(struct session *sess, struct connection *conn);
int session_check_idle_conn(struct session *sess, struct connection *conn);
struct connection *session_get_conn(struct session *sess, void *target, int64_t hash);
void session_unown_conn(struct session *sess, struct connection *conn);
goto done;
if (conn_in_list) {
- if (srv->cur_admin & SRV_ADMF_MAINT) {
+ if (srv && (srv->cur_admin & SRV_ADMF_MAINT)) {
/* Do not store an idle conn if server in maintenance. */
conn->mux->destroy(conn->ctx);
ret = -1;
goto done;
}
- HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
- _srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ if (conn->flags & CO_FL_SESS_IDLE) {
+ if (!session_reinsert_idle_conn(conn->owner, conn)) {
+ /* session add conn failure */
+ conn->mux->destroy(conn->ctx);
+ ret = -1;
+ }
+ }
+ else {
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ _srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ }
}
}
done:
t = NULL;
if (!ret && conn_in_list) {
- struct server *srv = __objt_server(conn->target);
+ struct server *srv = objt_server(conn->target);
- if (!(srv->cur_admin & SRV_ADMF_MAINT)) {
- HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
- _srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ if (!srv || !(srv->cur_admin & SRV_ADMF_MAINT)) {
+ if (conn->flags & CO_FL_SESS_IDLE) {
+ if (!session_reinsert_idle_conn(conn->owner, conn)) {
+ /* session add conn failure */
+ goto release;
+ }
+ }
+ else {
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ _srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ }
}
else {
/* Do not store an idle conn if server in maintenance. */
t = NULL;
if (!ret && conn_in_list) {
- struct server *srv = __objt_server(conn->target);
+ struct server *srv = objt_server(conn->target);
- if (!(srv->cur_admin & SRV_ADMF_MAINT)) {
- HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
- _srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ if (!srv || !(srv->cur_admin & SRV_ADMF_MAINT)) {
+ if (conn->flags & CO_FL_SESS_IDLE) {
+ if (!session_reinsert_idle_conn(conn->owner, conn)) {
+ /* session add conn failure */
+ goto release;
+ }
+ }
+ else {
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ _srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ }
}
else {
/* Do not store an idle conn if server in maintenance. */
h2c->next_tasklet = NULL;
if (!ret && conn_in_list) {
- struct server *srv = __objt_server(conn->target);
+ struct server *srv = objt_server(conn->target);
- if (!(srv->cur_admin & SRV_ADMF_MAINT)) {
- HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
- _srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ if (!srv || !(srv->cur_admin & SRV_ADMF_MAINT)) {
+ if (conn->flags & CO_FL_SESS_IDLE) {
+ if (!session_reinsert_idle_conn(conn->owner, conn)) {
+ /* session add conn failure */
+ goto release;
+ }
+ }
+ else {
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ _srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ }
}
else {
/* Do not store an idle conn if server in maintenance. */
t = NULL;
if (!ret && conn_in_list) {
- struct server *srv = __objt_server(conn->target);
+ struct server *srv = objt_server(conn->target);
- if (!(srv->cur_admin & SRV_ADMF_MAINT)) {
- HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
- _srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ if (!srv || !(srv->cur_admin & SRV_ADMF_MAINT)) {
+ if (conn->flags & CO_FL_SESS_IDLE) {
+ if (!session_reinsert_idle_conn(conn->owner, conn)) {
+ /* session add conn failure */
+ goto release;
+ }
+ }
+ else {
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ _srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ }
}
else {
/* Do not store an idle conn if server in maintenance. */
return ret;
}
+/* Reinsert a backend connection <conn> into <sess> session. This function is
+ * reserved for idle conns which were previously temporarily removed from
+ * session to protect it against other threads.
+ *
+ * Returns true on success else false.
+ */
+int session_reinsert_idle_conn(struct session *sess, struct connection *conn)
+{
+ struct sess_priv_conns *pconns;
+ int ret = 0;
+
+ /* This function is reserved for idle private connections. */
+ BUG_ON(!(conn->flags & CO_FL_SESS_IDLE));
+
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+
+ pconns = sess_get_sess_conns(sess, conn->target);
+ if (!pconns) {
+ pconns = sess_alloc_sess_conns(sess, conn->target);
+ if (!pconns)
+ goto out;
+ }
+
+ LIST_APPEND(&pconns->conn_list, &conn->sess_el);
+ ++sess->idle_conns;
+ ret = 1;
+
+ out:
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ return ret;
+}
+
/* Check that session <sess> is able to keep idle connection <conn>. This must
* be called each time a connection stored in a session becomes idle.
*
#endif
leave:
if (!ret && conn_in_list) {
- struct server *srv = __objt_server(conn->target);
-
- if (!(srv->cur_admin & SRV_ADMF_MAINT)) {
- TRACE_DEVEL("adding conn back to idle list", SSL_EV_CONN_IO_CB, conn);
- HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
- _srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ struct server *srv = objt_server(conn->target);
+
+ /* Connection is idle which means MUX layer is already initialized. */
+ BUG_ON(!conn->mux);
+
+ if (!srv || !(srv->cur_admin & SRV_ADMF_MAINT)) {
+ if (conn->flags & CO_FL_SESS_IDLE) {
+ TRACE_DEVEL("adding conn back to session list", SSL_EV_CONN_IO_CB, conn);
+ if (!session_reinsert_idle_conn(conn->owner, conn)) {
+ /* session add conn failure */
+ conn->mux->destroy(conn->ctx);
+ t = NULL;
+ }
+ }
+ else {
+ TRACE_DEVEL("adding conn back to idle list", SSL_EV_CONN_IO_CB, conn);
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ _srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ }
}
else {
/* Do not store an idle conn if server in maintenance. */
-
- /* Connection is idle which means MUX layer is already initialized. */
- BUG_ON(!conn->mux);
conn->mux->destroy(conn->ctx);
t = NULL;
}