1
0
mirror of https://gitlab.com/libvirt/libvirt.git synced 2025-01-11 09:17:52 +03:00

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:
Peter Krempa 2014-11-13 14:09:39 +01:00
parent 24c25a68c2
commit 15bbaaf014
6 changed files with 149 additions and 0 deletions

View File

@ -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;

View File

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

View File

@ -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;

View File

@ -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);

View File

@ -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,

View File

@ -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 = {
.eofNotify = qemuProcessHandleMonitorEOF,
.errorNotify = qemuProcessHandleMonitorError,
@ -1562,6 +1605,7 @@ static qemuMonitorCallbacks monitorCallbacks = {
.domainGuestPanic = qemuProcessHandleGuestPanic,
.domainDeviceDeleted = qemuProcessHandleDeviceDeleted,
.domainNicRxFilterChanged = qemuProcessHandleNicRxFilterChanged,
.domainSerialChange = qemuProcessHandleSerialChanged,
};
static int