diff --git a/src/server.c b/src/server.c index df24612f5..197600ebd 100644 --- a/src/server.c +++ b/src/server.c @@ -5796,7 +5796,7 @@ int srv_check_for_deletion(const char *bename, const char *svname, struct proxy * TODO idle connections should not prevent server deletion. A proper * cleanup function should be implemented to be used here. */ - if (srv->cur_sess || srv->curr_idle_conns || + if (srv->curr_used_conns || srv->curr_idle_conns || !eb_is_empty(&srv->queue.head) || srv_has_streams(srv)) { msg = "Server still has connections attached to it, cannot remove it."; goto leave; diff --git a/src/stream.c b/src/stream.c index 54c70ecba..40756e6ae 100644 --- a/src/stream.c +++ b/src/stream.c @@ -2681,6 +2681,20 @@ void sess_change_server(struct stream *strm, struct server *newsrv) { struct server *oldsrv = strm->srv_conn; + /* Dynamic servers may be deleted during process lifetime. This + * operation is always conducted under thread isolation. Several + * conditions prevent deletion, one of them is if server streams list + * is not empty. sess_change_server() uses stream_add_srv_conn() to + * ensure the latter condition. + * + * A race condition could exist for stream which referenced a server + * instance (s->target) without registering itself in its server list. + * This is notably the case for SF_DIRECT streams which referenced a + * server earlier during process_stream(). However at this time the + * code is deemed safe as process_stream() cannot be rescheduled before + * invocation of sess_change_server(). + */ + if (oldsrv == newsrv) return;