diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c index c30d14cbf2..55b79e4c03 100644 --- a/tools/xenstore/xenstored_core.c +++ b/tools/xenstore/xenstored_core.c @@ -562,15 +562,17 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node, return 0; } +/* + * Write the node. If the node is written, caller can find the key used in + * node->key. This can later be used if the change needs to be reverted. + */ static int write_node(struct connection *conn, struct node *node, bool no_quota_check) { - TDB_DATA key; - - if (access_node(conn, node, NODE_ACCESS_WRITE, &key)) + if (access_node(conn, node, NODE_ACCESS_WRITE, &node->key)) return errno; - return write_node_raw(conn, &key, node, no_quota_check); + return write_node_raw(conn, &node->key, node, no_quota_check); } unsigned int perm_for_conn(struct connection *conn, @@ -1086,16 +1088,21 @@ nomem: static int destroy_node(struct connection *conn, struct node *node) { - TDB_DATA key; - if (streq(node->name, "/")) corrupt(NULL, "Destroying root node!"); - set_tdb_key(node->name, &key); - tdb_delete(tdb_ctx, key); + tdb_delete(tdb_ctx, node->key); domain_entry_dec(conn, node); + /* + * It is not possible to easily revert the changes in a transaction. + * So if the failure happens in a transaction, mark it as fail to + * prevent any commit. + */ + if ( conn->transaction ) + fail_transaction(conn->transaction); + return 0; } diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h index 742812a974..7d0fe77e79 100644 --- a/tools/xenstore/xenstored_core.h +++ b/tools/xenstore/xenstored_core.h @@ -155,6 +155,8 @@ struct node_perms { struct node { const char *name; + /* Key used to update TDB */ + TDB_DATA key; /* Parent (optional) */ struct node *parent; diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c index cd07fb0f21..faf6c930e4 100644 --- a/tools/xenstore/xenstored_transaction.c +++ b/tools/xenstore/xenstored_transaction.c @@ -580,6 +580,11 @@ void transaction_entry_dec(struct transaction *trans, unsigned int domid) list_add_tail(&d->list, &trans->changed_domains); } +void fail_transaction(struct transaction *trans) +{ + trans->fail = true; +} + void conn_delete_all_transactions(struct connection *conn) { struct transaction *trans; diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h index 43a162bea3..14062730e3 100644 --- a/tools/xenstore/xenstored_transaction.h +++ b/tools/xenstore/xenstored_transaction.h @@ -46,6 +46,9 @@ int access_node(struct connection *conn, struct node *node, int transaction_prepend(struct connection *conn, const char *name, TDB_DATA *key); +/* Mark the transaction as failed. This will prevent it to be committed. */ +void fail_transaction(struct transaction *trans); + void conn_delete_all_transactions(struct connection *conn); int check_transactions(struct hashtable *hash);