def->onReboot != VIR_DOMAIN_LIFECYCLE_RESTART)
virCommandAddArg(cmd, "-no-reboot");
+ /* If JSON monitor is enabled, we can receive an event
+ * when QEMU stops. If we use no-shutdown, then we can
+ * watch for this event and do a soft/warm reboot.
+ */
+ if (monitor_json)
+ virCommandAddArg(cmd, "-no-shutdown");
+
if (!(def->features & (1 << VIR_DOMAIN_FEATURE_ACPI)))
virCommandAddArg(cmd, "-no-acpi");
virBitmapPtr qemuCaps;
char *lockState;
+
+ bool fakeReboot;
};
struct qemuDomainWatchdogEvent
}
-static int qemudDomainShutdown(virDomainPtr dom) {
+static int qemuDomainShutdown(virDomainPtr dom) {
struct qemud_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
int ret = -1;
ret = qemuMonitorSystemPowerdown(priv->mon);
qemuDomainObjExitMonitor(vm);
+ priv->fakeReboot = false;
+
endjob:
if (qemuDomainObjEndJob(vm) == 0)
vm = NULL;
}
+static int qemuDomainReboot(virDomainPtr dom, unsigned int flags) {
+ struct qemud_driver *driver = dom->conn->privateData;
+ virDomainObjPtr vm;
+ int ret = -1;
+ qemuDomainObjPrivatePtr priv;
+
+ virCheckFlags(0, -1);
+
+ qemuDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ qemuDriverUnlock(driver);
+
+ if (!vm) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(dom->uuid, uuidstr);
+ qemuReportError(VIR_ERR_NO_DOMAIN,
+ _("no domain with matching uuid '%s'"), uuidstr);
+ goto cleanup;
+ }
+ priv = vm->privateData;
+
+#if HAVE_YAJL
+ if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_MONITOR_JSON)) {
+ if (qemuDomainObjBeginJob(vm) < 0)
+ goto cleanup;
+
+ if (!virDomainObjIsActive(vm)) {
+ qemuReportError(VIR_ERR_OPERATION_INVALID,
+ "%s", _("domain is not running"));
+ goto endjob;
+ }
+
+ qemuDomainObjEnterMonitor(vm);
+ ret = qemuMonitorSystemPowerdown(priv->mon);
+ qemuDomainObjExitMonitor(vm);
+
+ priv->fakeReboot = true;
+
+ endjob:
+ if (qemuDomainObjEndJob(vm) == 0)
+ vm = NULL;
+ } else {
+#endif
+ qemuReportError(VIR_ERR_NO_SUPPORT, "%s",
+ _("Reboot is not supported without the JSON monitor"));
+#if HAVE_YAJL
+ }
+#endif
+
+cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ return ret;
+}
+
+
static int qemudDomainDestroy(virDomainPtr dom) {
struct qemud_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
int ret = -1;
virDomainEventPtr event = NULL;
+ qemuDomainObjPrivatePtr priv;
qemuDriverLock(driver);
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
goto cleanup;
}
+ priv = vm->privateData;
+ priv->fakeReboot = false;
+
/* Although qemuProcessStop does this already, there may
* be an outstanding job active. We want to make sure we
* can kill the process even if a job is active. Killing
.domainLookupByName = qemudDomainLookupByName, /* 0.2.0 */
.domainSuspend = qemudDomainSuspend, /* 0.2.0 */
.domainResume = qemudDomainResume, /* 0.2.0 */
- .domainShutdown = qemudDomainShutdown, /* 0.2.0 */
+ .domainShutdown = qemuDomainShutdown, /* 0.2.0 */
+ .domainReboot = qemuDomainReboot, /* 0.9.3 */
.domainDestroy = qemudDomainDestroy, /* 0.2.0 */
.domainGetOSType = qemudDomainGetOSType, /* 0.2.2 */
.domainGetMaxMemory = qemudDomainGetMaxMemory, /* 0.4.2 */
}
+int qemuMonitorSystemReset(qemuMonitorPtr mon)
+{
+ int ret;
+ VIR_DEBUG("mon=%p", mon);
+
+ if (!mon) {
+ qemuReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("monitor must not be NULL"));
+ return -1;
+ }
+
+ if (mon->json)
+ ret = qemuMonitorJSONSystemReset(mon);
+ else
+ ret = qemuMonitorTextSystemReset(mon);
+ return ret;
+}
+
+
int qemuMonitorGetCPUInfo(qemuMonitorPtr mon,
int **pids)
{
int qemuMonitorStopCPUs(qemuMonitorPtr mon);
int qemuMonitorGetStatus(qemuMonitorPtr mon, bool *running);
+int qemuMonitorSystemReset(qemuMonitorPtr mon);
int qemuMonitorSystemPowerdown(qemuMonitorPtr mon);
int qemuMonitorGetCPUInfo(qemuMonitorPtr mon,
}
+int qemuMonitorJSONSystemReset(qemuMonitorPtr mon)
+{
+ int ret;
+ virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("system_reset", NULL);
+ virJSONValuePtr reply = NULL;
+ if (!cmd)
+ return -1;
+
+ ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+ if (ret == 0)
+ ret = qemuMonitorJSONCheckError(cmd, reply);
+
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
+
+
/*
* [ { "CPU": 0, "current": true, "halted": false, "pc": 3227107138 },
* { "CPU": 1, "current": false, "halted": true, "pc": 7108165 } ]
int qemuMonitorJSONGetStatus(qemuMonitorPtr mon, bool *running);
int qemuMonitorJSONSystemPowerdown(qemuMonitorPtr mon);
+int qemuMonitorJSONSystemReset(qemuMonitorPtr mon);
int qemuMonitorJSONGetCPUInfo(qemuMonitorPtr mon,
int **pids);
}
+int qemuMonitorTextSystemReset(qemuMonitorPtr mon) {
+ char *info;
+
+ if (qemuMonitorHMPCommand(mon, "system_reset", &info) < 0) {
+ qemuReportError(VIR_ERR_OPERATION_FAILED,
+ "%s", _("system reset operation failed"));
+ return -1;
+ }
+ VIR_FREE(info);
+ return 0;
+}
+
+
int qemuMonitorTextGetCPUInfo(qemuMonitorPtr mon,
int **pids)
{
int qemuMonitorTextGetStatus(qemuMonitorPtr mon, bool *running);
int qemuMonitorTextSystemPowerdown(qemuMonitorPtr mon);
+int qemuMonitorTextSystemReset(qemuMonitorPtr mon);
int qemuMonitorTextGetCPUInfo(qemuMonitorPtr mon,
int **pids);
}
+/*
+ * Since we have the '-no-shutdown' flag set, the
+ * QEMU process will currently have guest OS shutdown
+ * and the CPUS stopped. To fake the reboot, we thus
+ * want todo a reset of the virtual hardware, followed
+ * by restart of the CPUs. This should result in the
+ * guest OS booting up again
+ */
+static void
+qemuProcessFakeReboot(void *opaque)
+{
+ struct qemud_driver *driver = qemu_driver;
+ virDomainObjPtr vm = opaque;
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ virDomainEventPtr event = NULL;
+ int ret = -1;
+ VIR_DEBUG("vm=%p", vm);
+ qemuDriverLock(driver);
+ virDomainObjLock(vm);
+ if (qemuDomainObjBeginJob(vm) < 0)
+ goto cleanup;
+
+ if (!virDomainObjIsActive(vm)) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("guest unexpectedly quit"));
+ goto endjob;
+ }
+
+ qemuDomainObjEnterMonitorWithDriver(driver, vm);
+ if (qemuMonitorSystemReset(priv->mon) < 0) {
+ qemuDomainObjExitMonitorWithDriver(driver, vm);
+ goto endjob;
+ }
+ qemuDomainObjExitMonitorWithDriver(driver, vm);
+
+ if (!virDomainObjIsActive(vm)) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("guest unexpectedly quit"));
+ goto endjob;
+ }
+
+ if (qemuProcessStartCPUs(driver, vm, NULL,
+ VIR_DOMAIN_RUNNING_BOOTED) < 0) {
+ if (virGetLastError() == NULL)
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("resume operation failed"));
+ goto endjob;
+ }
+ event = virDomainEventNewFromObj(vm,
+ VIR_DOMAIN_EVENT_RESUMED,
+ VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
+
+ ret = 0;
+
+endjob:
+ if (qemuDomainObjEndJob(vm) == 0)
+ vm = NULL;
+
+cleanup:
+ if (vm) {
+ if (ret == -1)
+ qemuProcessKill(vm);
+ if (virDomainObjUnref(vm) > 0)
+ virDomainObjUnlock(vm);
+ }
+ if (event)
+ qemuDomainEventQueue(driver, event);
+ qemuDriverUnlock(driver);
+}
+
+
static int
qemuProcessHandleShutdown(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
virDomainObjPtr vm)
{
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ VIR_DEBUG("vm=%p", vm);
+
virDomainObjLock(vm);
- ((qemuDomainObjPrivatePtr) vm->privateData)->gotShutdown = true;
- virDomainObjUnlock(vm);
+ priv->gotShutdown = true;
+ if (priv->fakeReboot) {
+ virDomainObjRef(vm);
+ virThread th;
+ if (virThreadCreate(&th,
+ false,
+ qemuProcessFakeReboot,
+ vm) < 0) {
+ VIR_ERROR("Failed to create reboot thread, killing domain");
+ qemuProcessKill(vm);
+ if (virDomainObjUnref(vm) == 0)
+ vm = NULL;
+ }
+ } else {
+ qemuProcessKill(vm);
+ }
+ if (vm)
+ virDomainObjUnlock(vm);
return 0;
}
}
+/*
+ * Precondition: Both driver and vm must be locked,
+ * and a job must be active. This method will call
+ * {Enter,Exit}MonitorWithDriver
+ */
int
qemuProcessStartCPUs(struct qemud_driver *driver, virDomainObjPtr vm,
virConnectPtr conn, virDomainRunningReason reason)
goto cleanup;
vm->def->id = driver->nextvmid++;
+ priv->fakeReboot = false;
/* Run an early hook to set-up missing devices */
if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) {
--- /dev/null
+LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M \
+pc -m 214 -smp 1 -nographic -nodefconfig -nodefaults -chardev socket,\
+id=charmonitor,path=/tmp/test-monitor,server,nowait -mon chardev=charmonitor,\
+id=monitor,mode=control -no-shutdown -no-acpi -boot c -hda /dev/hda1 -usb -device \
+virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3
--- /dev/null
+<domain type='qemu'>
+ <name>encryptdisk</name>
+ <uuid>496898a6-e6ff-f7c8-5dc2-3cf410945ee9</uuid>
+ <memory>219100</memory>
+ <currentMemory>219100</currentMemory>
+ <vcpu>1</vcpu>
+ <os>
+ <type arch='i686' machine='pc'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu</emulator>
+ <disk type='file' device='disk'>
+ <driver name='qemu' type='qcow2'/>
+ <source file='/dev/hda1'/>
+ <target dev='hda'/>
+ </disk>
+ <memballoon model='virtio'/>
+ </devices>
+</domain>
virBitmapPtr extraFlags,
const char *migrateFrom,
int migrateFd,
+ bool json,
bool expectError)
{
char *expectargv = NULL;
}
if (!(cmd = qemuBuildCommandLine(conn, &driver,
- vmdef, &monitor_chr, false, extraFlags,
+ vmdef, &monitor_chr, json, extraFlags,
migrateFrom, migrateFd, NULL,
VIR_VM_OP_NO_OP)))
goto fail;
virBitmapPtr extraFlags;
const char *migrateFrom;
int migrateFd;
+ bool json;
bool expectError;
};
goto cleanup;
result = testCompareXMLToArgvFiles(xml, args, info->extraFlags,
- info->migrateFrom, info->migrateFd,
- info->expectError);
+ info->migrateFrom, info->migrateFd,
+ info->json, info->expectError);
cleanup:
free(xml);
{
int ret = 0;
char *map = NULL;
+ bool json = false;
abs_top_srcdir = getenv("abs_top_srcdir");
if (!abs_top_srcdir)
# define DO_TEST_FULL(name, migrateFrom, migrateFd, expectError, ...) \
do { \
struct testInfo info = { \
- name, NULL, migrateFrom, migrateFd, expectError \
+ name, NULL, migrateFrom, migrateFd, json, expectError \
}; \
if (!(info.extraFlags = qemuCapsNew())) \
return EXIT_FAILURE; \
QEMU_CAPS_DRIVE, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG,
QEMU_CAPS_PCI_MULTIFUNCTION);
+ json = true;
+ DO_TEST("monitor-json", false, QEMU_CAPS_DEVICE,
+ QEMU_CAPS_CHARDEV, QEMU_CAPS_MONITOR_JSON, QEMU_CAPS_NODEFCONFIG);
+ json = false;
+
free(driver.stateDir);
virCapabilitiesFree(driver.caps);
free(map);