[libvirt] [PATCHv3 07/10] threshold: track an allocation node name for a storage source

Peter Krempa pkrempa at redhat.com
Tue Jun 23 13:51:11 UTC 2015


On Mon, Jun 22, 2015 at 17:06:43 -0600, Eric Blake wrote:
> Set up functions to make it easy to map between libvirt disk
> names and qemu node names.  Although we won't expose the
> information in XML, it is still nicer to cache the information
> than to have to grab a job lock, so that we are less likely
> to need to re-query the monitor when dealing with a qemu
> monitor event.  We need the information in two places: one in
> the hash table used to collect QMP stats (as the QMP design
> requires using 'query-blockstats' to learn node names,
> followed by 'query-named-block-nodes' to learn statistics
> about those nodes), and the other in virStorageSourcePtr (the
> disk information tracked by libvirt).  Making sure this
> doesn't leak memory was interesting; in particular, in
> qemu_driver.c:qemUDomainBlocksStatsGather(), I made sure that
> the returned result does not set an allocation name, so that
> the callers of that function can continue to use VIR_FREE.
> 
> * src/util/virstoragefile.h (_virStorageSource): Add a field.
> * src/util/virstoragefile.c (virStorageSourceBackingStoreClear):
> Clear it.
> (virStorageSourceCopy): Document that it is not deep-copied.
> * src/qemu/qemu_domain.c (qemuDomainDiskGetAllocationNode)
> (qemuDomainDiskResolveAllocationNode): New functions, to use the
> field.
> (qemuDomainDiskSupportsAllocationNode): New helper.
> * src/qemu/qemu_domain.h: Declare new functions.
> * src/qemu/qemu_monitor.h (_qemuBlockStats): Add fields.
> (qemuMonitorCleanBlockStats): New declaration.
> * src/qemu/qemu_monitor.c (qemuMonitorCleanBlockStats): New
> function.
> (qemuMonitorGetAllBlockStatsInfo): Use it to avoid leak.
> * src/qemu/qemu_migration.c (qemuMigrationCookieAddNBD):
> Likewise.
> * src/qemu/qemu_driver.c (qemuDomainBlocksStatsGather): Don't leak
> memory.
> * tests/qemumonitortest.c (testBlockInfoData): Update test.
> ---
>  src/qemu/qemu_domain.c    | 105 ++++++++++++++++++++++++++++++++++++++++++++++
>  src/qemu/qemu_domain.h    |  10 ++++-
>  src/qemu/qemu_driver.c    |   1 +
>  src/qemu/qemu_migration.c |   2 +-
>  src/qemu/qemu_monitor.c   |  12 +++++-
>  src/qemu/qemu_monitor.h   |   4 ++
>  src/util/virstoragefile.c |   4 +-
>  src/util/virstoragefile.h |   3 +-
>  tests/qemumonitortest.c   |  13 +++---
>  9 files changed, 143 insertions(+), 11 deletions(-)
> 
> diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
> index 6213fd9..d3ce7db 100644
> --- a/src/qemu/qemu_domain.c
> +++ b/src/qemu/qemu_domain.c
> @@ -2906,6 +2906,111 @@ qemuDomainDetermineDiskChain(virQEMUDriverPtr driver,
>  }
> 
> 
> +static bool
> +qemuDomainDiskSupportsAllocationNode(virDomainDiskDefPtr disk)
> +{
> +    /* For now, only qcow2 images backed by block devices are supported. */
> +    if (disk->src->type != VIR_STORAGE_TYPE_BLOCK)
> +        return false;
> +    if (disk->src->format != VIR_STORAGE_FILE_QCOW2)
> +        return false;
> +    return true;
> +}
> +
> +
> +/* Determine the node name that qemu associates with allocation
> + * tracking.  Cache the value to minimize queries.  Return NULL if the
> + * storage source is not a qcow2 formatted block device (as those are
> + * the only devices where live allocation tracking is useful), or if
> + * qemu cannot determine a node name.  Requires a live domain, and
> + * assumes that the job lock is held, as this may require monitor
> + * interaction.  */
> +const char *
> +qemuDomainDiskGetAllocationNode(virQEMUDriverPtr driver,
> +                                virDomainObjPtr vm,
> +                                virDomainDiskDefPtr disk)
> +{
> +    virStorageSourcePtr src = disk->src;
> +    char *name = NULL;
> +    qemuDomainObjPrivatePtr priv = vm->privateData;
> +
> +    if (!qemuDomainDiskSupportsAllocationNode(disk))
> +        return NULL;
> +
> +    if (src->allocation_node)
> +        goto cleanup;
> +
> +    qemuDomainObjEnterMonitor(driver, vm);
> +    /* TODO: allow lookup of node name of backing images */
> +    name = qemuMonitorNodeNameLookup(priv->mon, disk->info.alias);
> +    if (qemuDomainObjExitMonitor(driver, vm) < 0)
> +        goto cleanup;
> +
> +    src->allocation_node = name;
> +    name = NULL;
> +
> + cleanup:
> +    VIR_FREE(name);
> +    return src->allocation_node;
> +}
> +
> +
> +/* Determine the disk name that matches a node name returned by qemu
> + * in a threshold event.  In the common case, no job is needed: the
> + * node name will be cached from when the threshold was
> + * registered. But if the cache is lost (such as over a libvirtd
> + * restart), JOB_OKAY states whether it is safe to rebuild the cache
> + * (requires a live domain and monitor interaction), instead of
> + * failing. */
> +virDomainDiskDefPtr
> +qemuDomainDiskResolveAllocationNode(virQEMUDriverPtr driver,
> +                                    virDomainObjPtr vm,
> +                                    const char *node,
> +                                    bool job_okay)
> +{
> +    size_t i;
> +    virDomainDiskDefPtr disk;
> +    virDomainDiskDefPtr ret = NULL;
> +    char *name = NULL;
> +    qemuDomainObjPrivatePtr priv = vm->privateData;
> +
> +    /* First pass - see if the node name is cached.  */
> +    for (i = 0; i < vm->def->ndisks; i++) {
> +        disk = vm->def->disks[i];
> +        if (!qemuDomainDiskSupportsAllocationNode(disk))
> +            continue;
> +        if (STREQ_NULLABLE(disk->src->allocation_node, node))
> +            return disk;
> +    }
> +
> +    /* Second pass - query the monitor. */
> +    if (!job_okay)
> +        return NULL;
> +    for (i = 0; i < vm->def->ndisks; i++) {
> +        disk = vm->def->disks[i];
> +        if (!qemuDomainDiskSupportsAllocationNode(disk) ||
> +            disk->src->allocation_node)
> +            continue;
> +
> +        qemuDomainObjEnterMonitor(driver, vm);
> +        name = qemuMonitorNodeNameLookup(priv->mon, disk->info.alias);
> +        if (qemuDomainObjExitMonitor(driver, vm) < 0)
> +            goto cleanup;
> +
> +        disk->src->allocation_node = name;
> +        name = NULL;
> +        if (STREQ_NULLABLE(disk->src->allocation_node, node)) {
> +            ret = disk;
> +            break;
> +        }
> +    }
> +
> + cleanup:
> +    VIR_FREE(name);
> +    return ret;
> +}

Rather than doing the ad-hoc back and forth mapping I think we should
cache all node names for all disks when reconnecting to the monitor and
when we complete a snapshot operation. This will simplfiy the event code
quite a bit and additionally it will be more future proof.


> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> index c1373de..25bc76d 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c
> @@ -10967,6 +10967,7 @@ qemuDomainBlocksStatsGather(virQEMUDriverPtr driver,
>                             _("cannot find statistics for device '%s'"), diskAlias);
>              goto cleanup;
>          }
> +        VIR_FREE(stats->allocation_node);

The callers should use qemuMonitorCleanBlockStats rather than deleting
it here.

> 
>          **retstats = *stats;
>      } else {

...

> diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
> index 5612491..86dc4be 100644
> --- a/src/qemu/qemu_monitor.c
> +++ b/src/qemu/qemu_monitor.c
> @@ -1763,6 +1763,16 @@ qemuMonitorBlockInfoLookup(virHashTablePtr blockInfo,
>  }
> 
> 
> +/* Callback for use in cleaning up a hash used by
> + * qemuMonitorGetAllBlockStatsInfo. */
> +void
> +qemuMonitorCleanBlockStats(void *opaque, const void *name ATTRIBUTE_UNUSED)

We use either Clear or Free. I'd go with qemuMonitorBlockStatsFree.

> +{
> +    qemuBlockStatsPtr stats = opaque;
> +    VIR_FREE(stats->allocation_node);
> +    VIR_FREE(stats);
> +}
> +
>  /**
>   * qemuMonitorGetAllBlockStatsInfo:
>   * @mon: monitor object

...

> diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
> index 826835b..c0ea2ee 100644
> --- a/src/qemu/qemu_monitor.h
> +++ b/src/qemu/qemu_monitor.h
> @@ -379,8 +379,12 @@ struct _qemuBlockStats {
>      unsigned long long capacity;
>      unsigned long long physical;
>      unsigned long long wr_highest_offset;
> +    char *allocation_node;

See below ...

> diff --git a/src/util/virstoragefile.h b/src/util/virstoragefile.h
> index aa17a00..8b2f491 100644
> --- a/src/util/virstoragefile.h
> +++ b/src/util/virstoragefile.h
> @@ -1,7 +1,7 @@
>  /*
>   * virstoragefile.h: file utility functions for FS storage backend
>   *
> - * Copyright (C) 2007-2009, 2012-2014 Red Hat, Inc.
> + * Copyright (C) 2007-2009, 2012-2015 Red Hat, Inc.
>   * Copyright (C) 2007-2008 Daniel P. Berrange
>   *
>   * This library is free software; you can redistribute it and/or
> @@ -260,6 +260,7 @@ struct _virStorageSource {
>      unsigned long long capacity; /* in bytes, 0 if unknown */
>      unsigned long long allocation; /* in bytes, 0 if unknown */
>      unsigned long long physical; /* in bytes, 0 if unknown */
> +    char *allocation_node; /* cache of node name for tracking allocation */

The node name will be useful for other operations too so I'd choose a
more universal name.

>      size_t nseclabels;
>      virSecurityDeviceLabelDefPtr *seclabels;
> 

Peter
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20150623/b2132982/attachment-0001.sig>


More information about the libvir-list mailing list