https://bugzilla.redhat.com/show_bug.cgi?id=1192399
It's known fact for a while now that we should not only lock the
top level layers of backing chain but the rest of it too. And
well known too that we are not doing that. Well, up until this
commit. The reason is that while one guest can have for instance
the following backing chain: A (top) -> B -> C (bottom), the
other can be started just over B or C. But libvirt should prevent
that as it will almost certainly mangle the backing chain for the
former guest. On the other hand, we want to allow guest with the
following backing chain: D (top) -> B -> C (bottom), because in
both cases B and C are there just for reading. In order to
achieve that we must lock the rest of backing chain with
VIR_LOCK_MANAGER_RESOURCE_SHARED flag.
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
src/locking/domain_lock.c | 53 +++++++++++++++++++++++++++++------------------
1 file changed, 33 insertions(+), 20 deletions(-)
diff --git a/src/locking/domain_lock.c b/src/locking/domain_lock.c
index 705b132..faf73f2 100644
--- a/src/locking/domain_lock.c
+++ b/src/locking/domain_lock.c
@@ -69,35 +69,48 @@ static int virDomainLockManagerAddLease(virLockManagerPtr lock,
static int virDomainLockManagerAddImage(virLockManagerPtr lock,
- virStorageSourcePtr src)
+ virStorageSourcePtr disk)
{
unsigned int diskFlags = 0;
- int type = virStorageSourceGetActualType(src);
-
- if (!src->path)
- return 0;
-
- if (!(type == VIR_STORAGE_TYPE_BLOCK ||
- type == VIR_STORAGE_TYPE_FILE ||
- type == VIR_STORAGE_TYPE_DIR))
- return 0;
+ virStorageSourcePtr src = disk;
+ int ret = -1;
+ /* The top layer of backing chain should have the correct flags set.
+ * The rest should be locked with VIR_LOCK_MANAGER_RESOURCE_SHARED
+ * for it can be shared among other domains. */
if (src->readonly)
diskFlags |= VIR_LOCK_MANAGER_RESOURCE_READONLY;
if (src->shared)
diskFlags |= VIR_LOCK_MANAGER_RESOURCE_SHARED;
- VIR_DEBUG("Add disk %s", src->path);
- if (virLockManagerAddResource(lock,
- VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK,
- src->path,
- 0,
- NULL,
- diskFlags) < 0) {
- VIR_DEBUG("Failed add disk %s", src->path);
- return -1;
+ while (src) {
+ if (!virStorageSourceIsLocalStorage(src))
+ break;
+
+ if (!src->path)
+ break;
+
+ VIR_DEBUG("Add disk %s", src->path);
+ if (virLockManagerAddResource(lock,
+ VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK,
+ src->path,
+ 0,
+ NULL,
+ diskFlags) < 0) {
+ VIR_DEBUG("Failed add disk %s", src->path);
+ goto cleanup;
+ }
+
+ /* Now that we've added the first disk (top layer of backing chain)
+ * into the lock manager, let's traverse the rest of the backing chain
+ * and lock each layer for RO. This should prevent accidentally
+ * starting a domain with RW disk from the middle of the chain. */
+ diskFlags = VIR_LOCK_MANAGER_RESOURCE_SHARED;
+ src = src->backingStore;
}
- return 0;
+ ret = 0;
+ cleanup:
+ return ret;
}
--
2.4.6