mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-07 15:47:01 +02:00
MINOR: listener: workaround for closing a tiny race between resume_listener() and stopping
This is an alternative fix that tries to address the same issue asd1ebee177
("BUG/MINOR: listener: close tiny race between resume_listener() and stopping") while allowing resume_listener() to be more versatile. Indeed, because of the previous fix, resume_listener() is not able to rebind stopped listeners, and this breaks the original behavior that is documented in the function description: "If the listener was only in the assigned state, it's totally rebound. This can happen if a pause() has completely stopped it. If the resume fails, 0 is returned and an error might be displayed." With relax_listener(), we now make sure to check l->state under the listener lock so we don't call resume_listener() when the conditions are not met. As such, concurrently stopped listeners may not be rebound using relax_listener(). Note: the documented race can't happen since1b927eb3c
("MEDIUM: proto: stop protocols under thread isolation during soft stop"), but older versions are concerned as1b927eb3c
was not marked for backports. Moreover, the patch also prevents the race between protocol_pause_all() and resuming from LIMITED or FULL states. This commit depends on: - "MINOR: listener: add relax_listener() function" This should be backported withd1ebee177
up to 2.4 (d1ebee177
is marked to be backported for all stable versions but the current patch does not apply for versions < 2.4)
This commit is contained in:
parent
bcad7e6319
commit
f5d98938ad
@ -538,10 +538,6 @@ int resume_listener(struct listener *l, int lpx, int lli)
|
|||||||
if (l->state == LI_READY)
|
if (l->state == LI_READY)
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
/* the listener might have been stopped in parallel */
|
|
||||||
if (l->state < LI_PAUSED)
|
|
||||||
goto end;
|
|
||||||
|
|
||||||
if (l->rx.proto->resume)
|
if (l->rx.proto->resume)
|
||||||
ret = l->rx.proto->resume(l);
|
ret = l->rx.proto->resume(l);
|
||||||
|
|
||||||
@ -599,7 +595,7 @@ int relax_listener(struct listener *l, int lpx, int lli)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Marks a ready listener as full so that the stream code tries to re-enable
|
/* Marks a ready listener as full so that the stream code tries to re-enable
|
||||||
* it upon next close() using resume_listener().
|
* it upon next close() using relax_listener().
|
||||||
*/
|
*/
|
||||||
static void listener_full(struct listener *l)
|
static void listener_full(struct listener *l)
|
||||||
{
|
{
|
||||||
@ -637,7 +633,7 @@ void dequeue_all_listeners()
|
|||||||
/* This cannot fail because the listeners are by definition in
|
/* This cannot fail because the listeners are by definition in
|
||||||
* the LI_LIMITED state.
|
* the LI_LIMITED state.
|
||||||
*/
|
*/
|
||||||
resume_listener(listener, 0, 0);
|
relax_listener(listener, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -650,7 +646,7 @@ void dequeue_proxy_listeners(struct proxy *px)
|
|||||||
/* This cannot fail because the listeners are by definition in
|
/* This cannot fail because the listeners are by definition in
|
||||||
* the LI_LIMITED state.
|
* the LI_LIMITED state.
|
||||||
*/
|
*/
|
||||||
resume_listener(listener, 0, 0);
|
relax_listener(listener, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1221,7 +1217,7 @@ void listener_accept(struct listener *l)
|
|||||||
(!tick_isset(global_listener_queue_task->expire) ||
|
(!tick_isset(global_listener_queue_task->expire) ||
|
||||||
tick_is_expired(global_listener_queue_task->expire, now_ms))))) {
|
tick_is_expired(global_listener_queue_task->expire, now_ms))))) {
|
||||||
/* at least one thread has to this when quitting */
|
/* at least one thread has to this when quitting */
|
||||||
resume_listener(l, 0, 0);
|
relax_listener(l, 0, 0);
|
||||||
|
|
||||||
/* Dequeues all of the listeners waiting for a resource */
|
/* Dequeues all of the listeners waiting for a resource */
|
||||||
dequeue_all_listeners();
|
dequeue_all_listeners();
|
||||||
@ -1280,7 +1276,7 @@ void listener_release(struct listener *l)
|
|||||||
_HA_ATOMIC_DEC(&l->thr_conn[tid]);
|
_HA_ATOMIC_DEC(&l->thr_conn[tid]);
|
||||||
|
|
||||||
if (l->state == LI_FULL || l->state == LI_LIMITED)
|
if (l->state == LI_FULL || l->state == LI_LIMITED)
|
||||||
resume_listener(l, 0, 0);
|
relax_listener(l, 0, 0);
|
||||||
|
|
||||||
/* Dequeues all of the listeners waiting for a resource */
|
/* Dequeues all of the listeners waiting for a resource */
|
||||||
dequeue_all_listeners();
|
dequeue_all_listeners();
|
||||||
|
@ -3035,7 +3035,7 @@ static int cli_parse_set_maxconn_frontend(char **args, char *payload, struct app
|
|||||||
px->maxconn = v;
|
px->maxconn = v;
|
||||||
list_for_each_entry(l, &px->conf.listeners, by_fe) {
|
list_for_each_entry(l, &px->conf.listeners, by_fe) {
|
||||||
if (l->state == LI_FULL)
|
if (l->state == LI_FULL)
|
||||||
resume_listener(l, 1, 0);
|
relax_listener(l, 1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (px->maxconn > px->feconn)
|
if (px->maxconn > px->feconn)
|
||||||
|
Loading…
Reference in New Issue
Block a user