BUG/MEDIUM: lb: Always lock the server when calling server_{take,drop}_conn

The server lock must be held when server_take_conn() and server_drop_conn()
lbprm callback functions are called. It is a documented prerequisite but it is
not always performed. It only affects leastconn and fas lb algorithm. Others
don't use these callback functions.

A race condition on the next pending effecive weight (next_eweight) may be
encountered with the leastconn lb algorithm. An agent check may set it to 0
while fwlc_srv_reposition() is called. The server is locked during the
next_eweight update. But because the server lock is not acquired when
fwlc_srv_reposition() is called, we may use it to recompute the server key,
leading to a division by 0.

This patch must be backported as far as 1.8.

(cherry picked from commit 26a52af642c3fcfd6a637aef019b78147c05e126)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
(cherry picked from commit e50dd9f3dd622937e0b7bb4cbe7067c50e9a1f13)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
(cherry picked from commit ec879982c223757d9c192ee7ea20deb1c890267e)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
diff --git a/src/backend.c b/src/backend.c
index 75ebada..dc13d3a 100644
--- a/src/backend.c
+++ b/src/backend.c
@@ -1658,8 +1658,11 @@
 		s->flags |= SF_CURR_SESS;
 		count = _HA_ATOMIC_ADD(&srv->cur_sess, 1);
 		HA_ATOMIC_UPDATE_MAX(&srv->counters.cur_sess_max, count);
-		if (s->be->lbprm.server_take_conn)
+		if (s->be->lbprm.server_take_conn) {
+			HA_SPIN_LOCK(SERVER_LOCK, &srv->lock);
 			s->be->lbprm.server_take_conn(srv);
+			HA_SPIN_UNLOCK(SERVER_LOCK, &srv->lock);
+		}
 
 #ifdef USE_OPENSSL
 		if (srv->ssl_ctx.sni) {