commit 9e49dcf67f4aa3e318e618e51eeb547a117c3805
Author: Juergen Gross <jgross@suse.com>
Date:   Mon Dec 5 08:48:45 2016 +0100

    xenstore: add per-node generation counter
    
    In order to be able to support reading the list of a node's children in
    multiple chunks (needed for list sizes > 4096 bytes) without having to
    allocate a temporary buffer we need some kind of generation counter for
    each node. This will help to recognize a node has changed between
    reading two chunks.
    
    As removing a node and reintroducing it must result in different
    generation counts each generation value has to be globally unique. This
    can be ensured only by using a global 64 bit counter.
    
    For handling of transactions there is already such a counter available,
    it just has to be expanded to 64 bits and must be stored in each
    modified node.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Wei Liu <wei.liu2@citrix.com>

Index: xen-4.4.4-testing/tools/xenstore/xenstore_lib.h
===================================================================
--- xen-4.4.4-testing.orig/tools/xenstore/xenstore_lib.h
+++ xen-4.4.4-testing/tools/xenstore/xenstore_lib.h
@@ -44,6 +44,7 @@ struct xs_permissions
 
 /* Header of the node record in tdb. */
 struct xs_tdb_record_hdr {
+	uint64_t generation;
 	uint32_t num_perms;
 	uint32_t datalen;
 	uint32_t childlen;
Index: xen-4.4.4-testing/tools/xenstore/xenstored_core.c
===================================================================
--- xen-4.4.4-testing.orig/tools/xenstore/xenstored_core.c
+++ xen-4.4.4-testing/tools/xenstore/xenstored_core.c
@@ -432,6 +432,7 @@ static struct node *read_node(struct con
 
 	/* Datalen, childlen, number of permissions */
 	hdr = (void *)data.dptr;
+	node->generation = hdr->generation;
 	node->num_perms = hdr->num_perms;
 	node->datalen = hdr->datalen;
 	node->childlen = hdr->childlen;
@@ -471,6 +472,7 @@ static bool write_node(struct connection
 
 	data.dptr = talloc_size(node, data.dsize);
 	hdr = (void *)data.dptr;
+	hdr->generation = node->generation;
 	hdr->num_perms = node->num_perms;
 	hdr->datalen = node->datalen;
 	hdr->childlen = node->childlen;
Index: xen-4.4.4-testing/tools/xenstore/xenstored_core.h
===================================================================
--- xen-4.4.4-testing.orig/tools/xenstore/xenstored_core.h
+++ xen-4.4.4-testing/tools/xenstore/xenstored_core.h
@@ -107,6 +107,9 @@ struct node {
 	/* Parent (optional) */
 	struct node *parent;
 
+	/* Generation count. */
+	uint64_t generation;
+
 	/* Permissions. */
 	unsigned int num_perms;
 	struct xs_permissions *perms;
Index: xen-4.4.4-testing/tools/xenstore/xenstored_transaction.c
===================================================================
--- xen-4.4.4-testing.orig/tools/xenstore/xenstored_transaction.c
+++ xen-4.4.4-testing/tools/xenstore/xenstored_transaction.c
@@ -69,7 +69,10 @@ struct transaction
 	uint32_t id;
 
 	/* Generation when transaction started. */
-	unsigned int generation;
+	uint64_t generation;
+
+	/* Transaction internal generation. */
+	uint64_t trans_gen;
 
 	/* TDB to work on, and filename */
 	TDB_CONTEXT *tdb;
@@ -83,7 +86,7 @@ struct transaction
 };
 
 extern int quota_max_transaction;
-static unsigned int generation;
+static uint64_t generation;
 
 /* Return tdb context to use for this connection. */
 TDB_CONTEXT *tdb_transaction_context(struct transaction *trans)
@@ -100,12 +103,14 @@ void add_change_node(struct connection *
 
 	if (!conn || !conn->transaction) {
 		/* They're changing the global database. */
-		generation++;
+		node->generation = generation++;
 		return;
 	}
 
 	trans = conn->transaction;
 
+	node->generation = generation + trans->trans_gen++;
+
 	list_for_each_entry(i, &trans->changes, list) {
 		if (streq(i->node, node->name)) {
 			if (recurse)
@@ -162,7 +167,7 @@ void do_transaction_start(struct connect
 	}
 
 	/* Attach transaction to input for autofree until it's complete */
-	trans = talloc(in, struct transaction);
+	trans = talloc_zero(in, struct transaction);
 	INIT_LIST_HEAD(&trans->changes);
 	INIT_LIST_HEAD(&trans->changed_domains);
 	trans->generation = generation;
@@ -236,7 +241,7 @@ void do_transaction_end(struct connectio
 		/* Fire off the watches for everything that changed. */
 		list_for_each_entry(i, &trans->changes, list)
 			fire_watches(conn, in, i->node, i->recurse);
-		generation++;
+		generation += trans->trans_gen;
 	}
 	send_ack(conn, XS_TRANSACTION_END);
 }
