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 :|