]> xenbits.xensource.com Git - people/pauldu/qemu.git/commitdiff
more infrastructure
authorPaul Durrant <paul.durrant@citrix.com>
Mon, 23 Apr 2018 12:48:46 +0000 (13:48 +0100)
committerPaul Durrant <paul.durrant@citrix.com>
Thu, 26 Apr 2018 10:11:19 +0000 (11:11 +0100)
Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
hw/block/xen_qdisk.c
hw/xen/trace-events
hw/xen/xen_bus.c
include/hw/xen/xen_bus.h

index 85f4d87fd30fe5a3b29dd99b6fc49c5d07e2d53d..f8ccb02628b4fc912b83ddec8a0b65ef33e952f9 100644 (file)
@@ -70,7 +70,7 @@ static void xen_qdisk_realize(XenBackend *dev, Error **errp)
                             size / d->conf.logical_block_size);
 }
 
-static void xen_qdisk_connect(XenBackend *dev, Error **errp)
+static void xen_qdisk_initialize(XenBackend *dev, Error **errp)
 {
 }
 
@@ -103,10 +103,9 @@ static void xen_qdisk_class_init(ObjectClass *klass, void *data)
     DeviceClass *dc = DEVICE_CLASS(klass);
     XenBackendClass *k = XEN_BACKEND_CLASS(klass);
 
-    k->type = "xen-qdisk";
     k->device = "bar";
     k->realize = xen_qdisk_realize;
-    k->connect = xen_qdisk_connect;
+    k->initialize = xen_qdisk_initialize;
     k->disconnect = xen_qdisk_disconnect;
     k->event = xen_qdisk_event;
     k->unrealize = xen_qdisk_unrealize;
index c17c0187eafc836ace5daab193ff1cee69917afb..cf65d455558f838b81a70fb3a846ec57033cb68c 100644 (file)
@@ -14,7 +14,6 @@ xen_unmap_pcidev(uint32_t id, uint8_t bus, uint8_t dev, uint8_t func) "id: %u bd
 xen_domid_restrict(int err) "err: %u"
 
 # include/hw/xen/xen_bus.c
-xen_backend_type_ref(const char *type, uint16_t domid) "type: %s domid: %u"
-xen_backend_type_unref(const char *type, uint16_t domid) "type: %s domid: %u"
-xen_backend_realize(const char *type, char *name) "type: %s name: %s"
-xen_backend_unrealize(const char *type, char *name) "type: %s name: %s"
+xen_backend_log(const char *type, char *name, char *msg) "%s/%s: %s"
+xen_backend_realize(const char *type, char *name) "%s/%s"
+xen_backend_unrealize(const char *type, char *name) "%s/%s"
index d0fafb7a2e37c8b02053753e4bcbe9c1a58fc289..81ea913ebcc1877a8d7c48f30b4d317d38228e4a 100644 (file)
@@ -16,19 +16,19 @@ static domid_t xen_backend_id;
 static void xen_bus_dev_print(Monitor *mon, DeviceState *dev, int indent)
 {
     XenBackend *d = XEN_BACKEND(dev);
-    XenBackendClass *dc = XEN_BACKEND_GET_CLASS(d);
+    const char *type = object_get_typename(OBJECT(d));
 
     monitor_printf(mon, "%*stype = '%s' name = '%s' frontend_id = %u\n",
-                   indent, "", dc->type, d->name, d->frontend_id);
+                   indent, "", type, d->name, d->frontend_id);
 }
 
 static char *xen_bus_get_dev_path(DeviceState *dev)
 {
     XenBackend *d = XEN_BACKEND(dev);
-    XenBackendClass *dc = XEN_BACKEND_GET_CLASS(d);
+    const char *type = object_get_typename(OBJECT(d));
 
     return g_strdup_printf("/local/domain/%u/backend/%s/%u/%s",
-                           xen_backend_id, dc->type, d->frontend_id,
+                           xen_backend_id, type, d->frontend_id,
                            d->name);
 }
 
@@ -57,6 +57,29 @@ static void xen_bus_class_init(ObjectClass *klass, void *data)
     bc->get_frontend_path = xen_bus_get_frontend_path;
 }
 
+static void xen_backend_vlog(XenBackend *d, const char *fmt, va_list ap)
+{
+    const char *type = object_get_typename(OBJECT(d));
+    char *msg;
+
+    msg = g_strdup_vprintf(fmt, ap);
+    trace_xen_backend_log(type, d->name, msg);
+
+    g_free(msg);
+}
+
+static void xen_backend_log(XenBackend *d, const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    xen_backend_vlog(d, fmt, ap);
+    va_end(ap);
+}
+
+#define XEN_BACKEND_LOG(d, fmt, ...) \
+    xen_backend_log(d, "%s: " fmt, __func__, __VA_ARGS__)
+
 static int xenstore_vprintf(struct xs_handle *xsh, char *node,
                             const char *key, const char *fmt, va_list ap)
 {
@@ -74,6 +97,23 @@ static int xenstore_vprintf(struct xs_handle *xsh, char *node,
     return rc;
 }
 
+static int xenstore_vscanf(struct xs_handle *xsh, char *node,
+                           const char *key, const char *fmt, va_list ap)
+{
+    char *path, *value;
+    int rc;
+
+    path = g_strdup_printf("%s/%s", node, key);
+    value = xs_read(xsh, XBT_NULL, path, NULL);
+
+    rc = value ? vsscanf(value, fmt, ap) : -1;
+
+    free(value);
+    g_free(path);
+
+    return rc;
+}
+
 int xenstore_backend_printf(XenBackend *d, const char *key,
                             const char *fmt, ...)
 {
@@ -100,6 +140,230 @@ int xenstore_frontend_printf(XenBackend *d, const char *key,
     return rc;
 }
 
+int xenstore_frontend_scanf(XenBackend *d, const char *key,
+                            const char *fmt, ...)
+{
+    va_list ap;
+    int rc;
+
+    va_start(ap, fmt);
+    rc = xenstore_vscanf(d->xsh, d->frontend_path, key, fmt, ap);
+    va_end(ap);
+
+    return rc;
+}
+
+static const char *xenstore_strstate(enum xenbus_state state)
+{
+    static const char *const name[] = {
+        [XenbusStateUnknown]       = "Unknown",
+        [XenbusStateInitialising]  = "Initialising",
+        [XenbusStateInitWait]      = "InitWait",
+        [XenbusStateInitialised]   = "Initialised",
+        [XenbusStateConnected]     = "Connected",
+        [XenbusStateClosing]       = "Closing",
+        [XenbusStateClosed]        = "Closed",
+    };
+    return (state < ARRAY_SIZE(name)) ? name[state] : "INVALID";
+}
+
+static void xen_backend_set_state(XenBackend *d, enum xenbus_state state)
+{
+    XEN_BACKEND_LOG(d, "%s", xenstore_strstate(state));
+
+    d->backend_state = state;
+    xenstore_backend_printf(d, "state", "%u", d->backend_state);
+}
+
+static void xen_backend_try_initialize(XenBackend *d, Error **errp)
+{
+    XenBackendClass *dc = XEN_BACKEND_GET_CLASS(d);
+
+    if (d->frontend_state != XenbusStateInitialised &&
+        d->frontend_state != XenbusStateConnected) {
+        if (!(d->flags & XENBACKEND_FLAG_IGNORE_STATE)) {
+            error_setg(errp, "frontend not ready");
+            return;
+        }
+    }
+
+    if (dc->initialize) {
+        Error *local_err = NULL;
+
+        dc->initialize(d, &local_err);
+        if (local_err) {
+            error_propagate(errp, local_err);
+            return;
+        }
+    }
+
+    xen_backend_set_state(d, XenbusStateConnected);
+}
+
+static void xen_backend_try_connected(XenBackend *d, Error **errp)
+{
+    XenBackendClass *dc = XEN_BACKEND_GET_CLASS(d);
+    Error *local_err = NULL;
+
+    if (!dc->connected) {
+        return;
+    }
+
+    if (d->frontend_state != XenbusStateConnected) {
+        if (!(d->flags & XENBACKEND_FLAG_IGNORE_STATE)) {
+            error_setg(errp, "frontend not ready");
+            return;
+        }
+    }
+
+    dc->connected(d, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+    }
+}
+
+static void xen_backend_disconnect(XenBackend *d, Error **errp)
+{
+    XenBackendClass *dc = XEN_BACKEND_GET_CLASS(d);
+
+    if (d->backend_state != XenbusStateClosing &&
+        d->backend_state != XenbusStateClosed  &&
+        dc->disconnect) {
+        Error *local_err = NULL;
+
+        dc->disconnect(d, &local_err);
+
+        if (local_err) {
+            error_propagate(errp, local_err);
+            return;
+        }
+    }
+
+    if (d->backend_state != d->frontend_state) {
+        xen_backend_set_state(d, d->frontend_state);
+    }
+}
+
+static void xen_backend_try_reset(XenBackend *d, Error **errp)
+{
+    XenBackendClass *dc = XEN_BACKEND_GET_CLASS(d);
+
+    if (d->frontend_state != XenbusStateInitialising) {
+        error_setg(errp, "frontend not ready");
+        return;
+    }
+
+    if (dc->reset) {
+        Error *local_err = NULL;
+
+        dc->reset(d, &local_err);
+        if (local_err) {
+            error_propagate(errp, local_err);
+            return;
+        }
+    }
+
+    xen_backend_set_state(d, XenbusStateInitWait);
+}
+
+static void xenstore_frontend_state_change(XenBackend *d)
+{
+    enum xenbus_state state;
+    bool done = false;
+
+    if (xenstore_frontend_scanf(d, "state", "%u", &state) != 1) {
+        state = XenbusStateUnknown;
+    }
+
+    if (d->frontend_state == state)
+        return;
+
+    XEN_BACKEND_LOG(d, "frontend -> %s", xenstore_strstate(state));
+    d->frontend_state = state;
+
+    if (d->frontend_state == XenbusStateClosing ||
+        d->frontend_state == XenbusStateClosed) {
+        Error *local_err = NULL;
+
+        xen_backend_disconnect(d, &local_err);
+
+        if (local_err) {
+            const char *msg = error_get_pretty(local_err);
+
+            XEN_BACKEND_LOG(d, "%s", msg);
+            error_free(local_err);
+        }
+    }
+
+    while (!done) {
+        Error *local_err = NULL;
+
+        switch (d->backend_state) {
+        case XenbusStateInitWait:
+            xen_backend_try_initialize(d, &local_err);
+            break;
+
+        case XenbusStateConnected:
+            xen_backend_try_connected(d, &local_err);
+            done = true;
+            break;
+
+        case XenbusStateClosed:
+            xen_backend_try_reset(d, &local_err);
+            break;
+
+        default:
+            done = true;
+            break;
+        }
+
+        if (local_err) {
+            const char *msg = error_get_pretty(local_err);
+
+            XEN_BACKEND_LOG(d, "%s", msg);
+            error_free(local_err);
+
+            done = true;
+        }
+    }
+}
+
+static void xenstore_watch_handler(void *opaque)
+{
+    XenBackend *d = opaque;
+    char **v;
+    unsigned int num;
+    void *p;
+
+    v = xs_read_watch(d->xsh, &num);
+    if (v == NULL)
+        goto out;
+
+    if (sscanf(v[XS_WATCH_TOKEN], "%p", &p) == 1 &&
+        p == d) {
+        xenstore_frontend_state_change(d);
+    }
+
+out:
+    free(v);
+}
+
+static int xenstore_frontend_watch(XenBackend *d)
+{
+    char *path, *token;
+    int rc;
+
+    path = g_strdup_printf("%s/state", d->frontend_path);
+    token = g_strdup_printf("%p", d);
+
+    rc = xs_watch(d->xsh, path, token) ? -1 : 0;
+
+    g_free(token);
+    g_free(path);
+
+    return rc;
+}
+
 static void xen_backend_destroy(Notifier *n, void *data)
 {
     XenBackend *d = container_of(n, XenBackend, exit);
@@ -113,9 +377,10 @@ static void xen_backend_realize(DeviceState *dev, Error **errp)
     XenBackendClass *dc = XEN_BACKEND_GET_CLASS(d);
     XenBus *b = XEN_BUS(qdev_get_parent_bus(dev));
     XenBusClass *bc = XEN_BUS_GET_CLASS(b);
+    const char *type = object_get_typename(OBJECT(d));
     Error *local_err = NULL;
 
-    trace_xen_backend_realize(dc->type, d->name);
+    trace_xen_backend_realize(type, d->name);
 
     if (d->frontend_id == DOMID_INVALID)
         d->frontend_id = xen_domid;
@@ -136,6 +401,9 @@ static void xen_backend_realize(DeviceState *dev, Error **errp)
         return;
     }
 
+    qemu_set_fd_handler(xs_fileno(d->xsh), xenstore_watch_handler, NULL,
+                        d);
+
     d->backend_path = bc->get_backend_path(d);
     d->frontend_path = bc->get_frontend_path(d);
     
@@ -153,20 +421,27 @@ static void xen_backend_realize(DeviceState *dev, Error **errp)
     xenstore_backend_printf(d, "frontend", "%s", d->frontend_path);
     xenstore_backend_printf(d, "frontend-id", "%u", d->frontend_id);    
     xenstore_backend_printf(d, "online", "%u", 1);
-    xenstore_backend_printf(d, "state", "%u", XenbusStateInitWait);
+
+    xen_backend_set_state(d, XenbusStateInitWait);
     
     xenstore_frontend_printf(d, "backend", "%s", d->backend_path);
     xenstore_frontend_printf(d, "backend-id", "%u", xen_backend_id);
-    xenstore_frontend_printf(d, "state", "%u", XenbusStateInitialising);    
+    xenstore_frontend_printf(d, "hotplug-status", "connected");
+
+    d->frontend_state = XenbusStateInitialising;
+    xenstore_frontend_printf(d, "state", "%u", d->frontend_state);
+
+    xenstore_frontend_watch(d);
 }
 
 static void xen_backend_unrealize(DeviceState *dev, Error **errp)
 {
     XenBackend *d = XEN_BACKEND(dev);
     XenBackendClass *dc = XEN_BACKEND_GET_CLASS(d);
+    const char *type = object_get_typename(OBJECT(d));
     Error *local_err = NULL;
 
-    trace_xen_backend_unrealize(dc->type, d->name);
+    trace_xen_backend_unrealize(type, d->name);
 
     if (dc->unrealize) {
         dc->unrealize(d, &local_err);
index 9fd430c19b63a4fc40b533d4fd73543247b3d002..7d044a257d668d885bd58bcd0cc49c3eb962c01c 100644 (file)
@@ -29,20 +29,26 @@ typedef struct XenBus {
     BusState qbus;
 } XenBus;
 
+#define XENBACKEND_FLAG_IGNORE_STATE 1
+
 struct XenBackend {
     DeviceState qdev;
     domid_t frontend_id;
     char *name;
     struct xs_handle *xsh;
     char *backend_path, *frontend_path;
+    enum xenbus_state backend_state, frontend_state;
+    unsigned int flags;
     Notifier exit;
 };
 
 typedef void (*XenBackendRealize)(XenBackend *dev, Error **errp);
-typedef void (*XenBackendConnect)(XenBackend *dev, Error **errp);
+typedef void (*XenBackendInitialize)(XenBackend *dev, Error **errp);
+typedef void (*XenBackendConnected)(XenBackend *dev, Error **errp);
 typedef void (*XenBackendDisconnect)(XenBackend *dev, Error **errp);
-typedef void (*XenBackendEvent)(XenBackend *dev);
+typedef void (*XenBackendReset)(XenBackend *dev, Error **errp);
 typedef void (*XenBackendUnrealize)(XenBackend *dev, Error **errp);
+typedef void (*XenBackendEvent)(XenBackend *dev);
 
 typedef struct XenBackendClass {
     /*< private >*/
@@ -51,10 +57,12 @@ typedef struct XenBackendClass {
     const char *type;
     const char *device;
     XenBackendRealize realize;
-    XenBackendConnect connect;
+    XenBackendInitialize initialize;
+    XenBackendConnected connected;
     XenBackendDisconnect disconnect;
-    XenBackendEvent event;
+    XenBackendReset reset;
     XenBackendUnrealize unrealize;
+    XenBackendEvent event;
 } XenBackendClass;
 
 #define TYPE_XEN_BACKEND "xen-backend"
@@ -79,5 +87,7 @@ int xenstore_backend_printf(XenBackend *d, const char *key,
                             const char *fmt, ...);
 int xenstore_frontend_printf(XenBackend *d, const char *key,
                              const char *fmt, ...);
+int xenstore_frontend_scanf(XenBackend *d, const char *key,
+                            const char *fmt, ...);
 
 #endif