diff --git a/include/haproxy/server.h b/include/haproxy/server.h index 767764880..b39be2a1c 100644 --- a/include/haproxy/server.h +++ b/include/haproxy/server.h @@ -59,6 +59,7 @@ int srv_set_addr_via_libc(struct server *srv, int *err_code); int srv_init_addr(void); struct server *cli_find_server(struct appctx *appctx, char *arg); struct server *new_server(struct proxy *proxy); +void srv_use_dynsrv(struct server *srv); struct server *free_server(struct server *srv); int srv_init_per_thr(struct server *srv); diff --git a/src/server.c b/src/server.c index 583cce7f5..54a569f72 100644 --- a/src/server.c +++ b/src/server.c @@ -2197,7 +2197,7 @@ struct server *new_server(struct proxy *proxy) } /* Increment the dynamic server refcount. */ -static void srv_use_dynsrv(struct server *srv) +void srv_use_dynsrv(struct server *srv) { BUG_ON(!(srv->flags & SRV_F_DYNAMIC)); HA_ATOMIC_INC(&srv->refcount_dynsrv); diff --git a/src/stats.c b/src/stats.c index b767ce5d4..8140d87f9 100644 --- a/src/stats.c +++ b/src/stats.c @@ -3111,8 +3111,20 @@ int stats_dump_proxy_to_buffer(struct stream_interface *si, struct htx *htx, /* fall through */ case STAT_PX_ST_SV: - /* obj2 points to servers list as initialized above */ - for (; appctx->ctx.stats.obj2 != NULL; appctx->ctx.stats.obj2 = sv->next) { + /* obj2 points to servers list as initialized above. + * + * A dynamic server may be removed during the stats dumping. + * Temporarily increment its refcount to prevent its + * anticipated cleaning. Call free_server to release it. + */ + for (; appctx->ctx.stats.obj2 != NULL; + appctx->ctx.stats.obj2 = + (!(sv->flags & SRV_F_DYNAMIC)) ? sv->next : free_server(sv)) { + + sv = appctx->ctx.stats.obj2; + if (sv->flags & SRV_F_DYNAMIC) + srv_use_dynsrv(sv); + if (htx) { if (htx_almost_full(htx)) goto full; @@ -3122,11 +3134,12 @@ int stats_dump_proxy_to_buffer(struct stream_interface *si, struct htx *htx, goto full; } - sv = appctx->ctx.stats.obj2; - if (appctx->ctx.stats.flags & STAT_BOUND) { - if (!(appctx->ctx.stats.type & (1 << STATS_TYPE_SV))) + if (!(appctx->ctx.stats.type & (1 << STATS_TYPE_SV))) { + if (sv->flags & SRV_F_DYNAMIC) + free_server(appctx->ctx.stats.obj2); break; + } if (appctx->ctx.stats.sid != -1 && sv->puid != appctx->ctx.stats.sid) continue;