On Fri, Feb 01, 2013 at 11:18:26 +0000, Daniel P. Berrange wrote: > From: "Daniel P. Berrange" <berrange@xxxxxxxxxx> > > 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list