From: Willy Tarreau Date: Sat, 24 Nov 2012 10:09:07 +0000 (+0100) Subject: BUG/MEDIUM: connection: always disable polling upon error X-Git-Tag: v1.5-dev14~13 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=36fb02c526a3583227780e0e682f6be403ff6562;p=thirdparty%2Fhaproxy.git BUG/MEDIUM: connection: always disable polling upon error Commit 0ffde2cc in 1.5-dev13 tried to always disable polling on file descriptors when errors were encountered. Unfortunately it did not always succeed in doing so because it relied on detecting polling changes to disable it. Let's use a dedicated conn_stop_polling() function that is inconditionally called upon error instead. This managed to stop a busy loop observed when a health check makes use of the send-proxy protocol and fails before the connection can be established. --- diff --git a/include/proto/connection.h b/include/proto/connection.h index 3bf337dcbd..35b6312bd5 100644 --- a/include/proto/connection.h +++ b/include/proto/connection.h @@ -180,6 +180,17 @@ static inline void conn_cond_update_sock_polling(struct connection *c) conn_update_sock_polling(c); } +/* Stop all polling on the fd. This might be used when an error is encountered + * for example. + */ +static inline void conn_stop_polling(struct connection *c) +{ + c->flags &= ~(CO_FL_CURR_RD_ENA | CO_FL_CURR_WR_ENA | + CO_FL_SOCK_RD_ENA | CO_FL_SOCK_WR_ENA | + CO_FL_DATA_RD_ENA | CO_FL_DATA_WR_ENA); + fd_stop_both(c->t.sock.fd); +} + /* Automatically update polling on connection depending on the DATA and * SOCK flags, and on whether a handshake is in progress or not. This may be * called at any moment when there is a doubt about the effectiveness of the @@ -187,7 +198,9 @@ static inline void conn_cond_update_sock_polling(struct connection *c) */ static inline void conn_cond_update_polling(struct connection *c) { - if (!(c->flags & CO_FL_POLL_SOCK) && conn_data_polling_changes(c)) + if (unlikely(c->flags & CO_FL_ERROR)) + conn_stop_polling(c); + else if (!(c->flags & CO_FL_POLL_SOCK) && conn_data_polling_changes(c)) conn_update_data_polling(c); else if ((c->flags & CO_FL_POLL_SOCK) && conn_sock_polling_changes(c)) conn_update_sock_polling(c); diff --git a/src/connection.c b/src/connection.c index 8038a74648..9549dbae1b 100644 --- a/src/connection.c +++ b/src/connection.c @@ -166,14 +166,6 @@ void conn_update_data_polling(struct connection *c) { unsigned int f = c->flags; - if (unlikely(f & CO_FL_ERROR)) { - c->flags &= ~(CO_FL_CURR_RD_ENA | CO_FL_CURR_WR_ENA | - CO_FL_SOCK_RD_ENA | CO_FL_SOCK_WR_ENA | - CO_FL_DATA_RD_ENA | CO_FL_DATA_WR_ENA); - fd_stop_both(c->t.sock.fd); - return; - } - /* update read status if needed */ if (unlikely((f & (CO_FL_DATA_RD_ENA|CO_FL_WAIT_RD)) == (CO_FL_DATA_RD_ENA|CO_FL_WAIT_RD))) { fd_poll_recv(c->t.sock.fd); @@ -214,14 +206,6 @@ void conn_update_sock_polling(struct connection *c) { unsigned int f = c->flags; - if (unlikely(f & CO_FL_ERROR)) { - c->flags &= ~(CO_FL_CURR_RD_ENA | CO_FL_CURR_WR_ENA | - CO_FL_SOCK_RD_ENA | CO_FL_SOCK_WR_ENA | - CO_FL_DATA_RD_ENA | CO_FL_DATA_WR_ENA); - fd_stop_both(c->t.sock.fd); - return; - } - /* update read status if needed */ if (unlikely((f & (CO_FL_SOCK_RD_ENA|CO_FL_WAIT_RD)) == (CO_FL_SOCK_RD_ENA|CO_FL_WAIT_RD))) { fd_poll_recv(c->t.sock.fd);