qemu: Don't double-free disk->mirror if block commit initialization fails

disk->mirror would not be cleared while the local pointer was freed in
qemuDomainBlockCommit if qemuDomainObjExitMonitor or qemuBlockJobDiskNew
would return a failure.

Since block job handling is executed in the separate handler which needs
a qemu job, we don't need to pre-set the mirror state prior to starting
the job. Similarly the block copy job does not do that.

Move the setting of the data after starting the job so that we avoid
this problem.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: John Ferlan <jferlan@redhat.com>
This commit is contained in:
Peter Krempa 2019-01-24 10:35:48 +01:00
parent 06fa3366c6
commit f04bdf5368

View File

@ -18175,6 +18175,8 @@ qemuDomainBlockCommit(virDomainPtr dom,
disk->dst); disk->dst);
goto endjob; goto endjob;
} }
jobtype = QEMU_BLOCKJOB_TYPE_ACTIVE_COMMIT;
} else if (flags & VIR_DOMAIN_BLOCK_COMMIT_ACTIVE) { } else if (flags & VIR_DOMAIN_BLOCK_COMMIT_ACTIVE) {
virReportError(VIR_ERR_INVALID_ARG, virReportError(VIR_ERR_INVALID_ARG,
_("active commit requested but '%s' is not active"), _("active commit requested but '%s' is not active"),
@ -18247,22 +18249,16 @@ qemuDomainBlockCommit(virDomainPtr dom,
qemuDomainDiskChainElementPrepare(driver, vm, top_parent, false, false) < 0)) qemuDomainDiskChainElementPrepare(driver, vm, top_parent, false, false) < 0))
goto endjob; goto endjob;
if (!(job = qemuBlockJobDiskNew(disk, jobtype, device)))
goto endjob;
disk->mirrorState = VIR_DOMAIN_DISK_MIRROR_STATE_NONE;
/* Start the commit operation. Pass the user's original spelling, /* Start the commit operation. Pass the user's original spelling,
* if any, through to qemu, since qemu may behave differently * if any, through to qemu, since qemu may behave differently
* depending on whether the input was specified as relative or * depending on whether the input was specified as relative or
* absolute (that is, our absolute top_canon may do the wrong * absolute (that is, our absolute top_canon may do the wrong
* thing if the user specified a relative name). Be prepared for * thing if the user specified a relative name). */
* a ready event to occur while locks are dropped. */
if (mirror) {
disk->mirrorState = VIR_DOMAIN_DISK_MIRROR_STATE_NONE;
disk->mirror = mirror;
disk->mirrorJob = VIR_DOMAIN_BLOCK_JOB_TYPE_ACTIVE_COMMIT;
jobtype = QEMU_BLOCKJOB_TYPE_ACTIVE_COMMIT;
}
if (!(job = qemuBlockJobDiskNew(disk, jobtype, device)))
goto endjob;
qemuDomainObjEnterMonitor(driver, vm); qemuDomainObjEnterMonitor(driver, vm);
basePath = qemuMonitorDiskNameLookup(priv->mon, device, disk->src, basePath = qemuMonitorDiskNameLookup(priv->mon, device, disk->src,
baseSource); baseSource);
@ -18272,17 +18268,15 @@ qemuDomainBlockCommit(virDomainPtr dom,
ret = qemuMonitorBlockCommit(priv->mon, device, ret = qemuMonitorBlockCommit(priv->mon, device,
topPath, basePath, backingPath, topPath, basePath, backingPath,
speed); speed);
if (qemuDomainObjExitMonitor(driver, vm) < 0) { if (qemuDomainObjExitMonitor(driver, vm) < 0 || ret < 0) {
ret = -1; ret = -1;
goto endjob; goto endjob;
} }
if (ret == 0) { qemuBlockJobStarted(job);
qemuBlockJobStarted(job); if (mirror) {
mirror = NULL; VIR_STEAL_PTR(disk->mirror, mirror);
} else { disk->mirrorJob = VIR_DOMAIN_BLOCK_JOB_TYPE_ACTIVE_COMMIT;
disk->mirror = NULL;
disk->mirrorJob = VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN;
} }
if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0) if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0)