MINOR: server: implement a refcount for dynamic servers

It is necessary to have a refcount mechanism on dynamic servers to be
able to enable check support. Indeed, when deleting a dynamic server
with check activated, the check will be asynchronously removed. This is
mandatory to properly free the check resources in a thread-safe manner.
The server instance must be kept alive for this.

(cherry picked from commit d6b7080cecee3450bbad8fbd5d9b100be0a2d13d)
[ad: move refcount increment in 'add server' handler, or else a leak
 might be present in case on error return from the handler with the
 server already allocated; this bug is not present in upstream because
 the increment is now done in new_server directly.]
Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
diff --git a/include/haproxy/server-t.h b/include/haproxy/server-t.h
index ef91ee9..cd95f9e 100644
--- a/include/haproxy/server-t.h
+++ b/include/haproxy/server-t.h
@@ -258,6 +258,8 @@
 	unsigned cumulative_weight;		/* weight of servers prior to this one in the same group, for chash balancing */
 	int maxqueue;				/* maximum number of pending connections allowed */
 
+	uint refcount_dynsrv;                   /* refcount used for dynamic servers */
+
 	/* The elements below may be changed on every single request by any
 	 * thread, and generally at the same time.
 	 */
diff --git a/src/server.c b/src/server.c
index a9251af..b9f3915 100644
--- a/src/server.c
+++ b/src/server.c
@@ -2203,10 +2203,32 @@
 	return srv;
 }
 
+/* Increment the dynamic server refcount. */
+static void srv_use_dynsrv(struct server *srv)
+{
+	BUG_ON(!(srv->flags & SRV_F_DYNAMIC));
+	HA_ATOMIC_INC(&srv->refcount_dynsrv);
+}
+
+/* Decrement the dynamic server refcount. */
+static uint srv_release_dynsrv(struct server *srv)
+{
+	BUG_ON(!(srv->flags & SRV_F_DYNAMIC));
+	return HA_ATOMIC_SUB_FETCH(&srv->refcount_dynsrv, 1);
+}
+
 /* Deallocate a server <srv> and its member. <srv> must be allocated.
  */
 void free_server(struct server *srv)
 {
+	/* For dynamic servers, decrement the reference counter. Only free the
+	 * server when reaching zero.
+	 */
+	if (srv->flags & SRV_F_DYNAMIC) {
+		if (srv_release_dynsrv(srv))
+			return;
+	}
+
 	task_destroy(srv->warmup);
 	task_destroy(srv->srvrq_check);
 
@@ -4428,6 +4450,9 @@
 
 	args[1] = sv_name;
 	errcode = _srv_parse_init(&srv, args, &argc, be, parse_flags, &errmsg);
+	if (srv)
+		srv_use_dynsrv(srv);
+
 	if (errcode) {
 		if (errmsg)
 			cli_dynerr(appctx, errmsg);