[libvirt] [PATCH v3 04/13] Merge virDomainObjListIsDuplicate into virDomainObjListAdd

Jiri Denemark jdenemar at redhat.com
Mon Feb 4 15:58:25 UTC 2013


On Fri, Feb 01, 2013 at 11:18:26 +0000, Daniel P. Berrange wrote:
> From: "Daniel P. Berrange" <berrange at redhat.com>
> 
> The duplicate VM checking should be done atomically with
> virDomainObjListAdd, so shoud not be a separate function.
> Instead just use flags to indicate what kind of checks are
> required.
> 
...
> This pair, used in virDomainDefinXML:

s/Defin/Define/

> 
>    if (virDomainObjListIsDuplicate(privconn->domains, def, 0) < 0)
>      goto cleanup;
>    if (!(dom = virDomainObjListAdd(privconn->domains,
>                                    privconn->caps,
>                                    def, false)))
>      goto cleanup;
> 
> Changes to
> 
>    if (!(dom = virDomainObjListAdd(privconn->domains,
>                                    privconn->caps,
>                                    def,
>                                    0, NULL)))
>      goto cleanup;
...
> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
> index 3861e68..79da5eb 100644
> --- a/src/conf/domain_conf.c
> +++ b/src/conf/domain_conf.c
> @@ -1871,30 +1871,91 @@ void virDomainObjAssignDef(virDomainObjPtr domain,
>      }
>  }
>  
> +
> +
> +/*
> + *
> + * If flags & VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE then
> + * this will refuse updating an existing def if the
> + * current def is Live

It would be cool to have VIR_DOMAIN_OBJ_LIST_ADD_LIVE documented here
too :-)

> + *
> + */
>  virDomainObjPtr virDomainObjListAdd(virDomainObjListPtr doms,
>                                      virCapsPtr caps,
>                                      const virDomainDefPtr def,
> -                                    bool live)
> +                                    unsigned int flags,
> +                                    virDomainDefPtr *oldDef)
>  {
> -    virDomainObjPtr domain;
> +    virDomainObjPtr vm;
>      char uuidstr[VIR_UUID_STRING_BUFLEN];
> +    if (oldDef)
> +        *oldDef = false;
>  
> -    if ((domain = virDomainObjListFindByUUID(doms, def->uuid))) {
> -        virDomainObjAssignDef(domain, def, live);
> -        return domain;
> -    }
> +    /* See if a VM with matching UUID already exists */
> +    if ((vm = virDomainObjListFindByUUID(doms, def->uuid))) {
> +        /* UUID matches, but if names don't match, refuse it */
> +        if (STRNEQ(vm->def->name, def->name)) {
> +            virUUIDFormat(vm->def->uuid, uuidstr);
> +            virReportError(VIR_ERR_OPERATION_FAILED,
> +                           _("domain '%s' is already defined with uuid %s"),
> +                           vm->def->name, uuidstr);

    virObjectUnlock(vm);
    vm = NULL;

> +            goto cleanup;
> +        }
>  
> -    if (!(domain = virDomainObjNew(caps)))
> -        return NULL;
> -    domain->def = def;
> +        if (flags & VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE) {
> +            /* UUID & name match, but if VM is already active, refuse it */
> +            if (virDomainObjIsActive(vm)) {
> +                virReportError(VIR_ERR_OPERATION_INVALID,
> +                               _("domain is already active as '%s'"),
> +                               vm->def->name);

    virObjectUnlock(vm);
    vm = NULL;

Given that you need to repeat the same code in three places in this
function, it might be worth a dedicated "duplicate" label.

> +                goto cleanup;
> +            }
> +        }
>  
> -    virUUIDFormat(def->uuid, uuidstr);
> -    if (virHashAddEntry(doms->objs, uuidstr, domain) < 0) {
> -        VIR_FREE(domain);
> -        return NULL;
> -    }

So the following if statement is effectively copying
virDomainObjAssignDef with a small addition which allows for returning
the replaced def in *oldDef. Given how hard to read the code is (mainly
because newDef is not a very good name) I'd prefer to keep it only once
and call enhanced virDomainObjAssignDef from here.

> +        if (virDomainObjIsActive(vm)) {
> +            if (oldDef)
> +                *oldDef = vm->newDef;
> +            else
> +                virDomainDefFree(vm->newDef);
> +            vm->newDef = def;
> +        } else {
> +            if (flags & VIR_DOMAIN_OBJ_LIST_ADD_LIVE) {
> +                if (!vm->newDef)
> +                    vm->newDef = vm->def;
> +                else
> +                    virDomainDefFree(vm->newDef);

This else branch is not in virDomainObjAssignDef and seems to be wrong.
If you call virDomainObjListAdd with VIR_DOMAIN_OBJ_LIST_ADD_LIVE twice
in a row, you will lose the original def (in vm->newDef). It looks like
virDomainObjAssignDef is not correct either as we either store vm->def
in vm->newDef or replace it without freeing. So I think you wanted to
virDomainDefFree vm->def rather than vm->newDef and also add this branch
to virDomainObjAssignDef. Another argument against copying the code
here.

> +            } else {
> +                if (oldDef)
> +                    *oldDef = vm->def;
> +                else
> +                    virDomainDefFree(vm->def);
> +            }
> +            vm->def = def;
> +        }
> +    } else {
> +        /* UUID does not match, but if a name matches, refuse it */
> +        if ((vm = virDomainObjListFindByName(doms, def->name))) {
> +            virUUIDFormat(vm->def->uuid, uuidstr);
> +            virReportError(VIR_ERR_OPERATION_FAILED,
> +                           _("domain '%s' already exists with uuid %s"),
> +                           def->name, uuidstr);
> +            virObjectUnlock(vm);
> +            vm = NULL;
> +            goto cleanup;
> +        }
>  
> -    return domain;
> +        if (!(vm = virDomainObjNew(caps)))
> +            goto cleanup;
> +        vm->def = def;
> +
> +        virUUIDFormat(def->uuid, uuidstr);
> +        if (virHashAddEntry(doms->objs, uuidstr, vm) < 0) {
> +            VIR_FREE(vm);

Shouldn't this be virObjectUnref(vm)?

> +            return NULL;
> +        }
> +    }
> +cleanup:
> +    return vm;
>  }
>  
>  /*
...
> diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
> index 3ad1173..fa13e24 100644
> --- a/src/conf/domain_conf.h
> +++ b/src/conf/domain_conf.h
> @@ -1968,10 +1968,15 @@ virDomainChrDefPtr virDomainChrDefNew(void);
>  
>  /* live == true means def describes an active domain (being migrated or
>   * restored) as opposed to a new persistent configuration of the domain */

This commend would deserve some modifications :-)

> +enum {
> +    VIR_DOMAIN_OBJ_LIST_ADD_LIVE = (1 << 0),
> +    VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE = (1 << 1),
> +};
>  virDomainObjPtr virDomainObjListAdd(virDomainObjListPtr doms,
>                                      virCapsPtr caps,
>                                      const virDomainDefPtr def,
> -                                    bool live);
> +                                    unsigned int flags,
> +                                    virDomainDefPtr *oldDef);
>  void virDomainObjAssignDef(virDomainObjPtr domain,
>                             const virDomainDefPtr def,
>                             bool live);
...
> diff --git a/src/openvz/openvz_conf.c b/src/openvz/openvz_conf.c
> index 6eacbca..84ba3d6 100644
> --- a/src/openvz/openvz_conf.c
> +++ b/src/openvz/openvz_conf.c
> @@ -642,17 +642,13 @@ int openvzLoadDomains(struct openvz_driver *driver) {
>          openvzReadMemConf(def, veid);
>  
>          virUUIDFormat(def->uuid, uuidstr);
> -        if (virDomainObjListIsDuplicate(driver->domains, def, true)) {
> -            virReportError(VIR_ERR_INTERNAL_ERROR,
> -                           _("Duplicate container UUID %s detected for %d"),
> -                           uuidstr,
> -                           veid);
> -            goto cleanup;
> -        }
>          if (!(dom = virDomainObjListAdd(driver->domains,
>                                          driver->caps,
>                                          def,
> -                                        STRNEQ(status, "stopped"))))
> +                                        VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE |
> +                                        (STRNEQ(status, "stopped") ?
> +                                         VIR_DOMAIN_OBJ_LIST_ADD_LIVE : 0),

It might be easier to read to compute the flags separately and just use
the result here.

> +                                        NULL)))
>              goto cleanup;
>  
>          if (STREQ(status, "stopped")) {
...
> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> index a02e989..d6c6af5 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c
...
> @@ -5615,26 +5608,14 @@ static virDomainPtr qemuDomainDefine(virConnectPtr conn, const char *xml) {
>      if (qemuDomainAssignAddresses(def, caps, NULL) < 0)
>          goto cleanup;
>  
> -    /* We need to differentiate two cases:
> -     * a) updating an existing domain - must preserve previous definition
> -     *                                  so we can roll back if something fails
> -     * b) defining a brand new domain - virDomainObjListAdd is just sufficient
> -     */
> -    if ((vm = virDomainObjListFindByUUID(driver->domains, def->uuid))) {
> -        if (virDomainObjIsActive(vm)) {
> -            def_backup = vm->newDef;
> -            vm->newDef = def;
> -        } else {
> -            def_backup = vm->def;
> -            vm->def = def;
> -        }
> -    } else {
> -        if (!(vm = virDomainObjListAdd(driver->domains,
> -                                       driver->caps,
> -                                       def, false))) {
> -            goto cleanup;
> -        }
> -    }
> +    if (!(vm = virDomainObjListAdd(driver->domains,
> +                                   driver->caps,
> +                                   def,
> +                                   VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
> +                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,

I believe the flags should be 0 here. By using
VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE you would effectively forbid calling
virDomainDefine for running transient domains. And
VIR_DOMAIN_OBJ_LIST_ADD_LIVE should not be set either since def is
domain's persistent (rather than active) definition.

> +                                   &oldDef)))
> +        goto cleanup;
> +
>      def = NULL;
>      if (virDomainHasDiskMirror(vm)) {
>          virReportError(VIR_ERR_BLOCK_COPY_ACTIVE, "%s",
...
> @@ -12612,9 +12593,6 @@ static virDomainPtr qemuDomainAttach(virConnectPtr conn,
>      if (!(caps = qemuCapsCacheLookup(driver->capsCache, def->emulator)))
>          goto cleanup;
>  
> -    if (virDomainObjListIsDuplicate(driver->domains, def, 1) < 0)
> -        goto cleanup;
> -
>      if (qemuCanonicalizeMachine(def, caps) < 0)
>          goto cleanup;
>  
> @@ -12623,7 +12601,10 @@ static virDomainPtr qemuDomainAttach(virConnectPtr conn,
>  
>      if (!(vm = virDomainObjListAdd(driver->domains,
>                                     driver->caps,
> -                                   def, false)))
> +                                   def,
> +                                   VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
> +                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
> +                                   NULL)))

Although this could be correct, it doesn't match current code. To match
it, you'd need to use just VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE flag.

>          goto cleanup;
>  
>      def = NULL;
...
> diff --git a/src/vmware/vmware_driver.c b/src/vmware/vmware_driver.c
> index b99fca3..8684f56 100644
> --- a/src/vmware/vmware_driver.c
> +++ b/src/vmware/vmware_driver.c
> @@ -320,9 +320,6 @@ vmwareDomainDefineXML(virConnectPtr conn, const char *xml)
>                                           VIR_DOMAIN_XML_INACTIVE)) == NULL)
>          goto cleanup;
>  
> -    if (virDomainObjListIsDuplicate(driver->domains, vmdef, 1) < 0)
> -        goto cleanup;
> -
>      /* generate vmx file */
>      vmx = virVMXFormatConfig(&ctx, driver->caps, vmdef, 7);
>      if (vmx == NULL)
> @@ -341,7 +338,7 @@ vmwareDomainDefineXML(virConnectPtr conn, const char *xml)
>      /* assign def */
>      if (!(vm = virDomainObjListAdd(driver->domains,
>                                     driver->caps,
> -                                   vmdef, false)))
> +                                   vmdef, 0, NULL)))

virDomainObjListIsDuplicate was called with 1 as the third argument,
thus you need to use VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE flag here.

>          goto cleanup;
>  
>      pDomain = vm->privateData;
...

Looking forward to v2 :-)

Jirka




More information about the libvir-list mailing list