New qemu added a new event that is emitted when a virtio serial channel
is opened in the guest OS. This allows us to update the state of the
port in the output-only XML element.
This patch implements the monitor callbacks and necessary handlers to
update the state in the definition.
---
src/qemu/qemu_domain.h | 1 +
src/qemu/qemu_driver.c | 57 ++++++++++++++++++++++++++++++++++++++++++++
src/qemu/qemu_monitor.c | 14 +++++++++++
src/qemu/qemu_monitor.h | 10 ++++++++
src/qemu/qemu_monitor_json.c | 23 ++++++++++++++++++
src/qemu/qemu_process.c | 44 ++++++++++++++++++++++++++++++++++
6 files changed, 149 insertions(+)
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
index ad45a66..e4ea4ce 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -196,6 +196,7 @@ typedef enum {
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;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index a84fd47..31bf6bb 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -4334,6 +4334,60 @@ processNicRxFilterChangedEvent(virQEMUDriverPtr driver,
}
+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 domain status after removing device %s",
+ 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;
@@ -4357,6 +4411,9 @@ static void qemuProcessEventHandler(void *data, void *opaque)
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;
}
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 60440a7..926619f 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -1400,6 +1400,20 @@ qemuMonitorEmitNicRxFilterChanged(qemuMonitorPtr mon,
}
+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;
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 54d4476..3078be0 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -176,6 +176,12 @@ typedef int
(*qemuMonitorDomainNicRxFilterChangedCallback)(qemuMonitorPtr mon,
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 {
@@ -202,6 +208,7 @@ struct _qemuMonitorCallbacks {
qemuMonitorDomainGuestPanicCallback domainGuestPanic;
qemuMonitorDomainDeviceDeletedCallback domainDeviceDeleted;
qemuMonitorDomainNicRxFilterChangedCallback domainNicRxFilterChanged;
+ qemuMonitorDomainSerialChangeCallback domainSerialChange;
};
char *qemuMonitorEscapeArg(const char *in);
@@ -292,6 +299,9 @@ int qemuMonitorEmitDeviceDeleted(qemuMonitorPtr mon,
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);
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 394617c..9c8a6fb 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -82,6 +82,7 @@ static void qemuMonitorJSONHandlePMSuspendDisk(qemuMonitorPtr mon,
virJSONValueP
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;
@@ -112,6 +113,7 @@ static qemuEventHandler eventHandlers[] = {
{ "VNC_CONNECTED", qemuMonitorJSONHandleVNCConnect, },
{ "VNC_DISCONNECTED", qemuMonitorJSONHandleVNCDisconnect, },
{ "VNC_INITIALIZED", qemuMonitorJSONHandleVNCInitialize, },
+ { "VSERPORT_CHANGE", qemuMonitorJSONHandleSerialChange, },
{ "WAKEUP", qemuMonitorJSONHandlePMWakeup, },
{ "WATCHDOG", qemuMonitorJSONHandleWatchdog, },
/* We use bsearch, so keep this list sorted. */
@@ -895,6 +897,27 @@ qemuMonitorJSONHandleNicRxFilterChanged(qemuMonitorPtr mon,
virJSONValuePtr data
}
+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,
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index bf5239a..24c7383 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -1539,6 +1539,49 @@ qemuProcessHandleNicRxFilterChanged(qemuMonitorPtr mon
ATTRIBUTE_UNUSED,
}
+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,
@@ -1561,6 +1604,7 @@ static qemuMonitorCallbacks monitorCallbacks = {
.domainGuestPanic = qemuProcessHandleGuestPanic,
.domainDeviceDeleted = qemuProcessHandleDeviceDeleted,
.domainNicRxFilterChanged = qemuProcessHandleNicRxFilterChanged,
+ .domainSerialChange = qemuProcessHandleSerialChanged,
};
static int
--
2.1.0