mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
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:
1 parent
1d2355d1c6
commit
67617067f0
3 files changed
+137
-15
No files matched your search
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||