summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmaury Denoyelle <adenoyelle@haproxy.com>2021-08-25 14:39:53 +0200
committerAmaury Denoyelle <adenoyelle@haproxy.com>2021-08-25 15:53:43 +0200
commit0a8d05d31cc30279f4636ae1025d9e43d53719c9 (patch)
treea1f17b1c3edc0a17f7b6cf791e24214f1deb25a8
parentf5c1e12e44e1caa0185e063daf00fb8841c2ed3d (diff)
downloadhaproxy-0a8d05d31cc30279f4636ae1025d9e43d53719c9.tar.gz
BUG/MINOR: stats: use refcount to protect dynamic server on dump
A dynamic server may be deleted at runtime at the same moment when the stats applet is pointing to it. Use the server refcount to prevent deletion in this case. This should be backported up to 2.4, with an observability period of 2 weeks. Note that it requires the dynamic server refcounting feature which has been implemented on 2.5; the following commits are required : - MINOR: server: implement a refcount for dynamic servers - BUG/MINOR: server: do not use refcount in free_server in stopping mode - MINOR: server: return the next srv instance on free_server
-rw-r--r--include/haproxy/server.h1
-rw-r--r--src/server.c2
-rw-r--r--src/stats.c23
3 files changed, 20 insertions, 6 deletions
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;