[libvirt] [PATCH 03/12] qemu: refactor blockinfo job handling
John Ferlan
jferlan at redhat.com
Mon Dec 8 11:41:54 UTC 2014
On 12/06/2014 03:14 AM, Eric Blake wrote:
> In order for a future patch to virDomainListGetStats to reuse
> some code for determining disk usage of offline domains, we
> need to make it easier to pull out part of the guts of grabbing
> blockinfo. The current implementation grabs a job fairly late
> in the game, while getstats will already own a job; reordering
> things so that the job is always grabbed up front in both
> functions will make it easier to pull out the common code.
> This patch results in grabbing a job in cases where one was not
> previously needed, but as it is a query job, it should not be
> noticeably slower.
>
> This patch touches the same code as the fix for CVE-2014-6458
> (commit b799259); in that patch, we avoided hotplug changing
> a disk reference during the time of obtaining a monitor lock
> by copying all data we needed and no longer referencing disk;
> this patch goes the other way and ensures that by holding the
> job, the disk cannot be changed so we no longer need to worry
> about the disk being invalidated across the monitor lock.
>
> * src/qemu/qemu_driver.c (qemuDomainGetBlockInfo): Rearrange job
> control to be outside of disk information.
>
Ran thru my Coverity checker...
> Signed-off-by: Eric Blake <eblake at redhat.com>
> ---
> src/qemu/qemu_driver.c | 62 +++++++++++++++++++++++---------------------------
> 1 file changed, 29 insertions(+), 33 deletions(-)
>
> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> index a7b208f..ae4485a 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c
> @@ -10999,7 +10999,6 @@ qemuDomainGetBlockInfo(virDomainPtr dom,
> int format;
> bool activeFail = false;
> virQEMUDriverConfigPtr cfg = NULL;
> - char *alias = NULL;
> char *buf = NULL;
> ssize_t len;
>
> @@ -11018,11 +11017,19 @@ qemuDomainGetBlockInfo(virDomainPtr dom,
> goto cleanup;
> }
>
> + /* Technically, we only need a job if we are going to query the
> + * monitor, which is only for active domains that are using
> + * non-raw block devices. But it is easier to share code if we
> + * always grab a job; furthermore, grabbing the job ensures that
> + * hot-plug won't change disk behind our backs. */
> + if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
> + goto cleanup;
> +
> /* Check the path belongs to this domain. */
> if ((idx = virDomainDiskIndexByName(vm->def, path, false)) < 0) {
> virReportError(VIR_ERR_INVALID_ARG,
> _("invalid path %s not assigned to domain"), path);
> - goto cleanup;
> + goto endjob;
> }
>
> disk = vm->def->disks[idx];
> @@ -11032,36 +11039,36 @@ qemuDomainGetBlockInfo(virDomainPtr dom,
> virReportError(VIR_ERR_INVALID_ARG,
> _("disk '%s' does not currently have a source assigned"),
> path);
> - goto cleanup;
> + goto endjob;
> }
>
> if ((fd = qemuOpenFile(driver, vm, disk->src->path, O_RDONLY,
> NULL, NULL)) == -1)
> - goto cleanup;
> + goto endjob;
>
> if (fstat(fd, &sb) < 0) {
> virReportSystemError(errno,
> _("cannot stat file '%s'"), disk->src->path);
> - goto cleanup;
> + goto endjob;
> }
>
> if ((len = virFileReadHeaderFD(fd, VIR_STORAGE_MAX_HEADER, &buf)) < 0) {
> virReportSystemError(errno, _("cannot read header '%s'"),
> disk->src->path);
> - goto cleanup;
> + goto endjob;
> }
> } else {
> if (virStorageFileInitAs(disk->src, cfg->user, cfg->group) < 0)
> - goto cleanup;
> + goto endjob;
>
> if ((len = virStorageFileReadHeader(disk->src, VIR_STORAGE_MAX_HEADER,
> &buf)) < 0)
> - goto cleanup;
> + goto endjob;
>
> if (virStorageFileStat(disk->src, &sb) < 0) {
> virReportSystemError(errno, _("failed to stat remote file '%s'"),
> NULLSTR(disk->src->path));
> - goto cleanup;
> + goto endjob;
> }
> }
>
> @@ -11073,17 +11080,17 @@ qemuDomainGetBlockInfo(virDomainPtr dom,
> virReportError(VIR_ERR_INTERNAL_ERROR,
> _("no disk format for %s and probing is disabled"),
> path);
> - goto cleanup;
> + goto endjob;
> }
>
> if ((format = virStorageFileProbeFormatFromBuf(disk->src->path,
> buf, len)) < 0)
> - goto cleanup;
> + goto endjob;
> }
>
> if (!(meta = virStorageFileGetMetadataFromBuf(disk->src->path, buf, len,
> format, NULL)))
> - goto cleanup;
> + goto endjob;
>
> /* Get info for normal formats */
> if (S_ISREG(sb.st_mode) || fd == -1) {
> @@ -11105,7 +11112,7 @@ qemuDomainGetBlockInfo(virDomainPtr dom,
> if (end == (off_t)-1) {
> virReportSystemError(errno,
> _("failed to seek to end of %s"), path);
> - goto cleanup;
> + goto endjob;
> }
> info->physical = end;
> info->capacity = end;
> @@ -11133,35 +11140,24 @@ qemuDomainGetBlockInfo(virDomainPtr dom,
> if (!virDomainObjIsActive(vm)) {
> activeFail = true;
> ret = 0;
> - goto cleanup;
> + goto endjob;
> }
>
> - if (VIR_STRDUP(alias, disk->info.alias) < 0)
> - goto cleanup;
> + qemuDomainObjEnterMonitor(driver, vm);
> + ret = qemuMonitorGetBlockExtent(priv->mon,
> + disk->info.alias,
> + &info->allocation);
> + qemuDomainObjExitMonitor(driver, vm);
>
> - if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
> - goto cleanup;
> -
> - if (virDomainObjIsActive(vm)) {
> - qemuDomainObjEnterMonitor(driver, vm);
> - ret = qemuMonitorGetBlockExtent(priv->mon,
> - alias,
> - &info->allocation);
> - qemuDomainObjExitMonitor(driver, vm);
> - } else {
> - activeFail = true;
> - ret = 0;
> - }
> -
> - if (!qemuDomainObjEndJob(driver, vm))
> - vm = NULL;
> } else {
> ret = 0;
> }
>
> + endjob:
> + if (!qemuDomainObjEndJob(driver, vm))
> + vm = NULL;
This makes a virObjectUnlock(vm); in the following cleanup section
unhappy...
11215 if (!qemuDomainObjEndJob(driver, vm))
(18) Event assign_zero: Assigning: "vm" = "NULL".
Also see events: [var_deref_model]
11216 vm = NULL;
> cleanup:
> VIR_FREE(buf);
> - VIR_FREE(alias);
> virStorageSourceFree(meta);
> VIR_FORCE_CLOSE(fd);
> if (disk)
>
11225 }
(21) Event var_deref_model: Passing null pointer "vm" to
"virObjectUnlock", which dereferences it. (The dereference is assumed on
the basis of the 'nonnull' parameter attribute.)
Also see events: [assign_zero]
11226 virObjectUnlock(vm);
More information about the libvir-list
mailing list