Signed-off-by: Jim Paris <jim@xxxxxxxx> --- src/qemu_driver.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 102 insertions(+), 4 deletions(-) diff --git a/src/qemu_driver.c b/src/qemu_driver.c index 50ab702..c6de8a0 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -2047,10 +2047,108 @@ 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 (read(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 ((xml = (char *)malloc(header.xml_len + 1)) == NULL) { + qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED, + "out of memory"); + close(fd); + return -1; + } + + if (read(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; + } + xml[header.xml_len] = '\0'; + + /* 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 to restore is already active"); + 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->stdinFd = 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->stdinFd = 0; + + /* If it was running before, resume it now. */ + if (header.was_running) { + char *info; + if (qemudMonitorCommand(driver, vm, "cont\n", &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