[libvirt] [PATCH] qemu: avoid double close on domain restore

qemudDomainSaveImageStartVM was evil - it closed the incoming fd argument on some, but not all, code paths, without informing the caller about that action. No wonder that this resulted in double-closes: https://bugzilla.redhat.com/show_bug.cgi?id=672725 * src/qemu/qemu_driver.c (qemudDomainSaveImageStartVM): Alter signature, to avoid double-close. (qemudDomainRestore, qemudDomainObjRestore): Update callers. --- src/qemu/qemu_driver.c | 21 +++++++++++---------- 1 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 7fc08e8..5acddcb 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -3248,7 +3248,7 @@ static int ATTRIBUTE_NONNULL(6) qemudDomainSaveImageStartVM(virConnectPtr conn, struct qemud_driver *driver, virDomainObjPtr vm, - int fd, + int *fd, pid_t read_pid, const struct qemud_save_header *header, const char *path) @@ -3273,20 +3273,21 @@ qemudDomainSaveImageStartVM(virConnectPtr conn, if (header->compressed != QEMUD_SAVE_FORMAT_RAW) { intermediate_argv[0] = prog; - intermediatefd = fd; - fd = -1; + intermediatefd = *fd; + *fd = -1; if (virExec(intermediate_argv, NULL, NULL, - &intermediate_pid, intermediatefd, &fd, NULL, 0) < 0) { + &intermediate_pid, intermediatefd, fd, NULL, 0) < 0) { qemuReportError(VIR_ERR_INTERNAL_ERROR, _("Failed to start decompression binary %s"), intermediate_argv[0]); + *fd = intermediatefd; goto out; } } } /* Set the migration source and start it up. */ - ret = qemuProcessStart(conn, driver, vm, "stdio", true, fd, path, + ret = qemuProcessStart(conn, driver, vm, "stdio", true, *fd, path, VIR_VM_OP_RESTORE); if (intermediate_pid != -1) { @@ -3295,7 +3296,7 @@ qemudDomainSaveImageStartVM(virConnectPtr conn, * wait forever to write to stdout, so we must manually kill it. */ VIR_FORCE_CLOSE(intermediatefd); - VIR_FORCE_CLOSE(fd); + VIR_FORCE_CLOSE(*fd); kill(intermediate_pid, SIGTERM); } @@ -3307,8 +3308,8 @@ qemudDomainSaveImageStartVM(virConnectPtr conn, } VIR_FORCE_CLOSE(intermediatefd); - wait_ret = qemudDomainSaveImageClose(fd, read_pid, &status); - fd = -1; + wait_ret = qemudDomainSaveImageClose(*fd, read_pid, &status); + *fd = -1; if (read_pid != -1) { if (wait_ret == -1) { virReportSystemError(errno, @@ -3398,7 +3399,7 @@ static int qemudDomainRestore(virConnectPtr conn, if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0) goto cleanup; - ret = qemudDomainSaveImageStartVM(conn, driver, vm, fd, + ret = qemudDomainSaveImageStartVM(conn, driver, vm, &fd, read_pid, &header, path); if (qemuDomainObjEndJob(vm) == 0) @@ -3449,7 +3450,7 @@ static int qemudDomainObjRestore(virConnectPtr conn, virDomainObjAssignDef(vm, def, true); def = NULL; - ret = qemudDomainSaveImageStartVM(conn, driver, vm, fd, + ret = qemudDomainSaveImageStartVM(conn, driver, vm, &fd, read_pid, &header, path); cleanup: -- 1.7.4

On Tue, Mar 01, 2011 at 09:02:23PM -0700, Eric Blake wrote:
qemudDomainSaveImageStartVM was evil - it closed the incoming fd argument on some, but not all, code paths, without informing the caller about that action. No wonder that this resulted in double-closes: https://bugzilla.redhat.com/show_bug.cgi?id=672725
* src/qemu/qemu_driver.c (qemudDomainSaveImageStartVM): Alter signature, to avoid double-close. (qemudDomainRestore, qemudDomainObjRestore): Update callers. --- src/qemu/qemu_driver.c | 21 +++++++++++---------- 1 files changed, 11 insertions(+), 10 deletions(-)
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On 03/02/2011 05:10 AM, Daniel P. Berrange wrote:
On Tue, Mar 01, 2011 at 09:02:23PM -0700, Eric Blake wrote:
qemudDomainSaveImageStartVM was evil - it closed the incoming fd argument on some, but not all, code paths, without informing the caller about that action. No wonder that this resulted in double-closes: https://bugzilla.redhat.com/show_bug.cgi?id=672725
* src/qemu/qemu_driver.c (qemudDomainSaveImageStartVM): Alter signature, to avoid double-close. (qemudDomainRestore, qemudDomainObjRestore): Update callers. --- src/qemu/qemu_driver.c | 21 +++++++++++---------- 1 files changed, 11 insertions(+), 10 deletions(-)
ACK
Actually, I realized that the read_pid had the same issue (in systems that rapidly reuse pids, a double wait can end up hanging while it waits for the wrong pid). I squashed this in before pushing. diff --git i/src/qemu/qemu_driver.c w/src/qemu/qemu_driver.c index 5acddcb..c9095bb 100644 --- i/src/qemu/qemu_driver.c +++ w/src/qemu/qemu_driver.c @@ -3249,7 +3249,7 @@ qemudDomainSaveImageStartVM(virConnectPtr conn, struct qemud_driver *driver, virDomainObjPtr vm, int *fd, - pid_t read_pid, + pid_t *read_pid, const struct qemud_save_header *header, const char *path) { @@ -3308,9 +3308,9 @@ qemudDomainSaveImageStartVM(virConnectPtr conn, } VIR_FORCE_CLOSE(intermediatefd); - wait_ret = qemudDomainSaveImageClose(*fd, read_pid, &status); + wait_ret = qemudDomainSaveImageClose(*fd, *read_pid, &status); *fd = -1; - if (read_pid != -1) { + if (*read_pid != -1) { if (wait_ret == -1) { virReportSystemError(errno, _("failed to wait for process reading '%s'"), @@ -3331,6 +3331,7 @@ qemudDomainSaveImageStartVM(virConnectPtr conn, } } } + *read_pid = -1; if (ret < 0) { qemuDomainStartAudit(vm, "restored", false); @@ -3400,7 +3401,7 @@ static int qemudDomainRestore(virConnectPtr conn, goto cleanup; ret = qemudDomainSaveImageStartVM(conn, driver, vm, &fd, - read_pid, &header, path); + &read_pid, &header, path); if (qemuDomainObjEndJob(vm) == 0) vm = NULL; @@ -3451,7 +3452,7 @@ static int qemudDomainObjRestore(virConnectPtr conn, def = NULL; ret = qemudDomainSaveImageStartVM(conn, driver, vm, &fd, - read_pid, &header, path); + &read_pid, &header, path); cleanup: virDomainDefFree(def); -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org
participants (2)
-
Daniel P. Berrange
-
Eric Blake