From fe543c6b459f3b7988183b97a0739e1acdaa8e9f Mon Sep 17 00:00:00 2001 From: Frediano Ziglio Date: Tue, 15 Nov 2016 23:38:57 +0000 Subject: [PATCH] Fix node removal Avoid to produce loop in the tree removing and adding nodes. Unlink the node from the containing tree. This possibly will create unlinked trees if a parent node is deleted. What was happening is that the creation of loops inside the tree caused some statistical function to go into an infinite loop (and reds_stat tool too). Nodes were only invalidated but still linked so when reused the new node could point to an already existing node (like a sibling) which pointed to the new reused one. Signed-off-by: Frediano Ziglio Acked-by: Christophe Fergeau --- server/stat-file.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/server/stat-file.c b/server/stat-file.c index d688f804..7e35db0e 100644 --- a/server/stat-file.c +++ b/server/stat-file.c @@ -159,10 +159,35 @@ stat_file_add_counter(RedStatFile *stat_file, StatNodeRef parent, const char *na static void stat_file_remove(RedStatFile *stat_file, SpiceStatNode *node) { + const StatNodeRef node_ref = node - stat_file->stat->nodes; + const StatNodeRef node_next = node->next_sibling_index; + StatNodeRef ref; + pthread_mutex_lock(&stat_file->lock); node->flags &= ~SPICE_STAT_NODE_FLAG_ENABLED; stat_file->stat->generation++; stat_file->stat->num_of_nodes--; + /* remove links from parent or siblings */ + /* children will be orphans */ + if (stat_file->stat->root_index == node_ref) { + stat_file->stat->root_index = node_next; + } else for (ref = 0; ref <= stat_file->max_nodes; ref++) { + node = &stat_file->stat->nodes[ref]; + if (!(node->flags & SPICE_STAT_NODE_FLAG_ENABLED)) { + continue; + } + /* in a tree there is only a link from a parent or + * previous sibling so we can exit the loop as + * soon as we found on link */ + if (node->first_child_index == node_ref) { + node->first_child_index = node_next; + break; + } + if (node->next_sibling_index == node_ref) { + node->next_sibling_index = node_next; + break; + } + } pthread_mutex_unlock(&stat_file->lock); }