git: 590f093f74f2 - stable/13 - xen/blkback: fix reconnection of backend

From: Roger Pau Monné <royger_at_FreeBSD.org>
Date: Tue, 12 Apr 2022 08:07:04 UTC
The branch stable/13 has been updated by royger:

URL: https://cgit.FreeBSD.org/src/commit/?id=590f093f74f2f60f7a49f0b8707970189d2faaef

commit 590f093f74f2f60f7a49f0b8707970189d2faaef
Author:     Roger Pau Monné <royger@FreeBSD.org>
AuthorDate: 2021-05-11 10:19:29 +0000
Commit:     Roger Pau Monné <royger@FreeBSD.org>
CommitDate: 2022-04-12 08:05:47 +0000

    xen/blkback: fix reconnection of backend
    
    The hotplug script will be executed only once for each backend,
    regardless of the frontend triggering reconnections. Fix blkback to
    deal with the hotplug script being executed only once, so that
    reconnections don't stall waiting for a hotplug script execution
    that will never happen.
    
    As a result of the fix move the initialization of dev_mode, dev_type
    and dev_name to the watch callback, as they should be set only once
    the first time the backend connects.
    
    This fix is specially relevant for guests wanting to use UEFI OVMF
    firmware, because OVMF will use Xen PV block devices and disconnect
    afterwards, thus allowing them to be used by the guest OS. Without
    this change the guest OS will stall waiting for the block backed to
    attach.
    
    Fixes: de0bad00010c ('blkback: add support for hotplug scripts')
    Sponsored by: Citrix Systems R&D
    (cherry picked from commit 4772e86beb089ee08a3bff8ad359e83a4c623238)
---
 sys/dev/xen/blkback/blkback.c | 83 +++++++++++++++++++++++++------------------
 1 file changed, 48 insertions(+), 35 deletions(-)

diff --git a/sys/dev/xen/blkback/blkback.c b/sys/dev/xen/blkback/blkback.c
index 678472cc2ab8..010e737740b8 100644
--- a/sys/dev/xen/blkback/blkback.c
+++ b/sys/dev/xen/blkback/blkback.c
@@ -3412,7 +3412,6 @@ xbb_shutdown(struct xbb_softc *xbb)
 		free(xbb->hotplug_watch.node, M_XENBLOCKBACK);
 		xbb->hotplug_watch.node = NULL;
 	}
-	xbb->hotplug_done = false;
 
 	if (xenbus_get_state(xbb->dev) < XenbusStateClosing)
 		xenbus_set_state(xbb->dev, XenbusStateClosing);
@@ -3597,39 +3596,14 @@ xbb_setup_sysctl(struct xbb_softc *xbb)
 }
 
 static void
-xbb_attach_disk(struct xs_watch *watch, const char **vec, unsigned int len)
+xbb_attach_disk(device_t dev)
 {
-	device_t		 dev;
 	struct xbb_softc	*xbb;
 	int			 error;
 
-	dev = (device_t) watch->callback_data;
 	xbb = device_get_softc(dev);
 
-	error = xs_gather(XST_NIL, xenbus_get_node(dev), "physical-device-path",
-	    NULL, &xbb->dev_name, NULL);
-	if (error != 0)
-		return;
-
-	xs_unregister_watch(watch);
-	free(watch->node, M_XENBLOCKBACK);
-	watch->node = NULL;
-
-	/* Collect physical device information. */
-	error = xs_gather(XST_NIL, xenbus_get_otherend_path(xbb->dev),
-			  "device-type", NULL, &xbb->dev_type,
-			  NULL);
-	if (error != 0)
-		xbb->dev_type = NULL;
-
-	error = xs_gather(XST_NIL, xenbus_get_node(dev),
-                          "mode", NULL, &xbb->dev_mode,
-                          NULL);
-	if (error != 0) {
-		xbb_attach_failed(xbb, error, "reading backend fields at %s",
-				  xenbus_get_node(dev));
-                return;
-        }
+	KASSERT(xbb->hotplug_done, ("Missing hotplug execution"));
 
 	/* Parse fopen style mode flags. */
 	if (strchr(xbb->dev_mode, 'w') == NULL)
@@ -3693,13 +3667,48 @@ xbb_attach_disk(struct xs_watch *watch, const char **vec, unsigned int len)
 		return;
 	}
 
-	xbb->hotplug_done = true;
-
 	/* The front end might be waiting for the backend, attach if so. */
 	if (xenbus_get_otherend_state(xbb->dev) == XenbusStateInitialised)
 		xbb_connect(xbb);
 }
 
+static void
+xbb_attach_cb(struct xs_watch *watch, const char **vec, unsigned int len)
+{
+	device_t dev;
+	struct xbb_softc *xbb;
+	int error;
+
+	dev = (device_t)watch->callback_data;
+	xbb = device_get_softc(dev);
+
+	error = xs_gather(XST_NIL, xenbus_get_node(dev), "physical-device-path",
+	    NULL, &xbb->dev_name, NULL);
+	if (error != 0)
+		return;
+
+	xs_unregister_watch(watch);
+	free(watch->node, M_XENBLOCKBACK);
+	watch->node = NULL;
+	xbb->hotplug_done = true;
+
+	/* Collect physical device information. */
+	error = xs_gather(XST_NIL, xenbus_get_otherend_path(dev), "device-type",
+	    NULL, &xbb->dev_type, NULL);
+	if (error != 0)
+		xbb->dev_type = NULL;
+
+	error = xs_gather(XST_NIL, xenbus_get_node(dev), "mode", NULL,
+	   &xbb->dev_mode, NULL);
+	if (error != 0) {
+		xbb_attach_failed(xbb, error, "reading backend fields at %s",
+		    xenbus_get_node(dev));
+		return;
+	}
+
+	xbb_attach_disk(dev);
+}
+
 /**
  * Attach to a XenBus device that has been claimed by our probe routine.
  *
@@ -3757,14 +3766,21 @@ xbb_attach(device_t dev)
 		return (error);
 	}
 
+	/* Tell the toolstack blkback has attached. */
+	xenbus_set_state(dev, XenbusStateInitWait);
+
+	if (xbb->hotplug_done) {
+		xbb_attach_disk(dev);
+		return (0);
+	}
+
 	/*
 	 * We need to wait for hotplug script execution before
 	 * moving forward.
 	 */
-	KASSERT(!xbb->hotplug_done, ("Hotplug scripts already executed"));
 	watch_path = xs_join(xenbus_get_node(xbb->dev), "physical-device-path");
 	xbb->hotplug_watch.callback_data = (uintptr_t)dev;
-	xbb->hotplug_watch.callback = xbb_attach_disk;
+	xbb->hotplug_watch.callback = xbb_attach_cb;
 	KASSERT(xbb->hotplug_watch.node == NULL, ("watch node already setup"));
 	xbb->hotplug_watch.node = strdup(sbuf_data(watch_path), M_XENBLOCKBACK);
 	/*
@@ -3782,9 +3798,6 @@ xbb_attach(device_t dev)
 		return (error);
 	}
 
-	/* Tell the toolstack blkback has attached. */
-	xenbus_set_state(dev, XenbusStateInitWait);
-
 	return (0);
 }