[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