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);
}
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)
{
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, ...)
{
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);
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;
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);
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);