QEMU_PROCESS_EVENT_GUESTPANIC,
QEMU_PROCESS_EVENT_DEVICE_DELETED,
QEMU_PROCESS_EVENT_NIC_RX_FILTER_CHANGED,
+ QEMU_PROCESS_EVENT_SERIAL_CHANGED,
QEMU_PROCESS_EVENT_LAST
} qemuProcessEventType;
}
+static void
+processSerialChangedEvent(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ char *devAlias,
+ bool connected)
+{
+ virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+ virDomainChrDeviceState newstate;
+ virDomainDeviceDef dev;
+
+ if (connected)
+ newstate = VIR_DOMAIN_CHR_DEVICE_STATE_CONNECTED;
+ else
+ newstate = VIR_DOMAIN_CHR_DEVICE_STATE_DISCONNECTED;
+
+ VIR_DEBUG("Changing serial port state %s in domain %p %s",
+ devAlias, vm, vm->def->name);
+
+ if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
+ goto cleanup;
+
+ if (!virDomainObjIsActive(vm)) {
+ VIR_DEBUG("Domain is not running");
+ goto endjob;
+ }
+
+ if (virDomainDefFindDevice(vm->def, devAlias, &dev, true) < 0)
+ goto endjob;
+
+ /* we care only about certain devices */
+ if (dev.type != VIR_DOMAIN_DEVICE_CHR ||
+ dev.data.chr->deviceType != VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL ||
+ dev.data.chr->targetType != VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO)
+ goto endjob;
+
+ dev.data.chr->state = newstate;
+
+ if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
+ VIR_WARN("unable to save status of domain %s after updating state of "
+ "channel %s", vm->def->name, devAlias);
+
+ endjob:
+ /* We had an extra reference to vm before starting a new job so ending the
+ * job is guaranteed not to remove the last reference.
+ */
+ ignore_value(qemuDomainObjEndJob(driver, vm));
+
+ cleanup:
+ VIR_FREE(devAlias);
+ virObjectUnref(cfg);
+
+}
+
+
static void qemuProcessEventHandler(void *data, void *opaque)
{
struct qemuProcessEvent *processEvent = data;
case QEMU_PROCESS_EVENT_NIC_RX_FILTER_CHANGED:
processNicRxFilterChangedEvent(driver, vm, processEvent->data);
break;
+ case QEMU_PROCESS_EVENT_SERIAL_CHANGED:
+ processSerialChangedEvent(driver, vm, processEvent->data,
+ processEvent->action);
case QEMU_PROCESS_EVENT_LAST:
break;
}
}
+int
+qemuMonitorEmitSerialChange(qemuMonitorPtr mon,
+ const char *devAlias,
+ bool connected)
+{
+ int ret = -1;
+ VIR_DEBUG("mon=%p, devAlias='%s', connected=%d", mon, devAlias, connected);
+
+ QEMU_MONITOR_CALLBACK(mon, ret, domainSerialChange, mon->vm, devAlias, connected);
+
+ return ret;
+}
+
+
int qemuMonitorSetCapabilities(qemuMonitorPtr mon)
{
int ret;
const char *devAlias,
void *opaque);
+typedef int (*qemuMonitorDomainSerialChangeCallback)(qemuMonitorPtr mon,
+ virDomainObjPtr vm,
+ const char *devAlias,
+ bool connected,
+ void *opaque);
+
typedef struct _qemuMonitorCallbacks qemuMonitorCallbacks;
typedef qemuMonitorCallbacks *qemuMonitorCallbacksPtr;
struct _qemuMonitorCallbacks {
qemuMonitorDomainGuestPanicCallback domainGuestPanic;
qemuMonitorDomainDeviceDeletedCallback domainDeviceDeleted;
qemuMonitorDomainNicRxFilterChangedCallback domainNicRxFilterChanged;
+ qemuMonitorDomainSerialChangeCallback domainSerialChange;
};
char *qemuMonitorEscapeArg(const char *in);
const char *devAlias);
int qemuMonitorEmitNicRxFilterChanged(qemuMonitorPtr mon,
const char *devAlias);
+int qemuMonitorEmitSerialChange(qemuMonitorPtr mon,
+ const char *devAlias,
+ bool connected);
int qemuMonitorStartCPUs(qemuMonitorPtr mon,
virConnectPtr conn);
static void qemuMonitorJSONHandleGuestPanic(qemuMonitorPtr mon, virJSONValuePtr data);
static void qemuMonitorJSONHandleDeviceDeleted(qemuMonitorPtr mon, virJSONValuePtr data);
static void qemuMonitorJSONHandleNicRxFilterChanged(qemuMonitorPtr mon, virJSONValuePtr data);
+static void qemuMonitorJSONHandleSerialChange(qemuMonitorPtr mon, virJSONValuePtr data);
typedef struct {
const char *type;
{ "VNC_CONNECTED", qemuMonitorJSONHandleVNCConnect, },
{ "VNC_DISCONNECTED", qemuMonitorJSONHandleVNCDisconnect, },
{ "VNC_INITIALIZED", qemuMonitorJSONHandleVNCInitialize, },
+ { "VSERPORT_CHANGE", qemuMonitorJSONHandleSerialChange, },
{ "WAKEUP", qemuMonitorJSONHandlePMWakeup, },
{ "WATCHDOG", qemuMonitorJSONHandleWatchdog, },
/* We use bsearch, so keep this list sorted. */
}
+static void
+qemuMonitorJSONHandleSerialChange(qemuMonitorPtr mon,
+ virJSONValuePtr data)
+{
+ const char *name;
+ bool connected;
+
+ if (!(name = virJSONValueObjectGetString(data, "id"))) {
+ VIR_WARN("missing device alias in VSERPORT_CHANGE event");
+ return;
+ }
+
+ if (virJSONValueObjectGetBoolean(data, "open", &connected) < 0) {
+ VIR_WARN("missing port state for '%s' in VSERPORT_CHANGE event", name);
+ return;
+ }
+
+ qemuMonitorEmitSerialChange(mon, name, connected);
+}
+
+
int
qemuMonitorJSONHumanCommandWithFd(qemuMonitorPtr mon,
const char *cmd_str,
}
+static int
+qemuProcessHandleSerialChanged(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
+ virDomainObjPtr vm,
+ const char *devAlias,
+ bool connected,
+ void *opaque)
+{
+ virQEMUDriverPtr driver = opaque;
+ struct qemuProcessEvent *processEvent = NULL;
+ char *data;
+
+ virObjectLock(vm);
+
+ VIR_DEBUG("Serial port %s state changed to '%d' in domain %p %s",
+ devAlias, connected, vm, vm->def->name);
+
+ if (VIR_ALLOC(processEvent) < 0)
+ goto error;
+
+ processEvent->eventType = QEMU_PROCESS_EVENT_SERIAL_CHANGED;
+ if (VIR_STRDUP(data, devAlias) < 0)
+ goto error;
+ processEvent->data = data;
+ processEvent->action = connected;
+ processEvent->vm = vm;
+
+ virObjectRef(vm);
+ if (virThreadPoolSendJob(driver->workerPool, 0, processEvent) < 0) {
+ ignore_value(virObjectUnref(vm));
+ goto error;
+ }
+
+ cleanup:
+ virObjectUnlock(vm);
+ return 0;
+ error:
+ if (processEvent)
+ VIR_FREE(processEvent->data);
+ VIR_FREE(processEvent);
+ goto cleanup;
+}
+
+
static qemuMonitorCallbacks monitorCallbacks = {
.eofNotify = qemuProcessHandleMonitorEOF,
.errorNotify = qemuProcessHandleMonitorError,
.domainGuestPanic = qemuProcessHandleGuestPanic,
.domainDeviceDeleted = qemuProcessHandleDeviceDeleted,
.domainNicRxFilterChanged = qemuProcessHandleNicRxFilterChanged,
+ .domainSerialChange = qemuProcessHandleSerialChanged,
};
static int