We need to be able to restore a domain which we already locked and
started a job for it without undoing these steps. This patch factors
out internals of qemudDomainRestore into separate functions which work
for locked objects.
---
src/qemu/qemu_driver.c | 213 ++++++++++++++++++++++++++++++------------------
1 files changed, 135 insertions(+), 78 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index a519c02..d048570 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -6014,29 +6014,43 @@ child_cleanup:
_exit(exit_code);
}
-/* TODO: check seclabel restore */
-static int qemudDomainRestore(virConnectPtr conn,
- const char *path) {
- struct qemud_driver *driver = conn->privateData;
- virDomainDefPtr def = NULL;
- virDomainObjPtr vm = NULL;
- int fd = -1;
+static int qemudDomainImageClose(int fd, pid_t read_pid, int *status)
+{
+ int ret = 0;
+
+ if (fd != -1)
+ close(fd);
+
+ if (read_pid != -1) {
+ /* reap the process that read the file */
+ while ((ret = waitpid(read_pid, status, 0)) == -1
+ && errno == EINTR) {
+ /* empty */
+ }
+ } else if (status) {
+ *status = 0;
+ }
+
+ return ret;
+}
+
+static int qemudDomainImageOpen(struct qemud_driver *driver,
+ const char *path,
+ virDomainDefPtr *ret_def,
+ struct qemud_save_header *ret_header,
+ pid_t *ret_read_pid)
+{
+ int fd;
pid_t read_pid = -1;
- int ret = -1;
- char *xml = NULL;
struct qemud_save_header header;
- virDomainEventPtr event = NULL;
- int intermediatefd = -1;
- pid_t intermediate_pid = -1;
- int childstat;
+ char *xml = NULL;
+ virDomainDefPtr def = NULL;
- qemuDriverLock(driver);
- /* Verify the header and read the XML */
if ((fd = open(path, O_RDONLY)) < 0) {
if ((driver->user == 0) || (getuid() != 0)) {
qemuReportError(VIR_ERR_OPERATION_FAILED,
"%s", _("cannot read domain image"));
- goto cleanup;
+ goto error;
}
/* Opening as root failed, but qemu runs as a different user
@@ -6045,44 +6059,44 @@ static int qemudDomainRestore(virConnectPtr conn,
have the necessary authority to read the file. */
if ((fd = qemudOpenAsUID(path, driver->user, &read_pid)) < 0) {
/* error already reported */
- goto cleanup;
+ goto error;
}
}
if (saferead(fd, &header, sizeof(header)) != sizeof(header)) {
qemuReportError(VIR_ERR_OPERATION_FAILED,
"%s", _("failed to read qemu header"));
- goto cleanup;
+ goto error;
}
if (memcmp(header.magic, QEMUD_SAVE_MAGIC, sizeof(header.magic)) != 0) {
qemuReportError(VIR_ERR_OPERATION_FAILED,
"%s", _("image magic is incorrect"));
- goto cleanup;
+ goto error;
}
if (header.version > QEMUD_SAVE_VERSION) {
qemuReportError(VIR_ERR_OPERATION_FAILED,
_("image version is not supported (%d > %d)"),
header.version, QEMUD_SAVE_VERSION);
- goto cleanup;
+ goto error;
}
if (header.xml_len <= 0) {
qemuReportError(VIR_ERR_OPERATION_FAILED,
_("invalid XML length: %d"), header.xml_len);
- goto cleanup;
+ goto error;
}
if (VIR_ALLOC_N(xml, header.xml_len) < 0) {
virReportOOMError();
- goto cleanup;
+ goto error;
}
if (saferead(fd, xml, header.xml_len) != header.xml_len) {
qemuReportError(VIR_ERR_OPERATION_FAILED,
"%s", _("failed to read XML"));
- goto cleanup;
+ goto error;
}
/* Create a domain from this XML */
@@ -6090,35 +6104,53 @@ static int qemudDomainRestore(virConnectPtr conn,
VIR_DOMAIN_XML_INACTIVE))) {
qemuReportError(VIR_ERR_OPERATION_FAILED,
"%s", _("failed to parse XML"));
- goto cleanup;
+ goto error;
}
- if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
- goto cleanup;
+ VIR_FREE(xml);
- if (!(vm = virDomainAssignDef(driver->caps,
- &driver->domains,
- def, true))) {
- qemuReportError(VIR_ERR_OPERATION_FAILED,
- "%s", _("failed to assign new VM"));
- goto cleanup;
- }
- def = NULL;
+ *ret_def = def;
+ *ret_header = header;
+ *ret_read_pid = read_pid;
- if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
- goto cleanup;
+ return fd;
+
+error:
+ virDomainDefFree(def);
+ VIR_FREE(xml);
+ qemudDomainImageClose(fd, read_pid, NULL);
+
+ return -1;
+}
+
+/* TODO: check seclabel restore */
+static int qemudDomainImageStartVM(virConnectPtr conn,
+ struct qemud_driver *driver,
+ virDomainObjPtr vm,
+ int fd,
+ pid_t read_pid,
+ const struct qemud_save_header *header,
+ const char *path)
+{
+ int ret = -1;
+ virDomainEventPtr event;
+ int intermediatefd = -1;
+ pid_t intermediate_pid = -1;
+ int childstat;
+ int wait_ret;
+ int status;
- if (header.version == 2) {
+ if (header->version == 2) {
const char *intermediate_argv[3] = { NULL, "-dc", NULL };
- const char *prog = qemudSaveCompressionTypeToString(header.compressed);
+ const char *prog = qemudSaveCompressionTypeToString(header->compressed);
if (prog == NULL) {
qemuReportError(VIR_ERR_OPERATION_FAILED,
_("Invalid compressed save format %d"),
- header.compressed);
- goto endjob;
+ header->compressed);
+ goto out;
}
- if (header.compressed != QEMUD_SAVE_FORMAT_RAW) {
+ if (header->compressed != QEMUD_SAVE_FORMAT_RAW) {
intermediate_argv[0] = prog;
intermediatefd = fd;
fd = -1;
@@ -6127,29 +6159,27 @@ static int qemudDomainRestore(virConnectPtr conn,
qemuReportError(VIR_ERR_INTERNAL_ERROR,
_("Failed to start decompression binary %s"),
intermediate_argv[0]);
- goto endjob;
+ goto out;
}
}
}
+
/* Set the migration source and start it up. */
ret = qemudStartVMDaemon(conn, driver, vm, "stdio", fd);
+
if (intermediate_pid != -1) {
/* Wait for intermediate process to exit */
while (waitpid(intermediate_pid, &childstat, 0) == -1 &&
- errno == EINTR);
+ errno == EINTR) {
+ /* empty */
+ }
}
if (intermediatefd != -1)
close(intermediatefd);
- close(fd);
+
+ wait_ret = qemudDomainImageClose(fd, read_pid, &status);
fd = -1;
if (read_pid != -1) {
- int wait_ret;
- int status;
- /* reap the process that read the file */
- while (((wait_ret = waitpid(read_pid, &status, 0)) == -1)
- && (errno == EINTR)) {
- /* empty */
- }
read_pid = -1;
if (wait_ret == -1) {
virReportSystemError(errno,
@@ -6171,22 +6201,19 @@ static int qemudDomainRestore(virConnectPtr conn,
}
}
}
- if (ret < 0) {
- if (!vm->persistent) {
- if (qemuDomainObjEndJob(vm) > 0)
- virDomainRemoveInactive(&driver->domains,
- vm);
- vm = NULL;
- }
- goto endjob;
- }
+
+ if (ret < 0)
+ goto out;
event = virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_STARTED,
VIR_DOMAIN_EVENT_STARTED_RESTORED);
+ if (event)
+ qemuDomainEventQueue(driver, event);
+
/* If it was running before, resume it now. */
- if (header.was_running) {
+ if (header->was_running) {
qemuDomainObjPrivatePtr priv = vm->privateData;
qemuDomainObjEnterMonitorWithDriver(driver, vm);
if (qemuMonitorStartCPUs(priv->mon, conn) < 0) {
@@ -6194,38 +6221,68 @@ static int qemudDomainRestore(virConnectPtr conn,
qemuReportError(VIR_ERR_OPERATION_FAILED,
"%s", _("failed to resume domain"));
qemuDomainObjExitMonitorWithDriver(driver,vm);
- goto endjob;
+ goto out;
}
qemuDomainObjExitMonitorWithDriver(driver, vm);
vm->state = VIR_DOMAIN_RUNNING;
if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0) {
VIR_WARN("Failed to save status on vm %s", vm->def->name);
- goto endjob;
+ goto out;
}
}
+
ret = 0;
-endjob:
- if (vm &&
- qemuDomainObjEndJob(vm) == 0)
+out:
+ return ret;
+}
+
+static int qemudDomainRestore(virConnectPtr conn,
+ const char *path) {
+ struct qemud_driver *driver = conn->privateData;
+ virDomainDefPtr def = NULL;
+ virDomainObjPtr vm = NULL;
+ int fd = -1;
+ pid_t read_pid = -1;
+ int ret = -1;
+ struct qemud_save_header header;
+
+ qemuDriverLock(driver);
+
+ fd = qemudDomainImageOpen(driver, path, &def, &header, &read_pid);
+ if (fd < 0)
+ goto cleanup;
+
+ if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
+ goto cleanup;
+
+ if (!(vm = virDomainAssignDef(driver->caps,
+ &driver->domains,
+ def, true))) {
+ qemuReportError(VIR_ERR_OPERATION_FAILED,
+ "%s", _("failed to assign new VM"));
+ goto cleanup;
+ }
+ def = NULL;
+
+ if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
+ goto cleanup;
+
+ ret = qemudDomainImageStartVM(conn, driver, vm, fd,
+ read_pid, &header, path);
+
+ if (qemuDomainObjEndJob(vm) == 0)
+ vm = NULL;
+ else if (ret < 0 && !vm->persistent) {
+ virDomainRemoveInactive(&driver->domains, vm);
vm = NULL;
+ }
cleanup:
virDomainDefFree(def);
- VIR_FREE(xml);
- if (fd != -1)
- close(fd);
- if (read_pid != 0) {
- /* reap the process that read the file */
- while ((waitpid(read_pid, NULL, 0) == -1)
- && (errno == EINTR)) {
- /* empty */
- }
- }
+ qemudDomainImageClose(fd, read_pid, NULL);
if (vm)
virDomainObjUnlock(vm);
- if (event)
- qemuDomainEventQueue(driver, event);
qemuDriverUnlock(driver);
return ret;
}
--
1.7.1