diff --git a/include/haproxy/proxy-t.h b/include/haproxy/proxy-t.h index fcf9732bd..c233d2909 100644 --- a/include/haproxy/proxy-t.h +++ b/include/haproxy/proxy-t.h @@ -247,6 +247,7 @@ enum PR_SRV_STATE_FILE { #define PR_FL_PAUSED 0x00000020 /* The proxy was paused at run time (reversible) */ #define PR_FL_CHECKED 0x00000040 /* The proxy configuration was fully checked (including postparsing checks) */ #define PR_FL_BE_UNPUBLISHED 0x00000080 /* The proxy cannot be targetted by content switching rules */ +#define PR_FL_DELETED 0x00000100 /* Proxy has been deleted and must be manipulated with care */ struct stream; @@ -508,6 +509,7 @@ struct proxy { struct guid_node guid; /* GUID global tree node */ struct mt_list watcher_list; /* list of elems which currently references this proxy instance (currently only used with backends) */ + uint refcount; /* refcount to keep proxy from being deleted during runtime */ EXTRA_COUNTERS(extra_counters_fe); EXTRA_COUNTERS(extra_counters_be); diff --git a/include/haproxy/proxy.h b/include/haproxy/proxy.h index fa19924f7..5b73b25d4 100644 --- a/include/haproxy/proxy.h +++ b/include/haproxy/proxy.h @@ -58,7 +58,7 @@ void stop_proxy(struct proxy *p); int stream_set_backend(struct stream *s, struct proxy *be); void deinit_proxy(struct proxy *p); -void free_proxy(struct proxy *p); +void proxy_drop(struct proxy *p); const char *proxy_cap_str(int cap); const char *proxy_mode_str(int mode); enum pr_mode str_to_proxy_mode(const char *mode); @@ -82,6 +82,7 @@ void proxy_unref_defaults(struct proxy *px); int setup_new_proxy(struct proxy *px, const char *name, unsigned int cap, char **errmsg); struct proxy *alloc_new_proxy(const char *name, unsigned int cap, char **errmsg); +void proxy_take(struct proxy *px); struct proxy *parse_new_proxy(const char *name, unsigned int cap, const char *file, int linenum, const struct proxy *defproxy); diff --git a/src/haproxy.c b/src/haproxy.c index 49640f6eb..9b13bd2f3 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -2814,7 +2814,7 @@ void deinit(void) while (p) { p0 = p; p = p->next; - free_proxy(p0); + proxy_drop(p0); }/* end while(p) */ /* we don't need to free sink_proxies_list nor cfg_log_forward proxies since diff --git a/src/hlua.c b/src/hlua.c index 52884221a..764c0fb84 100644 --- a/src/hlua.c +++ b/src/hlua.c @@ -14726,7 +14726,7 @@ static void hlua_deinit() lua_close(hlua_states[thr]); } - free_proxy(socket_proxy); + proxy_drop(socket_proxy); } REGISTER_POST_DEINIT(hlua_deinit); diff --git a/src/http_client.c b/src/http_client.c index 64fbc8707..762fc0946 100644 --- a/src/http_client.c +++ b/src/http_client.c @@ -1214,7 +1214,7 @@ err: if (err_code & ERR_CODE) { ha_alert("httpclient: cannot initialize: %s\n", errmsg); free(errmsg); - free_proxy(px); + proxy_drop(px); return NULL; } diff --git a/src/log.c b/src/log.c index 9fc0d86aa..f26079b22 100644 --- a/src/log.c +++ b/src/log.c @@ -3739,7 +3739,7 @@ void deinit_log_forward() while (p) { p0 = p; p = p->next; - free_proxy(p0); + proxy_drop(p0); } } diff --git a/src/proxy.c b/src/proxy.c index f9241ea1d..04982b705 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -456,9 +456,19 @@ void deinit_proxy(struct proxy *p) proxy_unref_defaults(p); } -/* deinit and free

proxy */ -void free_proxy(struct proxy *p) +/* Decrement

refcount and free it if null. For a default proxy instance, + * refcount is ignored and free is immediately performed. + */ +void proxy_drop(struct proxy *p) { + if (!p) + return; + + if (!(p->cap & PR_CAP_DEF)) { + if (HA_ATOMIC_SUB_FETCH(&p->refcount, 1)) + return; + } + deinit_proxy(p); ha_free(&p); } @@ -3211,6 +3221,8 @@ struct proxy *alloc_new_proxy(const char *name, unsigned int cap, char **errmsg) if (!setup_new_proxy(curproxy, name, cap, errmsg)) goto fail; + proxy_take(curproxy); + done: return curproxy; @@ -3225,6 +3237,13 @@ struct proxy *alloc_new_proxy(const char *name, unsigned int cap, char **errmsg) return NULL; } +/* Increment refcount. Does nothing for a default proxy instance. */ +void proxy_take(struct proxy *px) +{ + if (!(px->cap & PR_CAP_DEF)) + HA_ATOMIC_INC(&px->refcount); +} + /* post-check for proxies */ static int proxy_postcheck(struct proxy *px) { @@ -4955,8 +4974,8 @@ static int cli_parse_add_backend(char **args, char *payload, struct appctx *appc return 1; err: - /* free_proxy() ensures any potential refcounting on defpx is decremented. */ - free_proxy(px); + /* This ensures any potential refcounting on defpx is decremented. */ + proxy_drop(px); thread_release(); if (msg) { @@ -5053,6 +5072,8 @@ static int cli_parse_delete_backend(char **args, char *payload, struct appctx *a goto out; } + px->flags |= PR_FL_DELETED; + thread_release(); ha_notice("Backend deleted.\n"); diff --git a/src/resolvers.c b/src/resolvers.c index b8306d33d..5aa2a595f 100644 --- a/src/resolvers.c +++ b/src/resolvers.c @@ -2637,7 +2637,7 @@ static void resolvers_destroy(struct resolvers *resolvers) resolv_free_resolution(res); } - free_proxy(resolvers->px); + proxy_drop(resolvers->px); free(resolvers->id); free((char *)resolvers->conf.file); task_destroy(resolvers->t); @@ -3586,7 +3586,7 @@ out: err_free_conf_file: ha_free((void **)&r->conf.file); err_free_p: - free_proxy(p); + proxy_drop(p); err_free_r: ha_free(&r); return err_code; diff --git a/src/sink.c b/src/sink.c index 03f57abd8..e207db871 100644 --- a/src/sink.c +++ b/src/sink.c @@ -818,7 +818,7 @@ static void sink_free(struct sink *sink) } LIST_DEL_INIT(&sink->sink_list); // remove from parent list task_destroy(sink->forward_task); - free_proxy(sink->forward_px); + proxy_drop(sink->forward_px); ha_free(&sink->name); ha_free(&sink->desc); while (sink->sft) { @@ -866,7 +866,7 @@ static struct sink *sink_new_ringbuf(const char *id, const char *description, return sink; err: - free_proxy(p); + proxy_drop(p); return NULL; }