[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[xen stable-4.13] tools/xenstore: fix node accounting after failed node creation



commit 2007c635cbf39351623e2fd0dcfa526184aff1e8
Author:     Juergen Gross <jgross@xxxxxxxx>
AuthorDate: Thu Jun 11 16:12:39 2020 +0200
Commit:     Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Tue Dec 15 14:18:33 2020 +0100

    tools/xenstore: fix node accounting after failed node creation
    
    When a node creation fails the number of nodes of the domain should be
    the same as before the failed node creation. In case of failure when
    trying to create a node requiring to create one or more intermediate
    nodes as well (e.g. when /a/b/c/d is to be created, but /a/b isn't
    existing yet) it might happen that the number of nodes of the creating
    domain is not reset to the value it had before.
    
    So move the quota accounting out of construct_node() and into the node
    write loop in create_node() in order to be able to undo the accounting
    in case of an error in the intermediate node destructor.
    
    This is part of XSA-115.
    
    Signed-off-by: Juergen Gross <jgross@xxxxxxxx>
    Reviewed-by: Paul Durrant <paul@xxxxxxx>
    Acked-by: Julien Grall <jgrall@xxxxxxxxxx>
---
 tools/xenstore/xenstored_core.c | 37 +++++++++++++++++++++++++------------
 1 file changed, 25 insertions(+), 12 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index bb2f9fd4e7..db9b9ca795 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -925,11 +925,6 @@ static struct node *construct_node(struct connection 
*conn, const void *ctx,
        if (!parent)
                return NULL;
 
-       if (domain_entry(conn) >= quota_nb_entry_per_domain) {
-               errno = ENOSPC;
-               return NULL;
-       }
-
        /* Add child to parent. */
        base = basename(name);
        baselen = strlen(base) + 1;
@@ -962,7 +957,6 @@ static struct node *construct_node(struct connection *conn, 
const void *ctx,
        node->children = node->data = NULL;
        node->childlen = node->datalen = 0;
        node->parent = parent;
-       domain_entry_inc(conn, node);
        return node;
 
 nomem:
@@ -982,6 +976,9 @@ static int destroy_node(void *_node)
        key.dsize = strlen(node->name);
 
        tdb_delete(tdb_ctx, key);
+
+       domain_entry_dec(talloc_parent(node), node);
+
        return 0;
 }
 
@@ -998,18 +995,34 @@ static struct node *create_node(struct connection *conn, 
const void *ctx,
        node->data = data;
        node->datalen = datalen;
 
-       /* We write out the nodes down, setting destructor in case
-        * something goes wrong. */
+       /*
+        * We write out the nodes bottom up.
+        * All new created nodes will have i->parent set, while the final
+        * node will be already existing and won't have i->parent set.
+        * New nodes are subject to quota handling.
+        * Initially set a destructor for all new nodes removing them from
+        * TDB again and undoing quota accounting for the case of an error
+        * during the write loop.
+        */
        for (i = node; i; i = i->parent) {
-               if (write_node(conn, i, false)) {
-                       domain_entry_dec(conn, i);
+               /* i->parent is set for each new node, so check quota. */
+               if (i->parent &&
+                   domain_entry(conn) >= quota_nb_entry_per_domain) {
+                       errno = ENOSPC;
                        return NULL;
                }
-               talloc_set_destructor(i, destroy_node);
+               if (write_node(conn, i, false))
+                       return NULL;
+
+               /* Account for new node, set destructor for error case. */
+               if (i->parent) {
+                       domain_entry_inc(conn, i);
+                       talloc_set_destructor(i, destroy_node);
+               }
        }
 
        /* OK, now remove destructors so they stay around */
-       for (i = node; i; i = i->parent)
+       for (i = node; i->parent; i = i->parent)
                talloc_set_destructor(i, NULL);
        return node;
 }
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.