All of lore.kernel.org
 help / color / mirror / Atom feed
From: Paul Durrant <paul.durrant@citrix.com>
To: qemu-devel@nongnu.org, qemu-block@nongnu.org,
	xen-devel@lists.xenproject.org
Cc: Anthony Perard <anthony.perard@citrix.com>,
	Kevin Wolf <kwolf@redhat.com>,
	Paul Durrant <paul.durrant@citrix.com>,
	Stefano Stabellini <sstabellini@kernel.org>,
	Max Reitz <mreitz@redhat.com>
Subject: [PATCH v3 14/18] xen: add implementations of xen-block connect and disconnect functions...
Date: Tue, 11 Dec 2018 10:47:14 +0000	[thread overview]
Message-ID: <1544525238-3527-15-git-send-email-paul.durrant@citrix.com> (raw)
In-Reply-To: <1544525238-3527-1-git-send-email-paul.durrant@citrix.com>

...and wire in the dataplane.

This patch adds the remaining code to make the xen-block XenDevice
functional. The parameters that a block frontend expects to find are
populated in the backend xenstore area, and the 'ring-ref' and
'event-channel' values specified in the frontend xenstore area are
mapped/bound and used to set up the dataplane.

Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
---
Cc: Stefano Stabellini <sstabellini@kernel.org>
Cc: Anthony Perard <anthony.perard@citrix.com>
Cc: Kevin Wolf <kwolf@redhat.com>
Cc: Max Reitz <mreitz@redhat.com>

v3:
 - Add missing return statement to xen_block_realize()
 - Set device name to 'vbd' now the backend is functional
 - Add an unplug handler
 - Move backend watch code from subsequent patch since it's now needed
   to handle unplug

v2:
 - Tidy up header inclusions
 - Stop leaking ring_ref on error
 - Auto-create drive for CDRom devices
---
 hw/block/xen-block.c       | 166 ++++++++++++++++++++++++++++++++++++++++
 hw/xen/trace-events        |   3 +
 hw/xen/xen-bus.c           | 187 +++++++++++++++++++++++++++++++++++++++------
 include/hw/xen/xen-block.h |   9 +++
 include/hw/xen/xen-bus.h   |  14 +++-
 5 files changed, 353 insertions(+), 26 deletions(-)

diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c
index 5932672..f3d21c6 100644
--- a/hw/block/xen-block.c
+++ b/hw/block/xen-block.c
@@ -10,7 +10,13 @@
 #include "qapi/error.h"
 #include "qapi/visitor.h"
 #include "hw/hw.h"
+#include "hw/xen/xen_common.h"
+#include "hw/block/xen_blkif.h"
 #include "hw/xen/xen-block.h"
+#include "sysemu/blockdev.h"
+#include "sysemu/block-backend.h"
+#include "sysemu/iothread.h"
+#include "dataplane/xen-block.h"
 #include "trace.h"
 
 static char *xen_block_get_name(XenDevice *xendev, Error **errp)
@@ -28,6 +34,8 @@ static void xen_block_disconnect(XenDevice *xendev, Error **errp)
     XenBlockVdev *vdev = &blockdev->vdev;
 
     trace_xen_block_disconnect(type, vdev->disk, vdev->partition);
+
+    xen_block_dataplane_stop(blockdev->dataplane);
 }
 
 static void xen_block_connect(XenDevice *xendev, Error **errp)
@@ -35,8 +43,72 @@ static void xen_block_connect(XenDevice *xendev, Error **errp)
     XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
     const char *type = object_get_typename(OBJECT(blockdev));
     XenBlockVdev *vdev = &blockdev->vdev;
+    unsigned int order, nr_ring_ref, *ring_ref, event_channel, protocol;
+    char *str;
 
     trace_xen_block_connect(type, vdev->disk, vdev->partition);
+
+    if (xen_device_frontend_scanf(xendev, "ring-page-order", "%u",
+                                  &order) != 1) {
+        nr_ring_ref = 1;
+        ring_ref = g_new(unsigned int, nr_ring_ref);
+
+        if (xen_device_frontend_scanf(xendev, "ring-ref", "%u",
+                                      &ring_ref[0]) != 1) {
+            error_setg(errp, "failed to read ring-ref");
+            g_free(ring_ref);
+            return;
+        }
+    } else if (order <= blockdev->max_ring_page_order) {
+        unsigned int i;
+
+        nr_ring_ref = 1 << order;
+        ring_ref = g_new(unsigned int, nr_ring_ref);
+
+        for (i = 0; i < nr_ring_ref; i++) {
+            const char *key = g_strdup_printf("ring-ref%u", i);
+
+            if (xen_device_frontend_scanf(xendev, key, "%u",
+                                          &ring_ref[i]) != 1) {
+                error_setg(errp, "failed to read %s", key);
+                g_free((gpointer)key);
+                g_free(ring_ref);
+                return;
+            }
+
+            g_free((gpointer)key);
+        }
+    } else {
+        error_setg(errp, "invalid ring-page-order (%d)", order);
+        return;
+    }
+
+    if (xen_device_frontend_scanf(xendev, "event-channel", "%u",
+                                  &event_channel) != 1) {
+        error_setg(errp, "failed to read event-channel");
+        g_free(ring_ref);
+        return;
+    }
+
+    if (xen_device_frontend_scanf(xendev, "protocol", "%ms",
+                                  &str) != 1) {
+        protocol = BLKIF_PROTOCOL_NATIVE;
+    } else {
+        if (strcmp(str, XEN_IO_PROTO_ABI_X86_32) == 0) {
+            protocol = BLKIF_PROTOCOL_X86_32;
+        } else if (strcmp(str, XEN_IO_PROTO_ABI_X86_64) == 0) {
+            protocol = BLKIF_PROTOCOL_X86_64;
+        } else {
+            protocol = BLKIF_PROTOCOL_NATIVE;
+        }
+
+        free(str);
+    }
+
+    xen_block_dataplane_start(blockdev->dataplane, ring_ref, nr_ring_ref,
+                              event_channel, protocol, errp);
+
+    g_free(ring_ref);
 }
 
 static void xen_block_unrealize(XenDevice *xendev, Error **errp)
@@ -56,6 +128,9 @@ static void xen_block_unrealize(XenDevice *xendev, Error **errp)
     /* Disconnect from the frontend in case this has not already happened */
     xen_block_disconnect(xendev, NULL);
 
+    xen_block_dataplane_destroy(blockdev->dataplane);
+    blockdev->dataplane = NULL;
+
     if (blockdev_class->unrealize) {
         blockdev_class->unrealize(blockdev, errp);
     }
@@ -69,6 +144,7 @@ static void xen_block_realize(XenDevice *xendev, Error **errp)
     const char *type = object_get_typename(OBJECT(blockdev));
     XenBlockVdev *vdev = &blockdev->vdev;
     Error *local_err = NULL;
+    BlockConf *conf = &blockdev->conf;
 
     if (vdev->type == XEN_BLOCK_VDEV_TYPE_INVALID) {
         error_setg(errp, "vdev property not set");
@@ -81,8 +157,62 @@ static void xen_block_realize(XenDevice *xendev, Error **errp)
         blockdev_class->realize(blockdev, &local_err);
         if (local_err) {
             error_propagate(errp, local_err);
+            return;
         }
     }
+
+    /*
+     * The blkif protocol does not deal with removable media, so it must
+     * always be present, even for CDRom devices.
+     */
+    assert(conf->blk);
+    if (!blk_is_inserted(conf->blk)) {
+        error_setg(errp, "device needs media, but drive is empty");
+        return;
+    }
+
+    if (!blkconf_apply_backend_options(conf, blockdev->info & VDISK_READONLY,
+                                       false, errp)) {
+        return;
+    }
+
+    if (!(blockdev->info & VDISK_CDROM) &&
+        !blkconf_geometry(conf, NULL, 65535, 255, 255, errp)) {
+        return;
+    }
+
+    blkconf_blocksizes(conf);
+
+    if (conf->logical_block_size > conf->physical_block_size) {
+        error_setg(
+            errp, "logical_block_size > physical_block_size not supported");
+        return;
+    }
+
+    blk_set_guest_block_size(conf->blk, conf->logical_block_size);
+
+    if (conf->discard_granularity > 0) {
+        xen_device_backend_printf(xendev, "feature-discard", "%u", 1);
+    }
+
+    xen_device_backend_printf(xendev, "feature-flush-cache", "%u", 1);
+    xen_device_backend_printf(xendev, "max-ring-page-order", "%u",
+                              blockdev->max_ring_page_order);
+    xen_device_backend_printf(xendev, "info", "%u", blockdev->info);
+
+    xen_device_frontend_printf(xendev, "virtual-device", "%lu",
+                               vdev->number);
+    xen_device_frontend_printf(xendev, "device-type", "%s",
+                               blockdev->device_type);
+
+    xen_device_backend_printf(xendev, "sector-size", "%u",
+                              conf->logical_block_size);
+    xen_device_backend_printf(xendev, "sectors", "%lu",
+                              blk_getlength(conf->blk) /
+                              conf->logical_block_size);
+
+    blockdev->dataplane = xen_block_dataplane_create(xendev, conf,
+                                                     blockdev->iothread);
 }
 
 static void xen_block_frontend_changed(XenDevice *xendev,
@@ -331,6 +461,11 @@ const PropertyInfo xen_block_prop_vdev = {
 static Property xen_block_props[] = {
     DEFINE_PROP("vdev", XenBlockDevice, vdev,
                 xen_block_prop_vdev, XenBlockVdev),
+    DEFINE_BLOCK_PROPERTIES(XenBlockDevice, conf),
+    DEFINE_PROP_UINT32("max-ring-page-order", XenBlockDevice,
+                       max_ring_page_order, 4),
+    DEFINE_PROP_LINK("iothread", XenBlockDevice, iothread, TYPE_IOTHREAD,
+                     IOThread *),
     DEFINE_PROP_END_OF_LIST()
 };
 
@@ -339,6 +474,7 @@ static void xen_block_class_init(ObjectClass *class, void *data)
     DeviceClass *dev_class = DEVICE_CLASS(class);
     XenDeviceClass *xendev_class = XEN_DEVICE_CLASS(class);
 
+    xendev_class->device = "vbd";
     xendev_class->get_name = xen_block_get_name;
     xendev_class->realize = xen_block_realize;
     xendev_class->frontend_changed = xen_block_frontend_changed;
@@ -363,7 +499,18 @@ static void xen_disk_unrealize(XenBlockDevice *blockdev, Error **errp)
 
 static void xen_disk_realize(XenBlockDevice *blockdev, Error **errp)
 {
+    BlockConf *conf = &blockdev->conf;
+
     trace_xen_disk_realize();
+
+    blockdev->device_type = "disk";
+
+    if (!conf->blk) {
+        error_setg(errp, "drive property not set");
+        return;
+    }
+
+    blockdev->info = blk_is_read_only(conf->blk) ? VDISK_READONLY : 0;
 }
 
 static void xen_disk_class_init(ObjectClass *class, void *data)
@@ -391,7 +538,26 @@ static void xen_cdrom_unrealize(XenBlockDevice *blockdev, Error **errp)
 
 static void xen_cdrom_realize(XenBlockDevice *blockdev, Error **errp)
 {
+    BlockConf *conf = &blockdev->conf;
+
     trace_xen_cdrom_realize();
+
+    blockdev->device_type = "cdrom";
+
+    if (!conf->blk) {
+        int rc;
+
+        /* Set up an empty drive */
+        conf->blk = blk_new(0, BLK_PERM_ALL);
+
+        rc = blk_attach_dev(conf->blk, DEVICE(blockdev));
+        if (!rc) {
+            error_setg_errno(errp, -rc, "failed to create drive");
+            return;
+        }
+    }
+
+    blockdev->info = VDISK_READONLY | VDISK_CDROM;
 }
 
 static void xen_cdrom_class_init(ObjectClass *class, void *data)
diff --git a/hw/xen/trace-events b/hw/xen/trace-events
index 22055b5..d4651bd 100644
--- a/hw/xen/trace-events
+++ b/hw/xen/trace-events
@@ -22,8 +22,11 @@ xen_bus_watch(const char *token) "token: %s"
 xen_device_realize(const char *type, char *name) "type: %s name: %s"
 xen_device_unrealize(const char *type, char *name) "type: %s name: %s"
 xen_device_backend_state(const char *type, char *name, const char *state) "type: %s name: %s -> %s"
+xen_device_backend_online(const char *type, char *name, bool online) "type: %s name: %s -> %u"
+xen_device_backend_changed(const char *type, char *name) "type: %s name: %s"
 xen_device_frontend_state(const char *type, char *name, const char *state) "type: %s name: %s -> %s"
 xen_device_frontend_changed(const char *type, char *name) "type: %s name: %s"
+xen_device_unplug(const char *type, char *name) "type: %s name: %s"
 
 # include/hw/xen/xen-bus-helper.c
 xs_node_create(const char *node) "%s"
diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c
index 9443f27..a22aa49 100644
--- a/hw/xen/xen-bus.c
+++ b/hw/xen/xen-bus.c
@@ -48,6 +48,54 @@ static char *xen_device_get_frontend_path(XenDevice *xendev)
                            xendev->frontend_id, device, xendev->name);
 }
 
+static void xen_device_unplug(XenDevice *xendev, Error **errp)
+{
+    XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
+    const char *type = object_get_typename(OBJECT(xendev));
+    Error *local_err = NULL;
+    xs_transaction_t tid;
+
+    trace_xen_device_unplug(type, xendev->name);
+
+    /* Mimic the way the Xen toolstack does an unplug */
+again:
+    tid = xs_transaction_start(xenbus->xsh);
+    if (tid == XBT_NULL) {
+        error_setg_errno(errp, errno, "failed xs_transaction_start");
+        return;
+    }
+
+    xs_node_printf(xenbus->xsh, tid, xendev->backend_path, "online",
+                   &local_err, "%u", 0);
+    if (local_err) {
+        goto abort;
+    }
+
+    xs_node_printf(xenbus->xsh, tid, xendev->backend_path, "state",
+                   &local_err, "%u", XenbusStateClosing);
+    if (local_err) {
+        goto abort;
+    }
+
+    if (!xs_transaction_end(xenbus->xsh, tid, false)) {
+        if (errno == EAGAIN) {
+            goto again;
+        }
+
+        error_setg_errno(errp, errno, "failed xs_transaction_end");
+    }
+
+    return;
+
+abort:
+    /*
+     * We only abort if there is already a failure so ignore any error
+     * from ending the transaction.
+     */
+    xs_transaction_end(xenbus->xsh, tid, true);
+    error_propagate(errp, local_err);
+}
+
 static void xen_bus_print_dev(Monitor *mon, DeviceState *dev, int indent)
 {
     XenDevice *xendev = XEN_DEVICE(dev);
@@ -208,14 +256,26 @@ fail:
     xen_bus_unrealize(bus, &error_abort);
 }
 
+static void xen_bus_unplug_request(HotplugHandler *hotplug,
+                                   DeviceState *dev,
+                                   Error **errp)
+{
+    XenDevice *xendev = XEN_DEVICE(dev);
+
+    xen_device_unplug(xendev, errp);
+}
+
 static void xen_bus_class_init(ObjectClass *class, void *data)
 {
     BusClass *bus_class = BUS_CLASS(class);
+    HotplugHandlerClass *hotplug_class = HOTPLUG_HANDLER_CLASS(class);
 
     bus_class->print_dev = xen_bus_print_dev;
     bus_class->get_dev_path = xen_bus_get_dev_path;
     bus_class->realize = xen_bus_realize;
     bus_class->unrealize = xen_bus_unrealize;
+
+    hotplug_class->unplug_request = xen_bus_unplug_request;
 }
 
 static const TypeInfo xen_bus_type_info = {
@@ -230,8 +290,8 @@ static const TypeInfo xen_bus_type_info = {
     },
 };
 
-static void xen_device_backend_printf(XenDevice *xendev, const char *key,
-                                      const char *fmt, ...)
+void xen_device_backend_printf(XenDevice *xendev, const char *key,
+                               const char *fmt, ...)
 {
     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
     Error *local_err = NULL;
@@ -287,6 +347,70 @@ enum xenbus_state xen_device_backend_get_state(XenDevice *xendev)
     return xendev->backend_state;
 }
 
+static void xen_device_backend_set_online(XenDevice *xendev, bool online)
+{
+    const char *type = object_get_typename(OBJECT(xendev));
+
+    if (xendev->backend_online == online) {
+        return;
+    }
+
+    trace_xen_device_backend_online(type, xendev->name, online);
+
+    xendev->backend_online = online;
+    xen_device_backend_printf(xendev, "online", "%u", online);
+}
+
+static void xen_device_backend_changed(void *opaque)
+{
+    XenDevice *xendev = opaque;
+    const char *type = object_get_typename(OBJECT(xendev));
+    enum xenbus_state state;
+    unsigned int online;
+
+    trace_xen_device_backend_changed(type, xendev->name);
+
+    if (xen_device_backend_scanf(xendev, "state", "%u", &state) != 1) {
+        state = XenbusStateUnknown;
+    }
+
+    xen_device_backend_set_state(xendev, state);
+
+    if (xen_device_backend_scanf(xendev, "online", "%u", &online) != 1) {
+        online = 0;
+    }
+
+    xen_device_backend_set_online(xendev, !!online);
+
+    /*
+     * If the toolstack (or unplug request callback) has set the backend
+     * state to Closing, but there is no active frontend (i.e. the
+     * state is not Connected) then set the backend state to Closed.
+     */
+    if (xendev->backend_state == XenbusStateClosing &&
+        xendev->frontend_state != XenbusStateConnected) {
+        xen_device_backend_set_state(xendev, XenbusStateClosed);
+    }
+
+    /*
+     * If a backend is still 'online' then its state should be cycled
+     * back round to InitWait in order for a new frontend instance to
+     * connect. This may happen when, for example, a frontend driver is
+     * re-installed or updated.
+     * If a backend is not 'online' then the device should be destroyed.
+     */
+    if (xendev->backend_online &&
+        xendev->backend_state == XenbusStateClosed) {
+        xen_device_backend_set_state(xendev, XenbusStateInitWait);
+    } else if (!xendev->backend_online &&
+               (xendev->backend_state == XenbusStateClosed ||
+                xendev->backend_state == XenbusStateInitialising ||
+                xendev->backend_state == XenbusStateInitWait ||
+                xendev->backend_state == XenbusStateUnknown)) {
+        object_unparent(OBJECT(xendev));
+    }
+}
+
 static void xen_device_backend_create(XenDevice *xendev, Error **errp)
 {
     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
@@ -307,6 +431,27 @@ static void xen_device_backend_create(XenDevice *xendev, Error **errp)
     if (local_err) {
         error_propagate_prepend(errp, local_err,
                                 "failed to create backend: ");
+        return;
+    }
+
+    xendev->backend_state_watch =
+        xen_bus_add_watch(xenbus, xendev->backend_path,
+                          "state", xen_device_backend_changed,
+                          xendev, &local_err);
+    if (local_err) {
+        error_propagate_prepend(errp, local_err,
+                                "failed to watch backend state: ");
+        return;
+    }
+
+    xendev->backend_online_watch =
+        xen_bus_add_watch(xenbus, xendev->backend_path,
+                          "online", xen_device_backend_changed,
+                          xendev, &local_err);
+    if (local_err) {
+        error_propagate_prepend(errp, local_err,
+                                "failed to watch backend online: ");
+        return;
     }
 }
 
@@ -315,6 +460,16 @@ static void xen_device_backend_destroy(XenDevice *xendev)
     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
     Error *local_err = NULL;
 
+    if (xendev->backend_online_watch) {
+        xen_bus_remove_watch(xenbus, xendev->backend_online_watch, NULL);
+        xendev->backend_online_watch = NULL;
+    }
+
+    if (xendev->backend_state_watch) {
+        xen_bus_remove_watch(xenbus, xendev->backend_state_watch, NULL);
+        xendev->backend_state_watch = NULL;
+    }
+
     if (!xendev->backend_path) {
         return;
     }
@@ -331,8 +486,8 @@ static void xen_device_backend_destroy(XenDevice *xendev)
     }
 }
 
-static void xen_device_frontend_printf(XenDevice *xendev, const char *key,
-                                       const char *fmt, ...)
+void xen_device_frontend_printf(XenDevice *xendev, const char *key,
+                                const char *fmt, ...)
 {
     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
     Error *local_err = NULL;
@@ -350,8 +505,8 @@ static void xen_device_frontend_printf(XenDevice *xendev, const char *key,
     }
 }
 
-static int xen_device_frontend_scanf(XenDevice *xendev, const char *key,
-                                     const char *fmt, ...)
+int xen_device_frontend_scanf(XenDevice *xendev, const char *key,
+                              const char *fmt, ...)
 {
     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
     va_list ap;
@@ -407,24 +562,6 @@ static void xen_device_frontend_changed(void *opaque)
             error_reportf_err(local_err, "frontend change error: ");
         }
     }
-
-    /*
-     * If a backend is still 'online' then its state should be cycled
-     * back round to InitWait in order for a new frontend instance to
-     * connect. This may happen when, for example, a frontend driver is
-     * re-installed or updated.
-     */
-    if (xendev->backend_state == XenbusStateClosed) {
-        unsigned int online;
-
-        if (xen_device_backend_scanf(xendev, "online", "%u", &online) != 1) {
-            online = 0;
-        }
-
-        if (online) {
-            xen_device_backend_set_state(xendev, XenbusStateInitWait);
-        }
-    }
 }
 
 static void xen_device_frontend_create(XenDevice *xendev, Error **errp)
@@ -822,9 +959,9 @@ static void xen_device_realize(DeviceState *dev, Error **errp)
                               xendev->frontend_path);
     xen_device_backend_printf(xendev, "frontend-id", "%u",
                               xendev->frontend_id);
-    xen_device_backend_printf(xendev, "online", "%u", 1);
     xen_device_backend_printf(xendev, "hotplug-status", "connected");
 
+    xen_device_backend_set_online(xendev, true);
     xen_device_backend_set_state(xendev, XenbusStateInitWait);
 
     xen_device_frontend_printf(xendev, "backend", "%s",
diff --git a/include/hw/xen/xen-block.h b/include/hw/xen/xen-block.h
index 067932a..37ed8a6 100644
--- a/include/hw/xen/xen-block.h
+++ b/include/hw/xen/xen-block.h
@@ -9,6 +9,9 @@
 #define HW_XEN_BLOCK_H
 
 #include "hw/xen/xen-bus.h"
+#include "hw/block/block.h"
+#include "hw/block/dataplane/xen-block.h"
+#include "sysemu/iothread.h"
 
 typedef enum XenBlockVdevType {
     XEN_BLOCK_VDEV_TYPE_INVALID,
@@ -29,6 +32,12 @@ typedef struct XenBlockVdev {
 typedef struct XenBlockDevice {
     XenDevice xendev;
     XenBlockVdev vdev;
+    BlockConf conf;
+    const char *device_type;
+    unsigned int info;
+    unsigned int max_ring_page_order;
+    IOThread *iothread;
+    XenBlockDataPlane *dataplane;
 } XenBlockDevice;
 
 typedef void (*XenBlockDeviceRealize)(XenBlockDevice *blockdev, Error **errp);
diff --git a/include/hw/xen/xen-bus.h b/include/hw/xen/xen-bus.h
index f83a95c..0834cb3 100644
--- a/include/hw/xen/xen-bus.h
+++ b/include/hw/xen/xen-bus.h
@@ -23,7 +23,9 @@ typedef struct XenDevice {
     char *backend_path, *frontend_path;
     enum xenbus_state backend_state, frontend_state;
     Notifier exit;
-    XenWatch *frontend_state_watch;
+    XenWatch *backend_state_watch, *frontend_state_watch;
+    bool backend_online;
+    XenWatch *backend_online_watch;
     xengnttab_handle *xgth;
     bool feature_grant_copy;
     xenevtchn_handle *xeh;
@@ -84,6 +86,16 @@ void xen_device_backend_set_state(XenDevice *xendev,
                                   enum xenbus_state state);
 enum xenbus_state xen_device_backend_get_state(XenDevice *xendev);
 
+void xen_device_backend_printf(XenDevice *xendev, const char *key,
+                               const char *fmt, ...)
+    GCC_FMT_ATTR(3, 4);
+void xen_device_frontend_printf(XenDevice *xendev, const char *key,
+                                const char *fmt, ...)
+    GCC_FMT_ATTR(3, 4);
+
+int xen_device_frontend_scanf(XenDevice *xendev, const char *key,
+                              const char *fmt, ...);
+
 void xen_device_set_max_grant_refs(XenDevice *xendev, unsigned int nr_refs,
                                    Error **errp);
 void *xen_device_map_grant_refs(XenDevice *xendev, uint32_t *refs,
-- 
2.1.4


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

WARNING: multiple messages have this Message-ID (diff)
From: Paul Durrant <paul.durrant@citrix.com>
To: qemu-devel@nongnu.org, qemu-block@nongnu.org,
	xen-devel@lists.xenproject.org
Cc: Paul Durrant <paul.durrant@citrix.com>,
	Stefano Stabellini <sstabellini@kernel.org>,
	Anthony Perard <anthony.perard@citrix.com>,
	Kevin Wolf <kwolf@redhat.com>, Max Reitz <mreitz@redhat.com>
Subject: [Qemu-devel] [PATCH v3 14/18] xen: add implementations of xen-block connect and disconnect functions...
Date: Tue, 11 Dec 2018 10:47:14 +0000	[thread overview]
Message-ID: <1544525238-3527-15-git-send-email-paul.durrant@citrix.com> (raw)
In-Reply-To: <1544525238-3527-1-git-send-email-paul.durrant@citrix.com>

...and wire in the dataplane.

This patch adds the remaining code to make the xen-block XenDevice
functional. The parameters that a block frontend expects to find are
populated in the backend xenstore area, and the 'ring-ref' and
'event-channel' values specified in the frontend xenstore area are
mapped/bound and used to set up the dataplane.

Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
---
Cc: Stefano Stabellini <sstabellini@kernel.org>
Cc: Anthony Perard <anthony.perard@citrix.com>
Cc: Kevin Wolf <kwolf@redhat.com>
Cc: Max Reitz <mreitz@redhat.com>

v3:
 - Add missing return statement to xen_block_realize()
 - Set device name to 'vbd' now the backend is functional
 - Add an unplug handler
 - Move backend watch code from subsequent patch since it's now needed
   to handle unplug

v2:
 - Tidy up header inclusions
 - Stop leaking ring_ref on error
 - Auto-create drive for CDRom devices
---
 hw/block/xen-block.c       | 166 ++++++++++++++++++++++++++++++++++++++++
 hw/xen/trace-events        |   3 +
 hw/xen/xen-bus.c           | 187 +++++++++++++++++++++++++++++++++++++++------
 include/hw/xen/xen-block.h |   9 +++
 include/hw/xen/xen-bus.h   |  14 +++-
 5 files changed, 353 insertions(+), 26 deletions(-)

diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c
index 5932672..f3d21c6 100644
--- a/hw/block/xen-block.c
+++ b/hw/block/xen-block.c
@@ -10,7 +10,13 @@
 #include "qapi/error.h"
 #include "qapi/visitor.h"
 #include "hw/hw.h"
+#include "hw/xen/xen_common.h"
+#include "hw/block/xen_blkif.h"
 #include "hw/xen/xen-block.h"
+#include "sysemu/blockdev.h"
+#include "sysemu/block-backend.h"
+#include "sysemu/iothread.h"
+#include "dataplane/xen-block.h"
 #include "trace.h"
 
 static char *xen_block_get_name(XenDevice *xendev, Error **errp)
@@ -28,6 +34,8 @@ static void xen_block_disconnect(XenDevice *xendev, Error **errp)
     XenBlockVdev *vdev = &blockdev->vdev;
 
     trace_xen_block_disconnect(type, vdev->disk, vdev->partition);
+
+    xen_block_dataplane_stop(blockdev->dataplane);
 }
 
 static void xen_block_connect(XenDevice *xendev, Error **errp)
@@ -35,8 +43,72 @@ static void xen_block_connect(XenDevice *xendev, Error **errp)
     XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
     const char *type = object_get_typename(OBJECT(blockdev));
     XenBlockVdev *vdev = &blockdev->vdev;
+    unsigned int order, nr_ring_ref, *ring_ref, event_channel, protocol;
+    char *str;
 
     trace_xen_block_connect(type, vdev->disk, vdev->partition);
+
+    if (xen_device_frontend_scanf(xendev, "ring-page-order", "%u",
+                                  &order) != 1) {
+        nr_ring_ref = 1;
+        ring_ref = g_new(unsigned int, nr_ring_ref);
+
+        if (xen_device_frontend_scanf(xendev, "ring-ref", "%u",
+                                      &ring_ref[0]) != 1) {
+            error_setg(errp, "failed to read ring-ref");
+            g_free(ring_ref);
+            return;
+        }
+    } else if (order <= blockdev->max_ring_page_order) {
+        unsigned int i;
+
+        nr_ring_ref = 1 << order;
+        ring_ref = g_new(unsigned int, nr_ring_ref);
+
+        for (i = 0; i < nr_ring_ref; i++) {
+            const char *key = g_strdup_printf("ring-ref%u", i);
+
+            if (xen_device_frontend_scanf(xendev, key, "%u",
+                                          &ring_ref[i]) != 1) {
+                error_setg(errp, "failed to read %s", key);
+                g_free((gpointer)key);
+                g_free(ring_ref);
+                return;
+            }
+
+            g_free((gpointer)key);
+        }
+    } else {
+        error_setg(errp, "invalid ring-page-order (%d)", order);
+        return;
+    }
+
+    if (xen_device_frontend_scanf(xendev, "event-channel", "%u",
+                                  &event_channel) != 1) {
+        error_setg(errp, "failed to read event-channel");
+        g_free(ring_ref);
+        return;
+    }
+
+    if (xen_device_frontend_scanf(xendev, "protocol", "%ms",
+                                  &str) != 1) {
+        protocol = BLKIF_PROTOCOL_NATIVE;
+    } else {
+        if (strcmp(str, XEN_IO_PROTO_ABI_X86_32) == 0) {
+            protocol = BLKIF_PROTOCOL_X86_32;
+        } else if (strcmp(str, XEN_IO_PROTO_ABI_X86_64) == 0) {
+            protocol = BLKIF_PROTOCOL_X86_64;
+        } else {
+            protocol = BLKIF_PROTOCOL_NATIVE;
+        }
+
+        free(str);
+    }
+
+    xen_block_dataplane_start(blockdev->dataplane, ring_ref, nr_ring_ref,
+                              event_channel, protocol, errp);
+
+    g_free(ring_ref);
 }
 
 static void xen_block_unrealize(XenDevice *xendev, Error **errp)
@@ -56,6 +128,9 @@ static void xen_block_unrealize(XenDevice *xendev, Error **errp)
     /* Disconnect from the frontend in case this has not already happened */
     xen_block_disconnect(xendev, NULL);
 
+    xen_block_dataplane_destroy(blockdev->dataplane);
+    blockdev->dataplane = NULL;
+
     if (blockdev_class->unrealize) {
         blockdev_class->unrealize(blockdev, errp);
     }
@@ -69,6 +144,7 @@ static void xen_block_realize(XenDevice *xendev, Error **errp)
     const char *type = object_get_typename(OBJECT(blockdev));
     XenBlockVdev *vdev = &blockdev->vdev;
     Error *local_err = NULL;
+    BlockConf *conf = &blockdev->conf;
 
     if (vdev->type == XEN_BLOCK_VDEV_TYPE_INVALID) {
         error_setg(errp, "vdev property not set");
@@ -81,8 +157,62 @@ static void xen_block_realize(XenDevice *xendev, Error **errp)
         blockdev_class->realize(blockdev, &local_err);
         if (local_err) {
             error_propagate(errp, local_err);
+            return;
         }
     }
+
+    /*
+     * The blkif protocol does not deal with removable media, so it must
+     * always be present, even for CDRom devices.
+     */
+    assert(conf->blk);
+    if (!blk_is_inserted(conf->blk)) {
+        error_setg(errp, "device needs media, but drive is empty");
+        return;
+    }
+
+    if (!blkconf_apply_backend_options(conf, blockdev->info & VDISK_READONLY,
+                                       false, errp)) {
+        return;
+    }
+
+    if (!(blockdev->info & VDISK_CDROM) &&
+        !blkconf_geometry(conf, NULL, 65535, 255, 255, errp)) {
+        return;
+    }
+
+    blkconf_blocksizes(conf);
+
+    if (conf->logical_block_size > conf->physical_block_size) {
+        error_setg(
+            errp, "logical_block_size > physical_block_size not supported");
+        return;
+    }
+
+    blk_set_guest_block_size(conf->blk, conf->logical_block_size);
+
+    if (conf->discard_granularity > 0) {
+        xen_device_backend_printf(xendev, "feature-discard", "%u", 1);
+    }
+
+    xen_device_backend_printf(xendev, "feature-flush-cache", "%u", 1);
+    xen_device_backend_printf(xendev, "max-ring-page-order", "%u",
+                              blockdev->max_ring_page_order);
+    xen_device_backend_printf(xendev, "info", "%u", blockdev->info);
+
+    xen_device_frontend_printf(xendev, "virtual-device", "%lu",
+                               vdev->number);
+    xen_device_frontend_printf(xendev, "device-type", "%s",
+                               blockdev->device_type);
+
+    xen_device_backend_printf(xendev, "sector-size", "%u",
+                              conf->logical_block_size);
+    xen_device_backend_printf(xendev, "sectors", "%lu",
+                              blk_getlength(conf->blk) /
+                              conf->logical_block_size);
+
+    blockdev->dataplane = xen_block_dataplane_create(xendev, conf,
+                                                     blockdev->iothread);
 }
 
 static void xen_block_frontend_changed(XenDevice *xendev,
@@ -331,6 +461,11 @@ const PropertyInfo xen_block_prop_vdev = {
 static Property xen_block_props[] = {
     DEFINE_PROP("vdev", XenBlockDevice, vdev,
                 xen_block_prop_vdev, XenBlockVdev),
+    DEFINE_BLOCK_PROPERTIES(XenBlockDevice, conf),
+    DEFINE_PROP_UINT32("max-ring-page-order", XenBlockDevice,
+                       max_ring_page_order, 4),
+    DEFINE_PROP_LINK("iothread", XenBlockDevice, iothread, TYPE_IOTHREAD,
+                     IOThread *),
     DEFINE_PROP_END_OF_LIST()
 };
 
@@ -339,6 +474,7 @@ static void xen_block_class_init(ObjectClass *class, void *data)
     DeviceClass *dev_class = DEVICE_CLASS(class);
     XenDeviceClass *xendev_class = XEN_DEVICE_CLASS(class);
 
+    xendev_class->device = "vbd";
     xendev_class->get_name = xen_block_get_name;
     xendev_class->realize = xen_block_realize;
     xendev_class->frontend_changed = xen_block_frontend_changed;
@@ -363,7 +499,18 @@ static void xen_disk_unrealize(XenBlockDevice *blockdev, Error **errp)
 
 static void xen_disk_realize(XenBlockDevice *blockdev, Error **errp)
 {
+    BlockConf *conf = &blockdev->conf;
+
     trace_xen_disk_realize();
+
+    blockdev->device_type = "disk";
+
+    if (!conf->blk) {
+        error_setg(errp, "drive property not set");
+        return;
+    }
+
+    blockdev->info = blk_is_read_only(conf->blk) ? VDISK_READONLY : 0;
 }
 
 static void xen_disk_class_init(ObjectClass *class, void *data)
@@ -391,7 +538,26 @@ static void xen_cdrom_unrealize(XenBlockDevice *blockdev, Error **errp)
 
 static void xen_cdrom_realize(XenBlockDevice *blockdev, Error **errp)
 {
+    BlockConf *conf = &blockdev->conf;
+
     trace_xen_cdrom_realize();
+
+    blockdev->device_type = "cdrom";
+
+    if (!conf->blk) {
+        int rc;
+
+        /* Set up an empty drive */
+        conf->blk = blk_new(0, BLK_PERM_ALL);
+
+        rc = blk_attach_dev(conf->blk, DEVICE(blockdev));
+        if (!rc) {
+            error_setg_errno(errp, -rc, "failed to create drive");
+            return;
+        }
+    }
+
+    blockdev->info = VDISK_READONLY | VDISK_CDROM;
 }
 
 static void xen_cdrom_class_init(ObjectClass *class, void *data)
diff --git a/hw/xen/trace-events b/hw/xen/trace-events
index 22055b5..d4651bd 100644
--- a/hw/xen/trace-events
+++ b/hw/xen/trace-events
@@ -22,8 +22,11 @@ xen_bus_watch(const char *token) "token: %s"
 xen_device_realize(const char *type, char *name) "type: %s name: %s"
 xen_device_unrealize(const char *type, char *name) "type: %s name: %s"
 xen_device_backend_state(const char *type, char *name, const char *state) "type: %s name: %s -> %s"
+xen_device_backend_online(const char *type, char *name, bool online) "type: %s name: %s -> %u"
+xen_device_backend_changed(const char *type, char *name) "type: %s name: %s"
 xen_device_frontend_state(const char *type, char *name, const char *state) "type: %s name: %s -> %s"
 xen_device_frontend_changed(const char *type, char *name) "type: %s name: %s"
+xen_device_unplug(const char *type, char *name) "type: %s name: %s"
 
 # include/hw/xen/xen-bus-helper.c
 xs_node_create(const char *node) "%s"
diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c
index 9443f27..a22aa49 100644
--- a/hw/xen/xen-bus.c
+++ b/hw/xen/xen-bus.c
@@ -48,6 +48,54 @@ static char *xen_device_get_frontend_path(XenDevice *xendev)
                            xendev->frontend_id, device, xendev->name);
 }
 
+static void xen_device_unplug(XenDevice *xendev, Error **errp)
+{
+    XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
+    const char *type = object_get_typename(OBJECT(xendev));
+    Error *local_err = NULL;
+    xs_transaction_t tid;
+
+    trace_xen_device_unplug(type, xendev->name);
+
+    /* Mimic the way the Xen toolstack does an unplug */
+again:
+    tid = xs_transaction_start(xenbus->xsh);
+    if (tid == XBT_NULL) {
+        error_setg_errno(errp, errno, "failed xs_transaction_start");
+        return;
+    }
+
+    xs_node_printf(xenbus->xsh, tid, xendev->backend_path, "online",
+                   &local_err, "%u", 0);
+    if (local_err) {
+        goto abort;
+    }
+
+    xs_node_printf(xenbus->xsh, tid, xendev->backend_path, "state",
+                   &local_err, "%u", XenbusStateClosing);
+    if (local_err) {
+        goto abort;
+    }
+
+    if (!xs_transaction_end(xenbus->xsh, tid, false)) {
+        if (errno == EAGAIN) {
+            goto again;
+        }
+
+        error_setg_errno(errp, errno, "failed xs_transaction_end");
+    }
+
+    return;
+
+abort:
+    /*
+     * We only abort if there is already a failure so ignore any error
+     * from ending the transaction.
+     */
+    xs_transaction_end(xenbus->xsh, tid, true);
+    error_propagate(errp, local_err);
+}
+
 static void xen_bus_print_dev(Monitor *mon, DeviceState *dev, int indent)
 {
     XenDevice *xendev = XEN_DEVICE(dev);
@@ -208,14 +256,26 @@ fail:
     xen_bus_unrealize(bus, &error_abort);
 }
 
+static void xen_bus_unplug_request(HotplugHandler *hotplug,
+                                   DeviceState *dev,
+                                   Error **errp)
+{
+    XenDevice *xendev = XEN_DEVICE(dev);
+
+    xen_device_unplug(xendev, errp);
+}
+
 static void xen_bus_class_init(ObjectClass *class, void *data)
 {
     BusClass *bus_class = BUS_CLASS(class);
+    HotplugHandlerClass *hotplug_class = HOTPLUG_HANDLER_CLASS(class);
 
     bus_class->print_dev = xen_bus_print_dev;
     bus_class->get_dev_path = xen_bus_get_dev_path;
     bus_class->realize = xen_bus_realize;
     bus_class->unrealize = xen_bus_unrealize;
+
+    hotplug_class->unplug_request = xen_bus_unplug_request;
 }
 
 static const TypeInfo xen_bus_type_info = {
@@ -230,8 +290,8 @@ static const TypeInfo xen_bus_type_info = {
     },
 };
 
-static void xen_device_backend_printf(XenDevice *xendev, const char *key,
-                                      const char *fmt, ...)
+void xen_device_backend_printf(XenDevice *xendev, const char *key,
+                               const char *fmt, ...)
 {
     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
     Error *local_err = NULL;
@@ -287,6 +347,70 @@ enum xenbus_state xen_device_backend_get_state(XenDevice *xendev)
     return xendev->backend_state;
 }
 
+static void xen_device_backend_set_online(XenDevice *xendev, bool online)
+{
+    const char *type = object_get_typename(OBJECT(xendev));
+
+    if (xendev->backend_online == online) {
+        return;
+    }
+
+    trace_xen_device_backend_online(type, xendev->name, online);
+
+    xendev->backend_online = online;
+    xen_device_backend_printf(xendev, "online", "%u", online);
+}
+
+static void xen_device_backend_changed(void *opaque)
+{
+    XenDevice *xendev = opaque;
+    const char *type = object_get_typename(OBJECT(xendev));
+    enum xenbus_state state;
+    unsigned int online;
+
+    trace_xen_device_backend_changed(type, xendev->name);
+
+    if (xen_device_backend_scanf(xendev, "state", "%u", &state) != 1) {
+        state = XenbusStateUnknown;
+    }
+
+    xen_device_backend_set_state(xendev, state);
+
+    if (xen_device_backend_scanf(xendev, "online", "%u", &online) != 1) {
+        online = 0;
+    }
+
+    xen_device_backend_set_online(xendev, !!online);
+
+    /*
+     * If the toolstack (or unplug request callback) has set the backend
+     * state to Closing, but there is no active frontend (i.e. the
+     * state is not Connected) then set the backend state to Closed.
+     */
+    if (xendev->backend_state == XenbusStateClosing &&
+        xendev->frontend_state != XenbusStateConnected) {
+        xen_device_backend_set_state(xendev, XenbusStateClosed);
+    }
+
+    /*
+     * If a backend is still 'online' then its state should be cycled
+     * back round to InitWait in order for a new frontend instance to
+     * connect. This may happen when, for example, a frontend driver is
+     * re-installed or updated.
+     * If a backend is not 'online' then the device should be destroyed.
+     */
+    if (xendev->backend_online &&
+        xendev->backend_state == XenbusStateClosed) {
+        xen_device_backend_set_state(xendev, XenbusStateInitWait);
+    } else if (!xendev->backend_online &&
+               (xendev->backend_state == XenbusStateClosed ||
+                xendev->backend_state == XenbusStateInitialising ||
+                xendev->backend_state == XenbusStateInitWait ||
+                xendev->backend_state == XenbusStateUnknown)) {
+        object_unparent(OBJECT(xendev));
+    }
+}
+
 static void xen_device_backend_create(XenDevice *xendev, Error **errp)
 {
     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
@@ -307,6 +431,27 @@ static void xen_device_backend_create(XenDevice *xendev, Error **errp)
     if (local_err) {
         error_propagate_prepend(errp, local_err,
                                 "failed to create backend: ");
+        return;
+    }
+
+    xendev->backend_state_watch =
+        xen_bus_add_watch(xenbus, xendev->backend_path,
+                          "state", xen_device_backend_changed,
+                          xendev, &local_err);
+    if (local_err) {
+        error_propagate_prepend(errp, local_err,
+                                "failed to watch backend state: ");
+        return;
+    }
+
+    xendev->backend_online_watch =
+        xen_bus_add_watch(xenbus, xendev->backend_path,
+                          "online", xen_device_backend_changed,
+                          xendev, &local_err);
+    if (local_err) {
+        error_propagate_prepend(errp, local_err,
+                                "failed to watch backend online: ");
+        return;
     }
 }
 
@@ -315,6 +460,16 @@ static void xen_device_backend_destroy(XenDevice *xendev)
     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
     Error *local_err = NULL;
 
+    if (xendev->backend_online_watch) {
+        xen_bus_remove_watch(xenbus, xendev->backend_online_watch, NULL);
+        xendev->backend_online_watch = NULL;
+    }
+
+    if (xendev->backend_state_watch) {
+        xen_bus_remove_watch(xenbus, xendev->backend_state_watch, NULL);
+        xendev->backend_state_watch = NULL;
+    }
+
     if (!xendev->backend_path) {
         return;
     }
@@ -331,8 +486,8 @@ static void xen_device_backend_destroy(XenDevice *xendev)
     }
 }
 
-static void xen_device_frontend_printf(XenDevice *xendev, const char *key,
-                                       const char *fmt, ...)
+void xen_device_frontend_printf(XenDevice *xendev, const char *key,
+                                const char *fmt, ...)
 {
     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
     Error *local_err = NULL;
@@ -350,8 +505,8 @@ static void xen_device_frontend_printf(XenDevice *xendev, const char *key,
     }
 }
 
-static int xen_device_frontend_scanf(XenDevice *xendev, const char *key,
-                                     const char *fmt, ...)
+int xen_device_frontend_scanf(XenDevice *xendev, const char *key,
+                              const char *fmt, ...)
 {
     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
     va_list ap;
@@ -407,24 +562,6 @@ static void xen_device_frontend_changed(void *opaque)
             error_reportf_err(local_err, "frontend change error: ");
         }
     }
-
-    /*
-     * If a backend is still 'online' then its state should be cycled
-     * back round to InitWait in order for a new frontend instance to
-     * connect. This may happen when, for example, a frontend driver is
-     * re-installed or updated.
-     */
-    if (xendev->backend_state == XenbusStateClosed) {
-        unsigned int online;
-
-        if (xen_device_backend_scanf(xendev, "online", "%u", &online) != 1) {
-            online = 0;
-        }
-
-        if (online) {
-            xen_device_backend_set_state(xendev, XenbusStateInitWait);
-        }
-    }
 }
 
 static void xen_device_frontend_create(XenDevice *xendev, Error **errp)
@@ -822,9 +959,9 @@ static void xen_device_realize(DeviceState *dev, Error **errp)
                               xendev->frontend_path);
     xen_device_backend_printf(xendev, "frontend-id", "%u",
                               xendev->frontend_id);
-    xen_device_backend_printf(xendev, "online", "%u", 1);
     xen_device_backend_printf(xendev, "hotplug-status", "connected");
 
+    xen_device_backend_set_online(xendev, true);
     xen_device_backend_set_state(xendev, XenbusStateInitWait);
 
     xen_device_frontend_printf(xendev, "backend", "%s",
diff --git a/include/hw/xen/xen-block.h b/include/hw/xen/xen-block.h
index 067932a..37ed8a6 100644
--- a/include/hw/xen/xen-block.h
+++ b/include/hw/xen/xen-block.h
@@ -9,6 +9,9 @@
 #define HW_XEN_BLOCK_H
 
 #include "hw/xen/xen-bus.h"
+#include "hw/block/block.h"
+#include "hw/block/dataplane/xen-block.h"
+#include "sysemu/iothread.h"
 
 typedef enum XenBlockVdevType {
     XEN_BLOCK_VDEV_TYPE_INVALID,
@@ -29,6 +32,12 @@ typedef struct XenBlockVdev {
 typedef struct XenBlockDevice {
     XenDevice xendev;
     XenBlockVdev vdev;
+    BlockConf conf;
+    const char *device_type;
+    unsigned int info;
+    unsigned int max_ring_page_order;
+    IOThread *iothread;
+    XenBlockDataPlane *dataplane;
 } XenBlockDevice;
 
 typedef void (*XenBlockDeviceRealize)(XenBlockDevice *blockdev, Error **errp);
diff --git a/include/hw/xen/xen-bus.h b/include/hw/xen/xen-bus.h
index f83a95c..0834cb3 100644
--- a/include/hw/xen/xen-bus.h
+++ b/include/hw/xen/xen-bus.h
@@ -23,7 +23,9 @@ typedef struct XenDevice {
     char *backend_path, *frontend_path;
     enum xenbus_state backend_state, frontend_state;
     Notifier exit;
-    XenWatch *frontend_state_watch;
+    XenWatch *backend_state_watch, *frontend_state_watch;
+    bool backend_online;
+    XenWatch *backend_online_watch;
     xengnttab_handle *xgth;
     bool feature_grant_copy;
     xenevtchn_handle *xeh;
@@ -84,6 +86,16 @@ void xen_device_backend_set_state(XenDevice *xendev,
                                   enum xenbus_state state);
 enum xenbus_state xen_device_backend_get_state(XenDevice *xendev);
 
+void xen_device_backend_printf(XenDevice *xendev, const char *key,
+                               const char *fmt, ...)
+    GCC_FMT_ATTR(3, 4);
+void xen_device_frontend_printf(XenDevice *xendev, const char *key,
+                                const char *fmt, ...)
+    GCC_FMT_ATTR(3, 4);
+
+int xen_device_frontend_scanf(XenDevice *xendev, const char *key,
+                              const char *fmt, ...);
+
 void xen_device_set_max_grant_refs(XenDevice *xendev, unsigned int nr_refs,
                                    Error **errp);
 void *xen_device_map_grant_refs(XenDevice *xendev, uint32_t *refs,
-- 
2.1.4

  parent reply	other threads:[~2018-12-11 10:58 UTC|newest]

Thread overview: 56+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-12-11 10:47 [PATCH v3 00/18] Xen PV backend 'qdevification' Paul Durrant
2018-12-11 10:47 ` [Qemu-devel] " Paul Durrant
2018-12-11 10:47 ` [PATCH v3 01/18] xen: re-name XenDevice to XenLegacyDevice Paul Durrant
2018-12-11 10:47   ` [Qemu-devel] " Paul Durrant
2018-12-11 10:47 ` [PATCH v3 02/18] xen: introduce new 'XenBus' and 'XenDevice' object hierarchy Paul Durrant
2018-12-11 10:47 ` [Qemu-devel] " Paul Durrant
2018-12-11 10:47 ` [PATCH v3 03/18] xen: introduce 'xen-block', 'xen-disk' and 'xen-cdrom' Paul Durrant
2018-12-11 10:47   ` [Qemu-devel] " Paul Durrant
2018-12-11 15:16   ` Anthony PERARD
2018-12-11 15:16     ` [Qemu-devel] " Anthony PERARD
2018-12-11 15:40     ` Paul Durrant
2018-12-11 15:40       ` [Qemu-devel] " Paul Durrant
2018-12-11 10:47 ` [PATCH v3 04/18] xen: create xenstore areas for XenDevice-s Paul Durrant
2018-12-11 10:47   ` [Qemu-devel] " Paul Durrant
2018-12-11 15:19   ` Anthony PERARD
2018-12-11 15:19     ` [Qemu-devel] " Anthony PERARD
2018-12-11 10:47 ` [PATCH v3 05/18] xen: add xenstore watcher infrastructure Paul Durrant
2018-12-11 10:47   ` [Qemu-devel] " Paul Durrant
2018-12-11 15:21   ` Anthony PERARD
2018-12-11 15:21     ` [Qemu-devel] " Anthony PERARD
2018-12-11 10:47 ` [PATCH v3 06/18] xen: add grant table interface for XenDevice-s Paul Durrant
2018-12-11 10:47 ` [Qemu-devel] " Paul Durrant
2018-12-11 10:47 ` [Qemu-devel] [PATCH v3 07/18] xen: add event channel " Paul Durrant
2018-12-11 15:24   ` Anthony PERARD
2018-12-11 15:24     ` [Qemu-devel] " Anthony PERARD
2018-12-11 15:43     ` Paul Durrant
2018-12-11 15:43       ` [Qemu-devel] " Paul Durrant
2018-12-11 10:47 ` Paul Durrant
2018-12-11 10:47 ` [PATCH v3 08/18] xen: duplicate xen_disk.c as basis of dataplane/xen-block.c Paul Durrant
2018-12-11 10:47   ` [Qemu-devel] " Paul Durrant
2018-12-11 10:47 ` [PATCH v3 09/18] xen: remove unnecessary code from dataplane/xen-block.c Paul Durrant
2018-12-11 10:47   ` [Qemu-devel] " Paul Durrant
2018-12-11 15:30   ` Anthony PERARD
2018-12-11 15:30     ` [Qemu-devel] [Xen-devel] " Anthony PERARD
2018-12-11 15:38     ` Paul Durrant
2018-12-11 15:38       ` [Qemu-devel] [Xen-devel] " Paul Durrant
2018-12-11 10:47 ` [PATCH v3 10/18] xen: add header and build dataplane/xen-block.c Paul Durrant
2018-12-11 10:47   ` [Qemu-devel] " Paul Durrant
2018-12-11 10:47 ` [PATCH v3 11/18] xen: remove 'XenBlkDev' and 'blkdev' names from dataplane/xen-block Paul Durrant
2018-12-11 10:47   ` [Qemu-devel] " Paul Durrant
2018-12-11 10:47 ` [PATCH v3 12/18] xen: remove 'ioreq' struct/varable/field names from dataplane/xen-block.c Paul Durrant
2018-12-11 10:47   ` [Qemu-devel] " Paul Durrant
2018-12-11 10:47 ` [PATCH v3 13/18] xen: purge 'blk' and 'ioreq' from function names in dataplane/xen-block.c Paul Durrant
2018-12-11 10:47   ` [Qemu-devel] " Paul Durrant
2018-12-11 10:47 ` Paul Durrant [this message]
2018-12-11 10:47   ` [Qemu-devel] [PATCH v3 14/18] xen: add implementations of xen-block connect and disconnect functions Paul Durrant
2018-12-11 16:17   ` Anthony PERARD
2018-12-11 16:17     ` [Qemu-devel] " Anthony PERARD
2018-12-11 10:47 ` [PATCH v3 15/18] xen: add a mechanism to automatically create XenDevice-s Paul Durrant
2018-12-11 10:47   ` [Qemu-devel] " Paul Durrant
2018-12-11 10:47 ` [PATCH v3 16/18] xen: automatically create XenBlockDevice-s Paul Durrant
2018-12-11 10:47   ` [Qemu-devel] " Paul Durrant
2018-12-11 10:47 ` [PATCH v3 17/18] MAINTAINERS: add myself as a Xen maintainer Paul Durrant
2018-12-11 10:47   ` [Qemu-devel] " Paul Durrant
2018-12-11 10:47 ` [PATCH v3 18/18] xen: remove the legacy 'xen_disk' backend Paul Durrant
2018-12-11 10:47   ` [Qemu-devel] " Paul Durrant

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1544525238-3527-15-git-send-email-paul.durrant@citrix.com \
    --to=paul.durrant@citrix.com \
    --cc=anthony.perard@citrix.com \
    --cc=kwolf@redhat.com \
    --cc=mreitz@redhat.com \
    --cc=qemu-block@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    --cc=sstabellini@kernel.org \
    --cc=xen-devel@lists.xenproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.