|
commit 0fc2d46fabb2b9317daf7030162e828c7e1684d5
|
|
Author: Christopher Faulet <cfaulet@haproxy.com>
|
|
Date: Thu Aug 1 10:09:29 2019 +0200
|
|
|
|
BUG/MEDIUM: lb-chash: Ensure the tree integrity when server weight is increased
|
|
|
|
When the server weight is increased in consistant hash, extra nodes have to be
|
|
allocated. So a realloc() is performed on the nodes array of the server. the
|
|
previous commit 962ea7732 ("BUG/MEDIUM: lb-chash: Remove all server's entries
|
|
before realloc() to re-insert them after") have fixed the size used during the
|
|
realloc() to avoid segfaults. But another bug remains. After the realloc(), the
|
|
memory area allocated for the nodes array may change, invalidating all node
|
|
addresses in the chash tree.
|
|
|
|
So, to fix the bug, we must remove all server's entries from the chash tree
|
|
before the realloc to insert all of them after, old nodes and new ones. The
|
|
insert will be automatically handled by the loop at the end of the function
|
|
chash_queue_dequeue_srv().
|
|
|
|
Note that if the call to realloc() failed, no new entries will be created for
|
|
the server, so the effective server weight will be unchanged.
|
|
|
|
This issue was reported on Github (#189).
|
|
|
|
This patch must be backported to all versions since the 1.6.
|
|
|
|
(cherry picked from commit 0a52c17f819a5b0a17718b605bdd990b9e2b58e6)
|
|
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
|
|
|
|
diff --git a/src/lb_chash.c b/src/lb_chash.c
|
|
index 0bf4e81a..23448df8 100644
|
|
--- a/src/lb_chash.c
|
|
+++ b/src/lb_chash.c
|
|
@@ -84,8 +84,13 @@ static inline void chash_queue_dequeue_srv(struct server *s)
|
|
* increased the weight beyond the original weight
|
|
*/
|
|
if (s->lb_nodes_tot < s->next_eweight) {
|
|
- struct tree_occ *new_nodes = realloc(s->lb_nodes, s->next_eweight * sizeof(*new_nodes));
|
|
+ struct tree_occ *new_nodes;
|
|
|
|
+ /* First we need to remove all server's entries from its tree
|
|
+ * because the realloc will change all nodes pointers */
|
|
+ chash_dequeue_srv(s);
|
|
+
|
|
+ new_nodes = realloc(s->lb_nodes, s->next_eweight * sizeof(*new_nodes));
|
|
if (new_nodes) {
|
|
unsigned int j;
|
|
|
|
@@ -494,7 +499,6 @@ void chash_init_server_tree(struct proxy *p)
|
|
srv->lb_nodes_tot = srv->uweight * BE_WEIGHT_SCALE;
|
|
srv->lb_nodes_now = 0;
|
|
srv->lb_nodes = calloc(srv->lb_nodes_tot, sizeof(struct tree_occ));
|
|
-
|
|
for (node = 0; node < srv->lb_nodes_tot; node++) {
|
|
srv->lb_nodes[node].server = srv;
|
|
srv->lb_nodes[node].node.key = full_hash(srv->puid * SRV_EWGHT_RANGE + node);
|