[libvirt] [PATCH v3 RESEND 08/12] qemu_domain: Introduce qemuDomainGetDiskBlockInfo

Jiri Denemark jdenemar at redhat.com
Wed Feb 20 13:44:33 UTC 2013


On Mon, Feb 18, 2013 at 15:38:41 +0100, Michal Privoznik wrote:
> This is just digging out important implementation from qemu
> driver's qemuDomainGetDiskBlockInfo() API as this functionality
> is going to be required in the next patch.
> ---
>  src/qemu/qemu_domain.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++++
>  src/qemu/qemu_domain.h |   4 ++
>  src/qemu/qemu_driver.c | 124 +++--------------------------------------------
>  3 files changed, 138 insertions(+), 117 deletions(-)
> 
> diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
> index 482f64a..8df2739 100644
> --- a/src/qemu/qemu_domain.c
> +++ b/src/qemu/qemu_domain.c
> @@ -40,6 +40,9 @@
>  
>  #include <sys/time.h>
>  #include <fcntl.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <unistd.h>
>  
>  #include <libxml/xpathInternals.h>
>  
> @@ -1959,3 +1962,127 @@ cleanup:
>      virObjectUnref(cfg);
>      return ret;
>  }
> +
> +int
> +qemuDomainGetDiskBlockInfo(virQEMUDriverPtr driver,
> +                           virDomainObjPtr vm,
> +                           virDomainDiskDefPtr disk,
> +                           virDomainBlockInfoPtr info)
> +{
> +
> +    int ret = -1;
> +    virStorageFileMetadata *meta = NULL;
> +    virQEMUDriverConfigPtr cfg = NULL;
> +    int format;
> +    struct stat sb;
> +    int fd = -1;
> +    off_t end;
> +    const char *path;
> +
> +    if (!disk->src) {
> +        virReportError(VIR_ERR_INVALID_ARG,
> +                       _("disk %s does not currently have a source assigned"),
> +                       disk->dst);
> +        goto cleanup;
> +    }
> +    path = disk->src;
> +    cfg = virQEMUDriverGetConfig(driver);
> +
> +    /* The path is correct, now try to open it and get its size. */
> +    if ((fd = open(path, O_RDONLY)) < 0) {

This should really check for -1 only, which is what the original code
did.

> +        virReportSystemError(errno, _("failed to open path '%s'"), path);
> +        goto cleanup;
> +    }
> +
> +    /* Probe for magic formats */
> +    if (disk->format) {
> +        format = disk->format;
> +    } else {
> +        if (cfg->allowDiskFormatProbing) {
> +            if ((format = virStorageFileProbeFormat(path,
> +                                                    cfg->user,
> +                                                    cfg->group)) < 0)
> +                goto cleanup;
> +        } else {
> +            virReportError(VIR_ERR_INTERNAL_ERROR,
> +                           _("no disk format for %s and probing is disabled"),
> +                           path);
> +            goto cleanup;
> +        }
> +    }
> +
> +    if (!(meta = virStorageFileGetMetadataFromFD(path, fd, format)))
> +        goto cleanup;
> +
> +    /* Get info for normal formats */
> +    if (fstat(fd, &sb) < 0) {
> +        virReportSystemError(errno, _("cannot stat file '%s'"), path);
> +        goto cleanup;
> +    }
> +
> +    if (S_ISREG(sb.st_mode)) {
> +#ifndef WIN32
> +        info->physical = (unsigned long long)sb.st_blocks *
> +            (unsigned long long)DEV_BSIZE;
> +#else
> +        info->physical = sb.st_size;
> +#endif
> +        /* Regular files may be sparse, so logical size (capacity) is not same
> +         * as actual physical above
> +         */
> +        info->capacity = sb.st_size;
> +    } else {
> +        /* NB. Because we configure with AC_SYS_LARGEFILE, off_t should
> +         * be 64 bits on all platforms.
> +         */
> +        end = lseek(fd, 0, SEEK_END);
> +        if (end == (off_t)-1) {
> +            virReportSystemError(errno, _("failed to seek to end of %s"), path);
> +            goto cleanup;
> +        }
> +        info->physical = end;
> +        info->capacity = end;
> +    }
> +
> +    /* If the file we probed has a capacity set, then override
> +     * what we calculated from file/block extents */
> +    if (meta->capacity)
> +        info->capacity = meta->capacity;
> +
> +    /* Set default value .. */
> +    info->allocation = info->physical;
> +
> +    /* ..but if guest is running & not using raw
> +       disk format and on a block device, then query
> +       highest allocated extent from QEMU */
> +    if (disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK &&
> +        format != VIR_STORAGE_FILE_RAW &&
> +        S_ISBLK(sb.st_mode) &&
> +        virDomainObjIsActive(vm)) {
> +        qemuDomainObjPrivatePtr priv = vm->privateData;
> +
> +        if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
> +            goto cleanup;
> +
> +        if (virDomainObjIsActive(vm)) {
> +            qemuDomainObjEnterMonitor(driver, vm);
> +            ret = qemuMonitorGetBlockExtent(priv->mon,
> +                                            disk->info.alias,
> +                                            &info->allocation);
> +            qemuDomainObjExitMonitor(driver, vm);
> +        } else {
> +            ret = 0;
> +        }
> +
> +        if (qemuDomainObjEndJob(driver, vm) == 0)
> +            vm = NULL;

As already found by John, this would not work. You either need to move
setting up the job outside of this function or pass a reference to vm
inside.

> +    } else {
> +        ret = 0;
> +    }
> +
> +cleanup:
> +    VIR_FORCE_CLOSE(fd);
> +    virStorageFileFreeMetadata(meta);
> +    virObjectUnref(cfg);
> +    return ret;
> +}
...

Jirka




More information about the libvir-list mailing list