MINOR: lb/api: let callers of take_conn/drop_conn tell if they have the lock

The two algos defining these functions (first and leastconn) do not need the
server's lock. However it's already present in pendconn_process_next_strm()
so the API must be updated so that the functions may take it if needed and
that the callers indicate whether they already own it.

As such, the call places (backend.c and stream.c) now do not take it
anymore, queue.c was unchanged since it's already held, and both "first"
and "leastconn" were updated to take it if not already held.

A quick test on the "first" algo showed a jump from 432 to 565k rps by
just dropping the lock in stream.c!

(cherry picked from commit 59b0fecfd9f2fe96f6a9c2d1d4fbe34f71adb6e3)
Signed-off-by: Willy Tarreau <w@1wt.eu>
diff --git a/include/haproxy/backend-t.h b/include/haproxy/backend-t.h
index 3e30240..8bee110 100644
--- a/include/haproxy/backend-t.h
+++ b/include/haproxy/backend-t.h
@@ -160,12 +160,15 @@
 	__decl_thread(HA_RWLOCK_T lock);
 	struct server *fbck;		/* first backup server when !PR_O_USE_ALL_BK, or NULL */
 
-	/* Call backs for some actions. Any of them may be NULL (thus should be ignored). */
-	void (*update_server_eweight)(struct server *);  /* to be called after eweight change */
-	void (*set_server_status_up)(struct server *);   /* to be called after status changes to UP */
-	void (*set_server_status_down)(struct server *); /* to be called after status changes to DOWN */
-	void (*server_take_conn)(struct server *);       /* to be called when connection is assigned */
-	void (*server_drop_conn)(struct server *);       /* to be called when connection is dropped */
+	/* Call backs for some actions. Any of them may be NULL (thus should be ignored).
+	 * Those marked "srvlock" will need to be called with the server lock held.
+	 * The other ones might take it themselves if needed, based on indications.
+	 */
+	void (*update_server_eweight)(struct server *);  /* to be called after eweight change // srvlock */
+	void (*set_server_status_up)(struct server *);   /* to be called after status changes to UP // srvlock */
+	void (*set_server_status_down)(struct server *); /* to be called after status changes to DOWN // srvlock */
+	void (*server_take_conn)(struct server *, int locked); /* to be called when connection is assigned */
+	void (*server_drop_conn)(struct server *, int locked); /* to be called when connection is dropped */
 };
 
 #endif /* _HAPROXY_BACKEND_T_H */
diff --git a/src/backend.c b/src/backend.c
index 62cb38c..522928e 100644
--- a/src/backend.c
+++ b/src/backend.c
@@ -1603,11 +1603,8 @@
 		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) {
-			HA_SPIN_LOCK(SERVER_LOCK, &srv->lock);
-			s->be->lbprm.server_take_conn(srv);
-			HA_SPIN_UNLOCK(SERVER_LOCK, &srv->lock);
-		}
+		if (s->be->lbprm.server_take_conn)
+			s->be->lbprm.server_take_conn(srv, 0);
 	}
 
 	/* Now handle synchronously connected sockets. We know the stream-int
diff --git a/src/lb_fas.c b/src/lb_fas.c
index e306065..3debfec 100644
--- a/src/lb_fas.c
+++ b/src/lb_fas.c
@@ -61,16 +61,23 @@
  * connection or after it has released one. Note that it is possible that
  * the server has been moved out of the tree due to failed health-checks.
  *
- * The server's lock must be held. The lbprm's lock will be used.
+ * <locked> must reflect the server's lock ownership. The lbprm's lock will
+ * be used.
  */
-static void fas_srv_reposition(struct server *s)
+static void fas_srv_reposition(struct server *s, int locked)
 {
+	if (!locked)
+		HA_SPIN_LOCK(SERVER_LOCK, &s->lock);
+
 	HA_RWLOCK_WRLOCK(LBPRM_LOCK, &s->proxy->lbprm.lock);
 	if (s->lb_tree) {
 		fas_dequeue_srv(s);
 		fas_queue_srv(s);
 	}
 	HA_RWLOCK_WRUNLOCK(LBPRM_LOCK, &s->proxy->lbprm.lock);
+
+	if (!locked)
+		HA_SPIN_UNLOCK(SERVER_LOCK, &s->lock);
 }
 
 /* This function updates the server trees according to server <srv>'s new
diff --git a/src/lb_fwlc.c b/src/lb_fwlc.c
index 630467b..4239a4c 100644
--- a/src/lb_fwlc.c
+++ b/src/lb_fwlc.c
@@ -67,16 +67,23 @@
  * connection or after it has released one. Note that it is possible that
  * the server has been moved out of the tree due to failed health-checks.
  *
- * The server's lock must be held. The lbprm's lock will be used.
+ * <locked> must reflect the server's lock ownership. The lbprm's lock will
+ * be used.
  */
-static void fwlc_srv_reposition(struct server *s)
+static void fwlc_srv_reposition(struct server *s, int locked)
 {
+	if (!locked)
+		HA_SPIN_LOCK(SERVER_LOCK, &s->lock);
+
 	HA_RWLOCK_WRLOCK(LBPRM_LOCK, &s->proxy->lbprm.lock);
 	if (s->lb_tree) {
 		fwlc_dequeue_srv(s);
 		fwlc_queue_srv(s, s->cur_eweight);
 	}
 	HA_RWLOCK_WRUNLOCK(LBPRM_LOCK, &s->proxy->lbprm.lock);
+
+	if (!locked)
+		HA_SPIN_UNLOCK(SERVER_LOCK, &s->lock);
 }
 
 /* This function updates the server trees according to server <srv>'s new
diff --git a/src/queue.c b/src/queue.c
index ea99761..8e603d4 100644
--- a/src/queue.c
+++ b/src/queue.c
@@ -327,7 +327,7 @@
 	_HA_ATOMIC_ADD(&srv->proxy->served, 1);
 	__ha_barrier_atomic_store();
 	if (px->lbprm.server_take_conn)
-		px->lbprm.server_take_conn(srv);
+		px->lbprm.server_take_conn(srv, 1);
 	stream_add_srv_conn(p->strm, srv);
 
 	task_wakeup(p->strm->task, TASK_WOKEN_RES);
diff --git a/src/stream.c b/src/stream.c
index 7b58e2a..7e33d82 100644
--- a/src/stream.c
+++ b/src/stream.c
@@ -2505,11 +2505,8 @@
 		_HA_ATOMIC_SUB(&oldsrv->served, 1);
 		_HA_ATOMIC_SUB(&oldsrv->proxy->served, 1);
 		__ha_barrier_atomic_store();
-		if (oldsrv->proxy->lbprm.server_drop_conn) {
-			HA_SPIN_LOCK(SERVER_LOCK, &oldsrv->lock);
-			oldsrv->proxy->lbprm.server_drop_conn(oldsrv);
-			HA_SPIN_UNLOCK(SERVER_LOCK, &oldsrv->lock);
-		}
+		if (oldsrv->proxy->lbprm.server_drop_conn)
+			oldsrv->proxy->lbprm.server_drop_conn(oldsrv, 0);
 		stream_del_srv_conn(sess);
 	}
 
@@ -2517,11 +2514,8 @@
 		_HA_ATOMIC_ADD(&newsrv->served, 1);
 		_HA_ATOMIC_ADD(&newsrv->proxy->served, 1);
 		__ha_barrier_atomic_store();
-		if (newsrv->proxy->lbprm.server_take_conn) {
-			HA_SPIN_LOCK(SERVER_LOCK, &newsrv->lock);
-			newsrv->proxy->lbprm.server_take_conn(newsrv);
-			HA_SPIN_UNLOCK(SERVER_LOCK, &newsrv->lock);
-		}
+		if (newsrv->proxy->lbprm.server_take_conn)
+			newsrv->proxy->lbprm.server_take_conn(newsrv, 0);
 		stream_add_srv_conn(sess, newsrv);
 	}
 }