Signed-off-by: Jim Paris <jim@xxxxxxxx> --- src/qemu_driver.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 109 insertions(+), 4 deletions(-) diff --git a/src/qemu_driver.c b/src/qemu_driver.c index f2c4316..b0b6d62 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -2041,10 +2041,115 @@ static int qemudDomainSave(virDomainPtr dom, static int qemudDomainRestore(virConnectPtr conn, - const char *path ATTRIBUTE_UNUSED) { - /*struct qemud_driver *driver = (struct qemud_driver *)conn->privateData;*/ - qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED, "restore is not supported"); - return -1; + const char *path) { + struct qemud_driver *driver = (struct qemud_driver *)conn->privateData; + struct qemud_vm_def *def; + struct qemud_vm *vm; + int fd; + char *xml; + struct qemud_save_header header; + + /* Verify the header and read the XML */ + if ((fd = open(path, O_RDONLY)) < 0) { + qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED, + "cannot read domain image"); + return -1; + } + + if (saferead(fd, &header, sizeof(header)) != sizeof(header)) { + qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED, + "failed to read qemu header"); + close(fd); + return -1; + } + + if (memcmp(header.magic, QEMUD_SAVE_MAGIC, sizeof(header.magic)) != 0) { + qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED, + "image magic is incorrect"); + close(fd); + return -1; + } + + if (header.version > QEMUD_SAVE_VERSION) { + qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED, + "image version is not supported (%d > %d)", + header.version, QEMUD_SAVE_VERSION); + close(fd); + return -1; + } + + if ((xml = (char *)malloc(header.xml_len)) == NULL) { + qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED, + "out of memory"); + close(fd); + return -1; + } + + if (saferead(fd, xml, header.xml_len) != header.xml_len) { + qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED, + "failed to read XML"); + close(fd); + free(xml); + return -1; + } + + /* Create a domain from this XML */ + if (!(def = qemudParseVMDef(conn, driver, xml, NULL))) { + qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED, + "failed to parse XML"); + close(fd); + free(xml); + return -1; + } + free(xml); + + /* Ensure the name and UUID don't already exist in an active VM */ + vm = qemudFindVMByUUID(driver, def->uuid); + if (!vm) vm = qemudFindVMByName(driver, def->name); + if (vm && qemudIsActiveVM(vm)) { + qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED, + "domain is already active as '%s'", vm->def->name); + close(fd); + return -1; + } + + if (!(vm = qemudAssignVMDef(conn, driver, def))) { + qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED, + "failed to assign new VM"); + qemudFreeVMDef(def); + close(fd); + return -1; + } + + /* Set the migration source and start it up. */ + snprintf(vm->migrateFrom, sizeof(vm->migrateFrom), "stdio"); + vm->stdin = fd; + + if (qemudStartVMDaemon(conn, driver, vm) < 0) { + qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED, + "failed to start VM"); + if (!vm->configFile[0]) + qemudRemoveInactiveVM(driver, vm); + close(fd); + return -1; + } + close(fd); + vm->migrateFrom[0] = '\0'; + vm->stdin = -1; + + /* If it was running before, resume it now. */ + if (header.was_running) { + char *info; + if (qemudMonitorCommand(driver, vm, "cont\r", &info) < 0) { + qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED, + "failed to resume domain"); + return -1; + } + free(info); + vm->state = VIR_DOMAIN_RUNNING; + } + + return 0; } -- 1.5.3.rc4 -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list