tools/xenstore: let check_store() check the accounting data

Today check_store() is only testing the correctness of the node tree.

Add verification of the accounting data (number of nodes) and correct
the data if it is wrong.

Do the initial check_store() call only after Xenstore entries of a
live update have been read. This is wanted to make sure the accounting
data is correct after a live update.

Signed-off-by: Juergen Gross <jgross@suse.com>
Reviewed-by: Julien Grall <jgrall@amazon.com>
This commit is contained in:
Juergen Gross authored and Julien Grall committed 2023-01-20 09:23:51 +00:00
1 parent 1d2355d1c6
commit 67617067f0
3 files changed
+137 -15

No files matched your search

+47 -15
View File
@@ -2384,8 +2384,6 @@ void setup_structure(bool live_update)
manual_node("@introduceDomain", NULL);
domain_nbentry_fix(dom0_domid, 5, true);
}
check_store();
}
static unsigned int hash_from_key_fn(void *k)
@@ -2428,20 +2426,28 @@ int remember_string(struct hashtable *hash, const char *str)
* As we go, we record each node in the given reachable hashtable. These
* entries will be used later in clean_store.
*/
struct check_store_data {
struct hashtable *reachable;
struct hashtable *domains;
};
static int check_store_step(const void *ctx, struct connection *conn,
struct node *node, void *arg)
{
struct hashtable *reachable = arg;
struct check_store_data *data = arg;
if (hashtable_search(reachable, (void *)node->name)) {
if (hashtable_search(data->reachable, (void *)node->name)) {
log("check_store: '%s' is duplicated!", node->name);
return recovery ? WALK_TREE_RM_CHILDENTRY
: WALK_TREE_SKIP_CHILDREN;
}
if (!remember_string(reachable, node->name))
if (!remember_string(data->reachable, node->name))
return WALK_TREE_ERROR_STOP;
domain_check_acc_add(node, data->domains);
return WALK_TREE_OK;
}
@@ -2491,37 +2497,61 @@ static int clean_store_(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA val,
* Given the list of reachable nodes, iterate over the whole store, and
* remove any that were not reached.
*/
static void clean_store(struct hashtable *reachable)
static void clean_store(struct check_store_data *data)
{
tdb_traverse(tdb_ctx, &clean_store_, reachable);
tdb_traverse(tdb_ctx, &clean_store_, data->reachable);
domain_check_acc(data->domains);
}
int check_store_path(const char *name, struct check_store_data *data)
{
struct node *node;
node = read_node(NULL, NULL, name);
if (!node) {
log("check_store: error %d reading special node '%s'", errno,
name);
return errno;
}
return check_store_step(NULL, NULL, node, data);
}
void check_store(void)
{
struct hashtable *reachable;
struct walk_funcs walkfuncs = {
.enter = check_store_step,
.enoent = check_store_enoent,
};
struct check_store_data data;
/* Don't free values (they are all void *1) */
reachable = create_hashtable(NULL, 16, hash_from_key_fn, keys_equal_fn,
HASHTABLE_FREE_KEY);
if (!reachable) {
data.reachable = create_hashtable(NULL, 16, hash_from_key_fn,
keys_equal_fn, HASHTABLE_FREE_KEY);
if (!data.reachable) {
log("check_store: ENOMEM");
return;
}
data.domains = domain_check_acc_init();
if (!data.domains) {
log("check_store: ENOMEM");
goto out_hash;
}
log("Checking store ...");
if (walk_node_tree(NULL, NULL, "/", &walkfuncs, reachable)) {
if (walk_node_tree(NULL, NULL, "/", &walkfuncs, &data)) {
if (errno == ENOMEM)
log("check_store: ENOMEM");
} else if (!check_transactions(reachable))
clean_store(reachable);
} else if (!check_store_path("@introduceDomain", &data) &&
!check_store_path("@releaseDomain", &data) &&
!check_transactions(data.reachable))
clean_store(&data);
log("Checking store complete.");
hashtable_destroy(reachable);
hashtable_destroy(data.domains);
out_hash:
hashtable_destroy(data.reachable);
}
@@ -2920,6 +2950,8 @@ int main(int argc, char *argv[])
lu_read_state();
#endif
check_store();
/* Get ready to listen to the tools. */
initialize_fds(&sock_pollfd_idx, &timeout);
+86
View File
@@ -1574,6 +1574,92 @@ void read_state_connection(const void *ctx, const void *state)
read_state_buffered_data(ctx, conn, sc);
}
struct domain_acc {
unsigned int domid;
int nodes;
};
static int domain_check_acc_init_sub(const void *k, void *v, void *arg)
{
struct hashtable *domains = arg;
struct domain *d = v;
struct domain_acc *dom;
dom = talloc_zero(NULL, struct domain_acc);
if (!dom)
return -1;
dom->domid = d->domid;
/*
* Set the initial value to the negative one of the current domain.
* If everything is correct incrementing the value for each node will
* result in dom->nodes being 0 at the end.
*/
dom->nodes = -d->nbentry;
if (!hashtable_insert(domains, &dom->domid, dom)) {
talloc_free(dom);
return -1;
}
return 0;
}
struct hashtable *domain_check_acc_init(void)
{
struct hashtable *domains;
domains = create_hashtable(NULL, 8, domhash_fn, domeq_fn,
HASHTABLE_FREE_VALUE);
if (!domains)
return NULL;
if (hashtable_iterate(domhash, domain_check_acc_init_sub, domains)) {
hashtable_destroy(domains);
return NULL;
}
return domains;
}
void domain_check_acc_add(const struct node *node, struct hashtable *domains)
{
struct domain_acc *dom;
unsigned int domid;
domid = get_node_owner(node);
dom = hashtable_search(domains, &domid);
if (!dom)
log("Node %s owned by unknown domain %u", node->name, domid);
else
dom->nodes++;
}
static int domain_check_acc_cb(const void *k, void *v, void *arg)
{
struct domain_acc *dom = v;
struct domain *d;
if (!dom->nodes)
return 0;
log("Correct accounting data for domain %u: nodes are %d off",
dom->domid, dom->nodes);
d = find_domain_struct(dom->domid);
if (!d)
return 0;
d->nbentry += dom->nodes;
return 0;
}
void domain_check_acc(struct hashtable *domains)
{
hashtable_iterate(domains, domain_check_acc_cb, NULL);
}
/*
* Local variables:
* mode: C
+4
View File
@@ -129,4 +129,8 @@ const char *dump_state_connections(FILE *fp);
void read_state_connection(const void *ctx, const void *state);
struct hashtable *domain_check_acc_init(void);
void domain_check_acc_add(const struct node *node, struct hashtable *domains);
void domain_check_acc(struct hashtable *domains);
#endif /* _XENSTORED_DOMAIN_H */
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.