This implements the same logic as described for the QEMU driver, in the LXC driver & its API calls. The concurrency on this is already very good, since the LXC driver has no long running code by virtue of not having a 'monitor' console to interact with. Daniel diff --git a/src/lxc_conf.h b/src/lxc_conf.h --- a/src/lxc_conf.h +++ b/src/lxc_conf.h @@ -36,6 +36,8 @@ typedef struct __lxc_driver lxc_driver_t; struct __lxc_driver { + pthread_mutex_t lock; + virCapsPtr caps; virDomainObjList domains; diff --git a/src/lxc_driver.c b/src/lxc_driver.c --- a/src/lxc_driver.c +++ b/src/lxc_driver.c @@ -52,6 +52,19 @@ static lxc_driver_t *lxc_driver = NULL; static lxc_driver_t *lxc_driver = NULL; /* Functions */ + +static int +lxcDriverLock(lxc_driver_t *driver) +{ + return pthread_mutex_lock(&driver->lock); +} + +static int +lxcDriverUnlock(lxc_driver_t *driver) +{ + return pthread_mutex_unlock(&driver->lock); +} + static const char *lxcProbe(void) { @@ -104,8 +117,12 @@ static virDomainPtr lxcDomainLookupByID( int id) { lxc_driver_t *driver = (lxc_driver_t *)conn->privateData; - virDomainObjPtr vm = virDomainFindByID(&driver->domains, id); + virDomainObjPtr vm; virDomainPtr dom; + + lxcDriverLock(driver); + vm = virDomainFindByID(&driver->domains, id); + lxcDriverUnlock(driver); if (!vm) { lxcError(conn, NULL, VIR_ERR_NO_DOMAIN, NULL); @@ -117,6 +134,7 @@ static virDomainPtr lxcDomainLookupByID( dom->id = vm->def->id; } + virDomainUnlock(vm); return dom; } @@ -124,8 +142,12 @@ static virDomainPtr lxcDomainLookupByUUI const unsigned char *uuid) { lxc_driver_t *driver = (lxc_driver_t *)conn->privateData; - virDomainObjPtr vm = virDomainFindByUUID(&driver->domains, uuid); + virDomainObjPtr vm; virDomainPtr dom; + + lxcDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, uuid); + lxcDriverUnlock(driver); if (!vm) { lxcError(conn, NULL, VIR_ERR_NO_DOMAIN, NULL); @@ -137,6 +159,7 @@ static virDomainPtr lxcDomainLookupByUUI dom->id = vm->def->id; } + virDomainUnlock(vm); return dom; } @@ -144,8 +167,12 @@ static virDomainPtr lxcDomainLookupByNam const char *name) { lxc_driver_t *driver = (lxc_driver_t *)conn->privateData; - virDomainObjPtr vm = virDomainFindByName(&driver->domains, name); + virDomainObjPtr vm; virDomainPtr dom; + + lxcDriverLock(driver); + vm = virDomainFindByName(&driver->domains, name); + lxcDriverUnlock(driver); if (!vm) { lxcError(conn, NULL, VIR_ERR_NO_DOMAIN, NULL); @@ -157,6 +184,7 @@ static virDomainPtr lxcDomainLookupByNam dom->id = vm->def->id; } + virDomainUnlock(vm); return dom; } @@ -164,9 +192,16 @@ static int lxcListDomains(virConnectPtr lxc_driver_t *driver = (lxc_driver_t *)conn->privateData; int got = 0, i; - for (i = 0 ; i < driver->domains.count && got < nids ; i++) + lxcDriverLock(driver); + + for (i = 0 ; i < driver->domains.count && got < nids ; i++) { + virDomainLock(driver->domains.objs[i]); if (virDomainIsActive(driver->domains.objs[i])) ids[got++] = driver->domains.objs[i]->def->id; + virDomainUnlock(driver->domains.objs[i]); + } + + lxcDriverUnlock(driver); return got; } @@ -174,9 +209,16 @@ static int lxcNumDomains(virConnectPtr c lxc_driver_t *driver = (lxc_driver_t *)conn->privateData; int n = 0, i; - for (i = 0 ; i < driver->domains.count ; i++) + lxcDriverLock(driver); + + for (i = 0 ; i < driver->domains.count ; i++) { + virDomainLock(driver->domains.objs[i]); if (virDomainIsActive(driver->domains.objs[i])) n++; + virDomainUnlock(driver->domains.objs[i]); + } + + lxcDriverUnlock(driver); return n; } @@ -186,21 +228,28 @@ static int lxcListDefinedDomains(virConn lxc_driver_t *driver = (lxc_driver_t *)conn->privateData; int got = 0, i; + lxcDriverLock(driver); + for (i = 0 ; i < driver->domains.count && got < nnames ; i++) { + virDomainLock(driver->domains.objs[i]); if (!virDomainIsActive(driver->domains.objs[i])) { if (!(names[got++] = strdup(driver->domains.objs[i]->def->name))) { lxcError(conn, NULL, VIR_ERR_NO_MEMORY, "%s", _("failed to allocate space for VM name string")); + virDomainUnlock(driver->domains.objs[i]); goto cleanup; } } + virDomainUnlock(driver->domains.objs[i]); } + lxcDriverUnlock(driver); return got; cleanup: for (i = 0 ; i < got ; i++) VIR_FREE(names[i]); + lxcDriverUnlock(driver); return -1; } @@ -209,9 +258,14 @@ static int lxcNumDefinedDomains(virConne lxc_driver_t *driver = (lxc_driver_t *)conn->privateData; int n = 0, i; - for (i = 0 ; i < driver->domains.count ; i++) + lxcDriverLock(driver); + for (i = 0 ; i < driver->domains.count ; i++) { + virDomainLock(driver->domains.objs[i]); if (!virDomainIsActive(driver->domains.objs[i])) n++; + virDomainUnlock(driver->domains.objs[i]); + } + lxcDriverUnlock(driver); return n; } @@ -225,27 +279,28 @@ static virDomainPtr lxcDomainDefine(virC virDomainObjPtr vm; virDomainPtr dom; + lxcDriverLock(driver); + if (!(def = virDomainDefParseString(conn, driver->caps, xml))) - return NULL; + goto error; if ((def->nets != NULL) && !(driver->have_netns)) { lxcError(conn, NULL, VIR_ERR_NO_SUPPORT, "%s", _("System lacks NETNS support")); - virDomainDefFree(def); - return NULL; + goto error; } - if (!(vm = virDomainAssignDef(conn, &driver->domains, def))) { - virDomainDefFree(def); - return NULL; - } + if (!(vm = virDomainAssignDef(conn, &driver->domains, def))) + goto error; + vm->persistent = 1; + def = NULL; if (virDomainSaveConfig(conn, driver->configDir, vm->newDef ? vm->newDef : vm->def) < 0) { virDomainRemoveInactive(&driver->domains, vm); - return NULL; + goto error; } dom = virGetDomain(conn, vm->def->name, vm->def->uuid); @@ -253,48 +308,73 @@ static virDomainPtr lxcDomainDefine(virC dom->id = vm->def->id; } + virDomainUnlock(vm); + lxcDriverUnlock(driver); + return dom; + +error: + if (def) + virDomainDefFree(def); + + lxcDriverUnlock(driver); + return NULL; } static int lxcDomainUndefine(virDomainPtr dom) { lxc_driver_t *driver = (lxc_driver_t *)dom->conn->privateData; - virDomainObjPtr vm = virDomainFindByUUID(&driver->domains, dom->uuid); + virDomainObjPtr vm; + + lxcDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); if (!vm) { lxcError(dom->conn, dom, VIR_ERR_INVALID_DOMAIN, "%s", _("no domain with matching uuid")); - return -1; + goto error; } if (virDomainIsActive(vm)) { lxcError(dom->conn, dom, VIR_ERR_INTERNAL_ERROR, "%s", _("cannot delete active domain")); - return -1; + goto error; } if (!vm->persistent) { lxcError(dom->conn, dom, VIR_ERR_INTERNAL_ERROR, "%s", _("cannot undefine transient domain")); - return -1; + goto error; } if (virDomainDeleteConfig(dom->conn, driver->configDir, driver->autostartDir, vm) <0) - return -1; + goto error; + virDomainUnlock(vm); virDomainRemoveInactive(&driver->domains, vm); + lxcDriverUnlock(driver); return 0; + +error: + if (vm) + virDomainUnlock(vm); + lxcDriverUnlock(driver); + return -1; } static int lxcDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info) { lxc_driver_t *driver = (lxc_driver_t *)dom->conn->privateData; - virDomainObjPtr vm = virDomainFindByUUID(&driver->domains, dom->uuid); + virDomainObjPtr vm; + + lxcDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + lxcDriverUnlock(driver); if (!vm) { lxcError(dom->conn, dom, VIR_ERR_INVALID_DOMAIN, @@ -314,13 +394,19 @@ static int lxcDomainGetInfo(virDomainPtr info->memory = vm->def->memory; info->nrVirtCpu = 1; + virDomainUnlock(vm); return 0; } static char *lxcGetOSType(virDomainPtr dom) { lxc_driver_t *driver = (lxc_driver_t *)dom->conn->privateData; - virDomainObjPtr vm = virDomainFindByUUID(&driver->domains, dom->uuid); + virDomainObjPtr vm; + char *ret; + + lxcDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + lxcDriverUnlock(driver); if (!vm) { lxcError(dom->conn, dom, VIR_ERR_INVALID_DOMAIN, @@ -328,14 +414,21 @@ static char *lxcGetOSType(virDomainPtr d return NULL; } - return strdup(vm->def->os.type); + ret = strdup(vm->def->os.type); + virDomainUnlock(vm); + return ret; } static char *lxcDomainDumpXML(virDomainPtr dom, int flags) { lxc_driver_t *driver = (lxc_driver_t *)dom->conn->privateData; - virDomainObjPtr vm = virDomainFindByUUID(&driver->domains, dom->uuid); + virDomainObjPtr vm; + char *ret; + + lxcDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + lxcDriverUnlock(driver); if (!vm) { lxcError(dom->conn, dom, VIR_ERR_INVALID_DOMAIN, @@ -343,10 +436,12 @@ static char *lxcDomainDumpXML(virDomainP return NULL; } - return virDomainDefFormat(dom->conn, - (flags & VIR_DOMAIN_XML_INACTIVE) && - vm->newDef ? vm->newDef : vm->def, + ret = virDomainDefFormat(dom->conn, + (flags & VIR_DOMAIN_XML_INACTIVE) && + vm->newDef ? vm->newDef : vm->def, flags); + virDomainUnlock(vm); + return ret; } @@ -590,19 +685,29 @@ static void lxcMonitorEvent(int fd, virDomainObjPtr vm = NULL; unsigned int i; + lxcDriverLock(driver); + for (i = 0 ; i < driver->domains.count ; i++) { + virDomainLock(driver->domains.objs[i]); if (driver->domains.objs[i]->monitor == fd) { vm = driver->domains.objs[i]; break; } + virDomainUnlock(driver->domains.objs[i]); } + if (!vm) { virEventRemoveHandle(fd); - return; + goto cleanup; } if (lxcVmTerminate(NULL, driver, vm, SIGINT) < 0) virEventRemoveHandle(fd); + +cleanup: + if (vm) + virDomainUnlock(vm); + lxcDriverUnlock(driver); } @@ -851,7 +956,10 @@ static int lxcDomainStart(virDomainPtr d int rc = -1; virConnectPtr conn = dom->conn; lxc_driver_t *driver = (lxc_driver_t *)(conn->privateData); - virDomainObjPtr vm = virDomainFindByName(&driver->domains, dom->name); + virDomainObjPtr vm; + + lxcDriverLock(driver); + vm = virDomainFindByName(&driver->domains, dom->name); if (!vm) { lxcError(conn, dom, VIR_ERR_INVALID_DOMAIN, @@ -868,6 +976,9 @@ static int lxcDomainStart(virDomainPtr d rc = lxcVmStart(conn, driver, vm); cleanup: + if (vm) + virDomainUnlock(vm); + lxcDriverUnlock(driver); return rc; } @@ -890,6 +1001,8 @@ lxcDomainCreateAndStart(virConnectPtr co virDomainDefPtr def; virDomainPtr dom = NULL; + lxcDriverLock(driver); + if (!(def = virDomainDefParseString(conn, driver->caps, xml))) goto return_point; @@ -917,6 +1030,9 @@ lxcDomainCreateAndStart(virConnectPtr co } return_point: + if (vm) + virDomainUnlock(vm); + lxcDriverUnlock(driver); return dom; } @@ -931,15 +1047,25 @@ static int lxcDomainShutdown(virDomainPt static int lxcDomainShutdown(virDomainPtr dom) { lxc_driver_t *driver = (lxc_driver_t*)dom->conn->privateData; - virDomainObjPtr vm = virDomainFindByID(&driver->domains, dom->id); + virDomainObjPtr vm; + int ret = -1; + + lxcDriverLock(driver); + vm = virDomainFindByID(&driver->domains, dom->id); if (!vm) { lxcError(dom->conn, dom, VIR_ERR_INVALID_DOMAIN, _("no domain with id %d"), dom->id); - return -1; + goto cleanup; } - return lxcVmTerminate(dom->conn, driver, vm, 0); + ret = lxcVmTerminate(dom->conn, driver, vm, 0); + +cleanup: + if (vm) + virDomainUnlock(vm); + lxcDriverUnlock(driver); + return ret; } @@ -954,15 +1080,24 @@ static int lxcDomainDestroy(virDomainPtr static int lxcDomainDestroy(virDomainPtr dom) { lxc_driver_t *driver = (lxc_driver_t*)dom->conn->privateData; - virDomainObjPtr vm = virDomainFindByID(&driver->domains, dom->id); + virDomainObjPtr vm; + int ret = -1; + + lxcDriverLock(driver); + vm = virDomainFindByID(&driver->domains, dom->id); if (!vm) { lxcError(dom->conn, dom, VIR_ERR_INVALID_DOMAIN, _("no domain with id %d"), dom->id); - return -1; + goto cleanup; } - return lxcVmTerminate(dom->conn, driver, vm, SIGKILL); + ret = lxcVmTerminate(dom->conn, driver, vm, SIGKILL); +cleanup: + if (vm) + virDomainUnlock(vm); + lxcDriverUnlock(driver); + return ret; } static int lxcCheckNetNsSupport(void) @@ -990,35 +1125,31 @@ static int lxcStartup(void) return -1; } - if (VIR_ALLOC(lxc_driver) < 0) { - return -1; - } - /* Check that this is a container enabled kernel */ if(lxcContainerAvailable(0) < 0) return -1; + if (VIR_ALLOC(lxc_driver) < 0) + return -1; + + pthread_mutex_init(&lxc_driver->lock, NULL); + lxcDriverLock(lxc_driver); + lxc_driver->have_netns = lxcCheckNetNsSupport(); /* Call function to load lxc driver configuration information */ - if (lxcLoadDriverConfig(lxc_driver) < 0) { - lxcShutdown(); - return -1; - } + if (lxcLoadDriverConfig(lxc_driver) < 0) + goto error; - if ((lxc_driver->caps = lxcCapsInit()) == NULL) { - lxcShutdown(); - return -1; - } + if ((lxc_driver->caps = lxcCapsInit()) == NULL) + goto error; if (virDomainLoadAllConfigs(NULL, lxc_driver->caps, &lxc_driver->domains, lxc_driver->configDir, - lxc_driver->autostartDir) < 0) { - lxcShutdown(); - return -1; - } + lxc_driver->autostartDir) < 0) + goto error; for (i = 0 ; i < lxc_driver->domains.count ; i++) { virDomainObjPtr vm = lxc_driver->domains.objs[i]; @@ -1058,7 +1189,13 @@ static int lxcStartup(void) } } + lxcDriverUnlock(lxc_driver); return 0; + +error: + lxcDriverUnlock(lxc_driver); + lxcShutdown(); + return -1; } static void lxcFreeDriver(lxc_driver_t *driver) @@ -1075,7 +1212,9 @@ static int lxcShutdown(void) if (lxc_driver == NULL) return(-1); + lxcDriverLock(lxc_driver); virDomainObjListFree(&lxc_driver->domains); + lxcDriverUnlock(lxc_driver); lxcFreeDriver(lxc_driver); lxc_driver = NULL; @@ -1091,17 +1230,20 @@ static int lxcShutdown(void) */ static int lxcActive(void) { - unsigned int i; + unsigned int i, active = 0; if (lxc_driver == NULL) return(0); - for (i = 0 ; i < lxc_driver->domains.count ; i++) + lxcDriverLock(lxc_driver); + for (i = 0 ; i < lxc_driver->domains.count ; i++) { + virDomainLock(lxc_driver->domains.objs[i]); if (virDomainIsActive(lxc_driver->domains.objs[i])) - return 1; + active = 1; + virDomainUnlock(lxc_driver->domains.objs[i]); + } - /* Otherwise we're happy to deal with a shutdown */ - return 0; + return active; } static int lxcVersion(virConnectPtr conn, unsigned long *version) @@ -1137,84 +1279,99 @@ static char *lxcGetSchedulerType(virDoma return strdup("posix"); } -static int lxcSetSchedulerParameters(virDomainPtr _domain, +static int lxcSetSchedulerParameters(virDomainPtr domain, virSchedParameterPtr params, int nparams) { + lxc_driver_t *driver = domain->conn->privateData; int i; - int rc; virCgroupPtr group; - virDomainObjPtr domain; + virDomainObjPtr vm; if (virCgroupHaveSupport() != 0) return 0; - domain = virDomainFindByUUID(&lxc_driver->domains, _domain->uuid); - if (domain == NULL) { + lxcDriverLock(driver); + vm = virDomainFindByUUID(&lxc_driver->domains, domain->uuid); + lxcDriverUnlock(driver); + + if (vm == NULL) { lxcError(NULL, _domain, VIR_ERR_INTERNAL_ERROR, - _("No such domain %s"), _domain->uuid); - return -EINVAL; + _("No such domain %s"), domain->uuid); + goto error; } - rc = virCgroupForDomain(domain->def, "lxc", &group); - if (rc != 0) - return rc; + if (virCgroupForDomain(vm->def, "lxc", &group) != 0) + goto error; for (i = 0; i < nparams; i++) { virSchedParameterPtr param = ¶ms[i]; if (STREQ(param->field, "cpu_shares")) { - rc = virCgroupSetCpuShares(group, params[i].value.ui); + if (virCgroupSetCpuShares(group, params[i].value.ui) != 0) + goto error; } else { - lxcError(NULL, _domain, VIR_ERR_INVALID_ARG, + lxcError(NULL, domain, VIR_ERR_INVALID_ARG, _("Invalid parameter `%s'"), param->field); - rc = -ENOENT; - goto out; + goto error; } } - rc = 0; -out: virCgroupFree(&group); + return 0; - return rc; +error: + if (group) + virCgroupFree(&group); + if (vm) + virDomainUnlock(vm); + lxcDriverUnlock(driver); + return -1; } -static int lxcGetSchedulerParameters(virDomainPtr _domain, +static int lxcGetSchedulerParameters(virDomainPtr domain, virSchedParameterPtr params, int *nparams) { - int rc = 0; + lxc_driver_t *driver = domain->conn->privateData; virCgroupPtr group; - virDomainObjPtr domain; + virDomainObjPtr vm; if (virCgroupHaveSupport() != 0) return 0; if ((*nparams) != 1) { - lxcError(NULL, _domain, VIR_ERR_INVALID_ARG, + lxcError(NULL, domain, VIR_ERR_INVALID_ARG, "%s", _("Invalid parameter count")); - return -1; + goto error; } - domain = virDomainFindByUUID(&lxc_driver->domains, _domain->uuid); - if (domain == NULL) { - lxcError(NULL, _domain, VIR_ERR_INTERNAL_ERROR, - _("No such domain %s"), _domain->uuid); - return -ENOENT; + lxcDriverLock(driver); + vm = virDomainFindByUUID(&lxc_driver->domains, domain->uuid); + lxcDriverUnlock(driver); + if (vm == NULL) { + lxcError(NULL, domain, VIR_ERR_INTERNAL_ERROR, + _("No such domain %s"), domain->uuid); + goto error; } - rc = virCgroupForDomain(domain->def, "lxc", &group); - if (rc != 0) - return rc; + if (virCgroupForDomain(vm->def, "lxc", &group) != 0) + goto error; - rc = virCgroupGetCpuShares(group, (unsigned long *)¶ms[0].value.ul); + if (virCgroupGetCpuShares(group, (unsigned long *)¶ms[0].value.ul) != 0) + goto error; + strncpy(params[0].field, "cpu_shares", sizeof(params[0].field)); params[0].type = VIR_DOMAIN_SCHED_FIELD_ULLONG; virCgroupFree(&group); - return rc; + return 0; + +error: + if (vm) + virDomainUnlock(vm); + return -1; } /* Function Tables */ -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :| -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list