[libvirt] [PATCH v1 4/5] qemu_migration: Send disk sizes to the other side

Peter Krempa pkrempa at redhat.com
Mon Dec 1 11:01:59 UTC 2014


On 11/27/14 14:55, Michal Privoznik wrote:
> Up 'til now, users need to precreate non-shared storage on migration
> themselves. This is not very friendly requirement and we should do
> something about it. In this patch, the migration cookie is extended,
> so that <nbd/> section does not only contain NBD port, but info on
> disks being migrated. This patch sends a list of pairs of:
> 
>     <disk target; disk size>
> 
> to the destination. The actual storage allocation is left for next
> commit.
> 
> Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
> ---
>  src/qemu/qemu_migration.c | 180 +++++++++++++++++++++++++++++++++++++++++-----
>  1 file changed, 161 insertions(+), 19 deletions(-)
> 
> diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
> index a1b1458..d4b3acf 100644
> --- a/src/qemu/qemu_migration.c
> +++ b/src/qemu/qemu_migration.c
> @@ -141,6 +141,10 @@ typedef struct _qemuMigrationCookieNBD qemuMigrationCookieNBD;
>  typedef qemuMigrationCookieNBD *qemuMigrationCookieNBDPtr;
>  struct _qemuMigrationCookieNBD {
>      int port; /* on which port does NBD server listen for incoming data */
> +
> +    size_t ndisks;  /* Number of items in @target and @alloc arrays */
> +    char **target;  /* Disk target */
> +    size_t *alloc;  /* And its allocation */

I think this already warrants usage of a struct to group them together.

>  };
>  
>  typedef struct _qemuMigrationCookie qemuMigrationCookie;


> @@ -523,18 +540,86 @@ qemuMigrationCookieAddNetwork(qemuMigrationCookiePtr mig,
>  }
>  
>  
> +/**
> + * qemuMigrationGetDiskSize:
> + * @disk: disk to query
> + * @alloc: disk size in bytes

Allocation and capacity are two different stats of a disk volume. You
should stick with capacity here to avoid confusion

> + *
> + * For given disk get its image size.
> + *
> + * Returns: 0 on success,
> + *         -1 on failure,
> + *          1 if disk size doesn't matter
> + */
> +static int
> +qemuMigrationGetDiskSize(virQEMUDriverPtr driver,
> +                         virDomainObjPtr vm,
> +                         virDomainDiskDefPtr disk,
> +                         size_t *alloc)
> +{
> +    int ret = -1;
> +    virDomainBlockInfo info;
> +
> +    if (!virStorageSourceIsLocalStorage(disk->src) ||
> +        !disk->src->path)
> +        return 1;
> +
> +    if (qemuDomainGetBlockInfoImpl(driver, vm, disk,
> +                                   &info, disk->src->path) < 0)
> +        goto cleanup;

Since you are requesting this only for a live domain and the only stat
you care about is capacity of the guest visible portion of the disk it
would be better to use a monitor call to determine the data from the
disk rather than use the weird function that parses the information from
the file on the disk.


> +
> +    *alloc = info.capacity;
> +    ret = 0;
> + cleanup:
> +    return ret;
> +}
> +
> +
>  static int
>  qemuMigrationCookieAddNBD(qemuMigrationCookiePtr mig,
> -                          virQEMUDriverPtr driver ATTRIBUTE_UNUSED,
> +                          virQEMUDriverPtr driver,
>                            virDomainObjPtr vm)
>  {
>      qemuDomainObjPrivatePtr priv = vm->privateData;
> +    size_t i;
>  
>      /* It is not a bug if there already is a NBD data */
>      if (!mig->nbd &&
>          VIR_ALLOC(mig->nbd) < 0)
>          return -1;
>  
> +    if (vm->def->ndisks &&
> +        (VIR_ALLOC_N(mig->nbd->target, vm->def->ndisks) < 0 ||
> +         VIR_ALLOC_N(mig->nbd->alloc, vm->def->ndisks) < 0))

Allocing an array of strutcts would look nicer.

> +        return -1;
> +    mig->nbd->ndisks = 0;
> +
> +    for (i = 0; i < vm->def->ndisks; i++) {
> +        virDomainDiskDefPtr disk = vm->def->disks[i];
> +        int rc;
> +        size_t alloc;
> +
> +        /* skip shared, RO and source-less disks */
> +        if (disk->src->shared || disk->src->readonly ||
> +            !virDomainDiskGetSource(disk))

I think also networked disks don't make sense here. We also have a
function (virStorageSourceIsEmpty or similar) to check whether the
source doesn't denote an empty drive.

One additional thing that might break is if some of the storage is on a
shared storage system, while other is not.

> +            continue;
> +
> +        if ((rc = qemuMigrationGetDiskSize(driver, vm, disk, &alloc)) < 0) {
> +            /* error reported */

We report errors by default. No need to note it explicitly.

> +            return -1;
> +        } else if (rc > 0) {
> +            /* Don't add this disk */
> +            continue;
> +        }
> +
> +        if (VIR_STRDUP(mig->nbd->target[mig->nbd->ndisks],
> +                       disk->dst) < 0)
> +            return -1;
> +
> +        mig->nbd->alloc[mig->nbd->ndisks] = alloc;
> +        mig->nbd->ndisks++;
> +    }
> +
>      mig->nbd->port = priv->nbdPort;
>      mig->flags |= QEMU_MIGRATION_COOKIE_NBD;
>  
> @@ -763,7 +848,18 @@ qemuMigrationCookieXMLFormat(virQEMUDriverPtr driver,
>          virBufferAddLit(buf, "<nbd");
>          if (mig->nbd->port)
>              virBufferAsprintf(buf, " port='%d'", mig->nbd->port);
> -        virBufferAddLit(buf, "/>\n");
> +        if (mig->nbd->ndisks) {
> +            virBufferAddLit(buf, ">\n");
> +            virBufferAdjustIndent(buf, 2);
> +            for (i = 0; i < mig->nbd->ndisks; i++)
> +                virBufferAsprintf(buf, "<disk target='%s' alloc='%zu'/>\n",

Again ... capacity is a better word for this IMO.

> +                                  mig->nbd->target[i],
> +                                  mig->nbd->alloc[i]);
> +            virBufferAdjustIndent(buf, -2);
> +            virBufferAddLit(buf, "</nbd>\n");
> +        } else {
> +            virBufferAddLit(buf, "/>\n");
> +        }
>      }
>  
>      if (mig->flags & QEMU_MIGRATION_COOKIE_STATS && mig->jobInfo)
> @@ -891,6 +987,65 @@ qemuMigrationCookieNetworkXMLParse(xmlXPathContextPtr ctxt)
>  }
>  
>  
> +static qemuMigrationCookieNBDPtr
> +qemuMigrationCookieNBDXMLParse(xmlXPathContextPtr ctxt)
> +{
> +    qemuMigrationCookieNBDPtr ret = NULL;
> +    char *port = NULL, *alloc = NULL;
> +    size_t i;
> +    int n;
> +    xmlNodePtr *disks = NULL;
> +    xmlNodePtr save_ctxt = ctxt->node;
> +
> +    if (VIR_ALLOC(ret) < 0)
> +        goto error;
> +
> +    port = virXPathString("string(./nbd/@port)", ctxt);
> +    if (port && virStrToLong_i(port, NULL, 10, &ret->port) < 0) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR,
> +                       _("Malformed nbd port '%s'"),
> +                       port);
> +        goto error;
> +    }
> +
> +    /* Now check if source sent a list of disks to prealloc. We might be
> +     * talking to an older server, so it's not an error if the list is
> +     * missing. */
> +    if ((n = virXPathNodeSet("./nbd/disk", ctxt, &disks)) > 0) {
> +        if (VIR_ALLOC_N(ret->target, n) < 0 ||
> +            VIR_ALLOC_N(ret->alloc, n) < 0)

capacity ...

> +            goto error;
> +        ret->ndisks = n;
> +
> +        for (i = 0; i < n; i++) {
> +            ctxt->node = disks[i];
> +            VIR_FREE(alloc);
> +
> +            ret->target[i] = virXPathString("string(./@target)", ctxt);
> +            alloc = virXPathString("string(./@alloc)", ctxt);
> +            if (virStrToLong_ull(alloc, NULL, 10, (unsigned long long *)
> +                                 &ret->alloc[i]) < 0) {
> +                virReportError(VIR_ERR_INTERNAL_ERROR,
> +                               _("Malformed disk allocation: '%s'"),
> +                               alloc);
> +                goto error;
> +            }
> +        }
> +    }
> +
> + cleanup:
> +    VIR_FREE(port);
> +    VIR_FREE(alloc);
> +    VIR_FREE(disks);
> +    ctxt->node = save_ctxt;
> +    return ret;
> + error:
> +    qemuMigrationCookieNBDFree(ret);
> +    ret = NULL;
> +    goto cleanup;
> +}
> +
> +
>  static qemuDomainJobInfoPtr
>  qemuMigrationCookieStatisticsXMLParse(xmlXPathContextPtr ctxt)
>  {
> @@ -1123,22 +1278,9 @@ qemuMigrationCookieXMLParse(qemuMigrationCookiePtr mig,
>          goto error;
>  
>      if (flags & QEMU_MIGRATION_COOKIE_NBD &&
> -        virXPathBoolean("boolean(./nbd)", ctxt)) {
> -        char *port;
> -
> -        if (VIR_ALLOC(mig->nbd) < 0)
> -            goto error;
> -
> -        port = virXPathString("string(./nbd/@port)", ctxt);
> -        if (port && virStrToLong_i(port, NULL, 10, &mig->nbd->port) < 0) {
> -            virReportError(VIR_ERR_INTERNAL_ERROR,
> -                           _("Malformed nbd port '%s'"),
> -                           port);
> -            VIR_FREE(port);
> -            goto error;
> -        }
> -        VIR_FREE(port);
> -    }
> +        virXPathBoolean("boolean(./nbd)", ctxt) &&
> +        (!(mig->nbd = qemuMigrationCookieNBDXMLParse(ctxt))))
> +        goto error;
>  
>      if (flags & QEMU_MIGRATION_COOKIE_STATS &&
>          virXPathBoolean("boolean(./statistics)", ctxt) &&
> 


Peter

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


More information about the libvir-list mailing list