diff --git a/include/haproxy/server-t.h b/include/haproxy/server-t.h index ecf11e2d3..d3e49d81f 100644 --- a/include/haproxy/server-t.h +++ b/include/haproxy/server-t.h @@ -237,6 +237,7 @@ struct server { unsigned int pp_opts; /* proxy protocol options (SRV_PP_*) */ struct list global_list; /* attach point in the global servers_list */ struct server *next; + struct mt_list prev_deleted; /* deleted servers with 'next' ptr pointing to us */ int cklen; /* the len of the cookie, to speed up checks */ int rdr_len; /* the length of the redirection prefix */ char *cookie; /* the id set in the cookie */ diff --git a/src/server.c b/src/server.c index 6b6d867b3..1b52f36e6 100644 --- a/src/server.c +++ b/src/server.c @@ -2368,6 +2368,7 @@ struct server *new_server(struct proxy *proxy) LIST_APPEND(&servers_list, &srv->global_list); LIST_INIT(&srv->srv_rec_item); LIST_INIT(&srv->ip_rec_item); + MT_LIST_INIT(&srv->prev_deleted); event_hdl_sub_list_init(&srv->e_subs); srv->next_state = SRV_ST_RUNNING; /* early server setup */ @@ -2429,6 +2430,13 @@ struct server *srv_drop(struct server *srv) goto end; } + /* make sure we are removed from our 'next->prev_deleted' list + * This doesn't require full thread isolation as we're using mt lists + * However this could easily be turned into regular list if required + * (with the proper use of thread isolation) + */ + MT_LIST_DELETE(&srv->prev_deleted); + task_destroy(srv->warmup); task_destroy(srv->srvrq_check); @@ -4998,6 +5006,7 @@ static int cli_parse_delete_server(char **args, char *payload, struct appctx *ap struct proxy *be; struct server *srv; char *be_name, *sv_name; + struct server *prev_del; if (!cli_has_level(appctx, ACCESS_LVL_ADMIN)) return 1; @@ -5098,6 +5107,25 @@ static int cli_parse_delete_server(char **args, char *payload, struct appctx *ap next->next = srv->next; } + /* Some deleted servers could still point to us using their 'next', + * update them as needed + * Please note the small race between the POP and APPEND, although in + * this situation this is not an issue as we are under full thread + * isolation + */ + while ((prev_del = MT_LIST_POP(&srv->prev_deleted, struct server *, prev_deleted))) { + /* update its 'next' ptr */ + prev_del->next = srv->next; + if (srv->next) { + /* now it is our 'next' responsibility */ + MT_LIST_APPEND(&srv->next->prev_deleted, &prev_del->prev_deleted); + } + } + + /* we ourselves need to inform our 'next' that we will still point it */ + if (srv->next) + MT_LIST_APPEND(&srv->next->prev_deleted, &srv->prev_deleted); + /* remove srv from addr_node tree */ eb32_delete(&srv->conf.id); ebpt_delete(&srv->conf.name);