On Wed, Dec 03, 2008 at 06:52:32PM +0000, Daniel P. Berrange wrote:
On Wed, Dec 03, 2008 at 04:18:21PM +0100, Daniel Veillard wrote:
> On Mon, Dec 01, 2008 at 12:26:48AM +0000, Daniel P. Berrange wrote:
> > This is a diffstat summary for the combined series of 28 patches
>
> Okay, my take at this point is that those should be commited with
> the few fix found my manual examination, maybe extend the documentation
> a bit, and start testing it as much as prossible.
> Some locking debug facility might be a good addition,
I wrote some an OCaml program using CIL to check driver method exit paths
and validate that all objects were left in an unlocked state. This found
some real bugs !
So here's the incremental fixes for those
I was having so much fun I wrote more checks for incorrect locking order
and data access while unlocked, and improved existing detection. A bunch
more bugs found and fixed !
lxc_driver.c | 23 +++++++++++++++++++----
network_driver.c | 3 ---
qemu_driver.c | 28 +++++++++++++++++-----------
storage_driver.c | 10 ++++++++--
test.c | 3 +--
uml_driver.c | 18 ++++++++++++++----
6 files changed, 59 insertions(+), 26 deletions(-)
Daniel
diff --git a/src/lxc_driver.c b/src/lxc_driver.c
--- a/src/lxc_driver.c
+++ b/src/lxc_driver.c
@@ -682,24 +682,32 @@ static void lxcMonitorEvent(int watch,
virDomainObjPtr vm = NULL;
unsigned int i;
+ lxcDriverLock(driver);
for (i = 0 ; i < driver->domains.count ; i++) {
+ virDomainObjLock(driver->domains.objs[i]);
if (driver->domains.objs[i]->monitorWatch == watch) {
vm = driver->domains.objs[i];
break;
}
+ virDomainObjUnlock(driver->domains.objs[i]);
}
if (!vm) {
virEventRemoveHandle(watch);
- return;
+ goto cleanup;
}
if (vm->monitor != fd) {
virEventRemoveHandle(watch);
- return;
+ goto cleanup;
}
if (lxcVmTerminate(NULL, driver, vm, SIGINT) < 0)
virEventRemoveHandle(watch);
+
+cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ lxcDriverUnlock(driver);
}
@@ -1153,20 +1161,26 @@ static int lxcStartup(void)
char *config = NULL;
virDomainDefPtr tmp;
int rc;
- if ((vm->monitor = lxcMonitorClient(NULL, lxc_driver, vm)) < 0)
+ virDomainObjLock(vm);
+ if ((vm->monitor = lxcMonitorClient(NULL, lxc_driver, vm)) < 0) {
+ virDomainObjUnlock(vm);
continue;
+ }
/* Read pid from controller */
if ((rc = virFileReadPid(lxc_driver->stateDir, vm->def->name,
&vm->pid)) != 0) {
close(vm->monitor);
vm->monitor = -1;
+ virDomainObjUnlock(vm);
continue;
}
if ((config = virDomainConfigFile(NULL,
lxc_driver->stateDir,
- vm->def->name)) == NULL)
+ vm->def->name)) == NULL) {
+ virDomainObjUnlock(vm);
continue;
+ }
/* Try and load the live config */
tmp = virDomainDefParseFile(NULL, lxc_driver->caps, config);
@@ -1184,6 +1198,7 @@ static int lxcStartup(void)
close(vm->monitor);
vm->monitor = -1;
}
+ virDomainObjUnlock(vm);
}
lxcDriverUnlock(lxc_driver);
diff --git a/src/network_driver.c b/src/network_driver.c
--- a/src/network_driver.c
+++ b/src/network_driver.c
@@ -1005,7 +1005,6 @@ static virNetworkPtr networkCreate(virCo
def = NULL;
if (networkStartNetworkDaemon(conn, driver, network) < 0) {
- virNetworkObjUnlock(network);
virNetworkRemoveInactive(&driver->networks,
network);
network = NULL;
@@ -1043,7 +1042,6 @@ static virNetworkPtr networkDefine(virCo
driver->networkConfigDir,
driver->networkAutostartDir,
network) < 0) {
- virNetworkObjUnlock(network);
virNetworkRemoveInactive(&driver->networks,
network);
network = NULL;
@@ -1083,7 +1081,6 @@ static int networkUndefine(virNetworkPtr
if (virNetworkDeleteConfig(net->conn, network) < 0)
goto cleanup;
- virNetworkObjUnlock(network);
virNetworkRemoveInactive(&driver->networks,
network);
network = NULL;
diff --git a/src/qemu_driver.c b/src/qemu_driver.c
--- a/src/qemu_driver.c
+++ b/src/qemu_driver.c
@@ -243,8 +243,7 @@ qemudStartup(void) {
goto out_of_memory;
if (qemudLoadDriverConfig(qemu_driver, driverConf) < 0) {
- qemudShutdown();
- return -1;
+ goto error;
}
if (virDomainLoadAllConfigs(NULL,
@@ -327,9 +326,13 @@ qemudActive(void) {
return 0;
qemuDriverLock(qemu_driver);
- for (i = 0 ; i < qemu_driver->domains.count ; i++)
- if (virDomainIsActive(qemu_driver->domains.objs[i]))
+ for (i = 0 ; i < qemu_driver->domains.count ; i++) {
+ virDomainObjPtr vm = qemu_driver->domains.objs[i];
+ virDomainObjLock(vm);
+ if (virDomainIsActive(vm))
active = 1;
+ virDomainObjUnlock(vm);
+ }
qemuDriverUnlock(qemu_driver);
return active;
@@ -1088,12 +1091,15 @@ qemudDispatchVMEvent(int watch, int fd,
qemuDriverLock(driver);
for (i = 0 ; i < driver->domains.count ; i++) {
- if (virDomainIsActive(driver->domains.objs[i]) &&
- (driver->domains.objs[i]->stdout_watch == watch ||
- driver->domains.objs[i]->stderr_watch == watch)) {
- vm = driver->domains.objs[i];
- break;
- }
+ virDomainObjPtr tmpvm = driver->domains.objs[i];
+ virDomainObjLock(vm);
+ if (virDomainIsActive(tmpvm) &&
+ (tmpvm->stdout_watch == watch ||
+ tmpvm->stderr_watch == watch)) {
+ vm = tmpvm;
+ break;
+ }
+ virDomainObjUnlock(vm);
}
if (!vm)
@@ -2128,7 +2134,7 @@ static int qemudDomainSave(virDomainPtr
if (safewrite(fd, &header, sizeof(header)) != sizeof(header)) {
qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
"%s", _("failed to write save header"));
- return -1;
+ goto cleanup;
}
if (safewrite(fd, xml, header.xml_len) != header.xml_len) {
diff --git a/src/storage_driver.c b/src/storage_driver.c
--- a/src/storage_driver.c
+++ b/src/storage_driver.c
@@ -62,13 +62,14 @@ storageDriverAutostart(virStorageDriverS
for (i = 0 ; i < driver->pools.count ; i++) {
virStoragePoolObjPtr pool = driver->pools.objs[i];
-
+ virStoragePoolObjLock(pool);
if (pool->autostart &&
!virStoragePoolObjIsActive(pool)) {
virStorageBackendPtr backend;
if ((backend = virStorageBackendForType(pool->def->type)) == NULL) {
storageLog("Missing backend %d",
pool->def->type);
+ virStoragePoolObjUnlock(pool);
continue;
}
@@ -77,6 +78,7 @@ storageDriverAutostart(virStorageDriverS
virErrorPtr err = virGetLastError();
storageLog("Failed to autostart storage pool '%s':
%s",
pool->def->name, err ? err->message : NULL);
+ virStoragePoolObjUnlock(pool);
continue;
}
@@ -86,10 +88,12 @@ storageDriverAutostart(virStorageDriverS
backend->stopPool(NULL, pool);
storageLog("Failed to autostart storage pool '%s':
%s",
pool->def->name, err ? err->message : NULL);
+ virStoragePoolObjUnlock(pool);
continue;
}
pool->active = 1;
}
+ virStoragePoolObjUnlock(pool);
}
}
@@ -237,11 +241,12 @@ storageDriverShutdown(void) {
/* shutdown active pools */
for (i = 0 ; i < driverState->pools.count ; i++) {
virStoragePoolObjPtr pool = driverState->pools.objs[i];
-
+ virStoragePoolObjLock(pool);
if (virStoragePoolObjIsActive(pool)) {
virStorageBackendPtr backend;
if ((backend = virStorageBackendForType(pool->def->type)) == NULL) {
storageLog("Missing backend");
+ virStoragePoolObjUnlock(pool);
continue;
}
@@ -253,6 +258,7 @@ storageDriverShutdown(void) {
}
virStoragePoolObjClearVols(pool);
}
+ virStoragePoolObjUnlock(pool);
}
/* free inactive pools */
diff --git a/src/test.c b/src/test.c
--- a/src/test.c
+++ b/src/test.c
@@ -1592,7 +1592,6 @@ static int testDomainUndefine(virDomainP
}
privdom->state = VIR_DOMAIN_SHUTOFF;
- virDomainObjUnlock(privdom);
virDomainRemoveInactive(&privconn->domains,
privdom);
privdom = NULL;
@@ -2393,7 +2392,7 @@ testStoragePoolCreate(virConnectPtr conn
}
if (!(pool = virStoragePoolObjAssignDef(conn, &privconn->pools, def))) {
- return NULL;
+ goto cleanup;
}
def = NULL;
diff --git a/src/uml_driver.c b/src/uml_driver.c
--- a/src/uml_driver.c
+++ b/src/uml_driver.c
@@ -215,28 +215,29 @@ umlInotifyEvent(int watch,
struct uml_driver *driver = data;
virDomainObjPtr dom;
+ umlDriverLock(driver);
if (watch != driver->inotifyWatch)
- return;
+ goto cleanup;
reread:
got = read(fd, buf, sizeof(buf));
if (got == -1) {
if (errno == EINTR)
goto reread;
- return;
+ goto cleanup;
}
tmp = buf;
while (got) {
if (got < sizeof(struct inotify_event))
- return; /* bad */
+ goto cleanup; /* bad */
e = (struct inotify_event *)tmp;
tmp += sizeof(struct inotify_event);
got -= sizeof(struct inotify_event);
if (got < e->len)
- return;
+ goto cleanup;
tmp += e->len;
got -= e->len;
@@ -251,6 +252,7 @@ reread:
if (e->mask & IN_DELETE) {
if (!virDomainIsActive(dom)) {
+ virDomainObjUnlock(dom);
continue;
}
@@ -263,10 +265,12 @@ reread:
dom->state = VIR_DOMAIN_SHUTOFF;
} else if (e->mask & (IN_CREATE | IN_MODIFY)) {
if (virDomainIsActive(dom)) {
+ virDomainObjUnlock(dom);
continue;
}
if (umlReadPidFile(NULL, driver, dom) < 0) {
+ virDomainObjUnlock(dom);
continue;
}
@@ -279,7 +283,11 @@ reread:
if (umlIdentifyChrPTY(NULL, driver, dom) < 0)
umlShutdownVMDaemon(NULL, driver, dom);
}
+ virDomainObjUnlock(dom);
}
+
+cleanup:
+ umlDriverUnlock(driver);
}
/**
@@ -465,8 +473,10 @@ umlShutdown(void) {
/* shutdown active VMs */
for (i = 0 ; i < uml_driver->domains.count ; i++) {
virDomainObjPtr dom = uml_driver->domains.objs[i];
+ virDomainObjLock(dom);
if (virDomainIsActive(dom))
umlShutdownVMDaemon(NULL, uml_driver, dom);
+ virDomainObjUnlock(dom);
}
virDomainObjListFree(¨_driver->domains);
--
|: 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 :|