From d6a64882a06c364ef17b54b259007e5b07d4d7f0 Mon Sep 17 00:00:00 2001
From: George Dunlap <george.dunlap@cloud.com>
Date: Fri, 13 Oct 2023 10:55:53 +0100
Subject: [PATCH] cxenstored: Wait until after reset to notify dom0less domains

Commit fc2b57c9a ("xenstored: send an evtchn notification on
introduce_domain") introduced the sending of an event channel to the
guest when first introduced, so that dom0less domains waiting for the
connection would know that xenstore was ready to use.

Unfortunately, it was introduced in introduce_domain(), which 1) is
called by other functions, where such functionality is unneeded, and
2) after the main XS_INTRODUCE call, calls domain_conn_reset().  This
introduces a race condition, whereby if xenstored is delayed, a domain
can wake up, send messages to the buffer, only to have them deleted by
xenstore before finishing its processing of the XS_INTRODUCE message.

Move the connect-and-notfy call into do_introduce() instead, after the
domain_conn_rest(); predicated on the state being in the
XENSTORE_RECONNECT state.

(We don't need to check for "restoring", since that value is always
passed as "false" from do_domain_introduce()).

Signed-off-by: George Dunlap <george.dunlap@cloud.com>
---
I'm not familiar with this code, so this commit message has been
written using the "the fastest way to get the right answer is to post
the wrong answer" method.  If you know xenstored & the protocol,
please review if carefully for accuracy.
---
 tools/xenstored/domain.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/tools/xenstored/domain.c b/tools/xenstored/domain.c
index a6cd199fdc..addc34f5f8 100644
--- a/tools/xenstored/domain.c
+++ b/tools/xenstored/domain.c
@@ -988,12 +988,6 @@ static struct domain *introduce_domain(const void *ctx,
 		/* Now domain belongs to its connection. */
 		talloc_steal(domain->conn, domain);
 
-		if (!restore) {
-			/* Notify the domain that xenstore is available */
-			interface->connection = XENSTORE_CONNECTED;
-			xenevtchn_notify(xce_handle, domain->port);
-		}
-
 		if (!is_master_domain && !restore)
 			fire_special_watches("@introduceDomain");
 	} else {
@@ -1033,6 +1027,12 @@ int do_introduce(const void *ctx, struct connection *conn,
 
 	domain_conn_reset(domain);
 
+	if (interface->connection == XENSTORE_RECONNECT) {
+		/* Notify the domain that xenstore is available */
+		interface->connection = XENSTORE_CONNECTED;
+		xenevtchn_notify(xce_handle, domain->port);
+	}
+
 	send_ack(conn, XS_INTRODUCE);
 
 	return 0;
-- 
2.42.0

