qemu: Add handling for VSERPORT_CHANGE event
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.
This commit is contained in:
parent
24c25a68c2
commit
15bbaaf014
@ -196,6 +196,7 @@ typedef enum {
|
|||||||
QEMU_PROCESS_EVENT_GUESTPANIC,
|
QEMU_PROCESS_EVENT_GUESTPANIC,
|
||||||
QEMU_PROCESS_EVENT_DEVICE_DELETED,
|
QEMU_PROCESS_EVENT_DEVICE_DELETED,
|
||||||
QEMU_PROCESS_EVENT_NIC_RX_FILTER_CHANGED,
|
QEMU_PROCESS_EVENT_NIC_RX_FILTER_CHANGED,
|
||||||
|
QEMU_PROCESS_EVENT_SERIAL_CHANGED,
|
||||||
|
|
||||||
QEMU_PROCESS_EVENT_LAST
|
QEMU_PROCESS_EVENT_LAST
|
||||||
} qemuProcessEventType;
|
} qemuProcessEventType;
|
||||||
|
@ -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 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)
|
static void qemuProcessEventHandler(void *data, void *opaque)
|
||||||
{
|
{
|
||||||
struct qemuProcessEvent *processEvent = data;
|
struct qemuProcessEvent *processEvent = data;
|
||||||
@ -4357,6 +4411,9 @@ static void qemuProcessEventHandler(void *data, void *opaque)
|
|||||||
case QEMU_PROCESS_EVENT_NIC_RX_FILTER_CHANGED:
|
case QEMU_PROCESS_EVENT_NIC_RX_FILTER_CHANGED:
|
||||||
processNicRxFilterChangedEvent(driver, vm, processEvent->data);
|
processNicRxFilterChangedEvent(driver, vm, processEvent->data);
|
||||||
break;
|
break;
|
||||||
|
case QEMU_PROCESS_EVENT_SERIAL_CHANGED:
|
||||||
|
processSerialChangedEvent(driver, vm, processEvent->data,
|
||||||
|
processEvent->action);
|
||||||
case QEMU_PROCESS_EVENT_LAST:
|
case QEMU_PROCESS_EVENT_LAST:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -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 qemuMonitorSetCapabilities(qemuMonitorPtr mon)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -176,6 +176,12 @@ typedef int (*qemuMonitorDomainNicRxFilterChangedCallback)(qemuMonitorPtr mon,
|
|||||||
const char *devAlias,
|
const char *devAlias,
|
||||||
void *opaque);
|
void *opaque);
|
||||||
|
|
||||||
|
typedef int (*qemuMonitorDomainSerialChangeCallback)(qemuMonitorPtr mon,
|
||||||
|
virDomainObjPtr vm,
|
||||||
|
const char *devAlias,
|
||||||
|
bool connected,
|
||||||
|
void *opaque);
|
||||||
|
|
||||||
typedef struct _qemuMonitorCallbacks qemuMonitorCallbacks;
|
typedef struct _qemuMonitorCallbacks qemuMonitorCallbacks;
|
||||||
typedef qemuMonitorCallbacks *qemuMonitorCallbacksPtr;
|
typedef qemuMonitorCallbacks *qemuMonitorCallbacksPtr;
|
||||||
struct _qemuMonitorCallbacks {
|
struct _qemuMonitorCallbacks {
|
||||||
@ -202,6 +208,7 @@ struct _qemuMonitorCallbacks {
|
|||||||
qemuMonitorDomainGuestPanicCallback domainGuestPanic;
|
qemuMonitorDomainGuestPanicCallback domainGuestPanic;
|
||||||
qemuMonitorDomainDeviceDeletedCallback domainDeviceDeleted;
|
qemuMonitorDomainDeviceDeletedCallback domainDeviceDeleted;
|
||||||
qemuMonitorDomainNicRxFilterChangedCallback domainNicRxFilterChanged;
|
qemuMonitorDomainNicRxFilterChangedCallback domainNicRxFilterChanged;
|
||||||
|
qemuMonitorDomainSerialChangeCallback domainSerialChange;
|
||||||
};
|
};
|
||||||
|
|
||||||
char *qemuMonitorEscapeArg(const char *in);
|
char *qemuMonitorEscapeArg(const char *in);
|
||||||
@ -292,6 +299,9 @@ int qemuMonitorEmitDeviceDeleted(qemuMonitorPtr mon,
|
|||||||
const char *devAlias);
|
const char *devAlias);
|
||||||
int qemuMonitorEmitNicRxFilterChanged(qemuMonitorPtr mon,
|
int qemuMonitorEmitNicRxFilterChanged(qemuMonitorPtr mon,
|
||||||
const char *devAlias);
|
const char *devAlias);
|
||||||
|
int qemuMonitorEmitSerialChange(qemuMonitorPtr mon,
|
||||||
|
const char *devAlias,
|
||||||
|
bool connected);
|
||||||
|
|
||||||
int qemuMonitorStartCPUs(qemuMonitorPtr mon,
|
int qemuMonitorStartCPUs(qemuMonitorPtr mon,
|
||||||
virConnectPtr conn);
|
virConnectPtr conn);
|
||||||
|
@ -82,6 +82,7 @@ static void qemuMonitorJSONHandlePMSuspendDisk(qemuMonitorPtr mon, virJSONValueP
|
|||||||
static void qemuMonitorJSONHandleGuestPanic(qemuMonitorPtr mon, virJSONValuePtr data);
|
static void qemuMonitorJSONHandleGuestPanic(qemuMonitorPtr mon, virJSONValuePtr data);
|
||||||
static void qemuMonitorJSONHandleDeviceDeleted(qemuMonitorPtr mon, virJSONValuePtr data);
|
static void qemuMonitorJSONHandleDeviceDeleted(qemuMonitorPtr mon, virJSONValuePtr data);
|
||||||
static void qemuMonitorJSONHandleNicRxFilterChanged(qemuMonitorPtr mon, virJSONValuePtr data);
|
static void qemuMonitorJSONHandleNicRxFilterChanged(qemuMonitorPtr mon, virJSONValuePtr data);
|
||||||
|
static void qemuMonitorJSONHandleSerialChange(qemuMonitorPtr mon, virJSONValuePtr data);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char *type;
|
const char *type;
|
||||||
@ -112,6 +113,7 @@ static qemuEventHandler eventHandlers[] = {
|
|||||||
{ "VNC_CONNECTED", qemuMonitorJSONHandleVNCConnect, },
|
{ "VNC_CONNECTED", qemuMonitorJSONHandleVNCConnect, },
|
||||||
{ "VNC_DISCONNECTED", qemuMonitorJSONHandleVNCDisconnect, },
|
{ "VNC_DISCONNECTED", qemuMonitorJSONHandleVNCDisconnect, },
|
||||||
{ "VNC_INITIALIZED", qemuMonitorJSONHandleVNCInitialize, },
|
{ "VNC_INITIALIZED", qemuMonitorJSONHandleVNCInitialize, },
|
||||||
|
{ "VSERPORT_CHANGE", qemuMonitorJSONHandleSerialChange, },
|
||||||
{ "WAKEUP", qemuMonitorJSONHandlePMWakeup, },
|
{ "WAKEUP", qemuMonitorJSONHandlePMWakeup, },
|
||||||
{ "WATCHDOG", qemuMonitorJSONHandleWatchdog, },
|
{ "WATCHDOG", qemuMonitorJSONHandleWatchdog, },
|
||||||
/* We use bsearch, so keep this list sorted. */
|
/* 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
|
int
|
||||||
qemuMonitorJSONHumanCommandWithFd(qemuMonitorPtr mon,
|
qemuMonitorJSONHumanCommandWithFd(qemuMonitorPtr mon,
|
||||||
const char *cmd_str,
|
const char *cmd_str,
|
||||||
|
@ -1540,6 +1540,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 = {
|
static qemuMonitorCallbacks monitorCallbacks = {
|
||||||
.eofNotify = qemuProcessHandleMonitorEOF,
|
.eofNotify = qemuProcessHandleMonitorEOF,
|
||||||
.errorNotify = qemuProcessHandleMonitorError,
|
.errorNotify = qemuProcessHandleMonitorError,
|
||||||
@ -1562,6 +1605,7 @@ static qemuMonitorCallbacks monitorCallbacks = {
|
|||||||
.domainGuestPanic = qemuProcessHandleGuestPanic,
|
.domainGuestPanic = qemuProcessHandleGuestPanic,
|
||||||
.domainDeviceDeleted = qemuProcessHandleDeviceDeleted,
|
.domainDeviceDeleted = qemuProcessHandleDeviceDeleted,
|
||||||
.domainNicRxFilterChanged = qemuProcessHandleNicRxFilterChanged,
|
.domainNicRxFilterChanged = qemuProcessHandleNicRxFilterChanged,
|
||||||
|
.domainSerialChange = qemuProcessHandleSerialChanged,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
Loading…
x
Reference in New Issue
Block a user