d89b3e
From 4e7b21b4138e011c05ae72ed8b92f0bd2b888744 Mon Sep 17 00:00:00 2001
d89b3e
Message-Id: <4e7b21b4138e011c05ae72ed8b92f0bd2b888744@dist-git>
d89b3e
From: Peter Krempa <pkrempa@redhat.com>
d89b3e
Date: Tue, 17 Mar 2015 13:13:53 +0100
d89b3e
Subject: [PATCH] qemu: Disallow concurrent block jobs on a single disk
d89b3e
d89b3e
https://bugzilla.redhat.com/show_bug.cgi?id=1202719
d89b3e
d89b3e
While qemu may be prepared to do this libvirt is not. Forbid the block
d89b3e
ops until we fix our code.
d89b3e
d89b3e
(cherry picked from commit 51f9f03a4ca50b070c0fbfb29748d49f583e15e1)
d89b3e
d89b3e
Conflicts:
d89b3e
	src/qemu/qemu_domain.h - context with upstream changes
d89b3e
d89b3e
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
d89b3e
---
d89b3e
 src/conf/domain_conf.h |  4 ++++
d89b3e
 src/qemu/qemu_domain.c | 23 +++++++++++++++++++++++
d89b3e
 src/qemu/qemu_domain.h |  2 ++
d89b3e
 src/qemu/qemu_driver.c | 28 +++++++++++++---------------
d89b3e
 4 files changed, 42 insertions(+), 15 deletions(-)
d89b3e
d89b3e
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
d89b3e
index 1436eb8..654c27d 100644
d89b3e
--- a/src/conf/domain_conf.h
d89b3e
+++ b/src/conf/domain_conf.h
d89b3e
@@ -636,6 +636,10 @@ struct _virDomainDiskDef {
d89b3e
     int tray_status; /* enum virDomainDiskTray */
d89b3e
     int removable; /* enum virTristateSwitch */
d89b3e
 
d89b3e
+    /* ideally we want a smarter way to interlock block jobs on single qemu disk
d89b3e
+     * in the future, but for now we just disallow any concurrent job on a
d89b3e
+     * single disk */
d89b3e
+    bool blockjob;
d89b3e
     virStorageSourcePtr mirror;
d89b3e
     int mirrorState; /* enum virDomainDiskMirrorState */
d89b3e
     int mirrorJob; /* virDomainBlockJobType */
d89b3e
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
d89b3e
index 0c3d21f..b9bf3eb 100644
d89b3e
--- a/src/qemu/qemu_domain.c
d89b3e
+++ b/src/qemu/qemu_domain.c
d89b3e
@@ -2771,6 +2771,29 @@ qemuDomainDetermineDiskChain(virQEMUDriverPtr driver,
d89b3e
     return ret;
d89b3e
 }
d89b3e
 
d89b3e
+
d89b3e
+bool
d89b3e
+qemuDomainDiskBlockJobIsActive(virDomainDiskDefPtr disk)
d89b3e
+{
d89b3e
+    if (disk->mirror) {
d89b3e
+        virReportError(VIR_ERR_BLOCK_COPY_ACTIVE,
d89b3e
+                       _("disk '%s' already in active block job"),
d89b3e
+                       disk->dst);
d89b3e
+
d89b3e
+        return true;
d89b3e
+    }
d89b3e
+
d89b3e
+    if (disk->blockjob) {
d89b3e
+        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
d89b3e
+                       _("disk '%s' already in active block job"),
d89b3e
+                       disk->dst);
d89b3e
+        return true;
d89b3e
+    }
d89b3e
+
d89b3e
+    return false;
d89b3e
+}
d89b3e
+
d89b3e
+
d89b3e
 int
d89b3e
 qemuDomainUpdateDeviceList(virQEMUDriverPtr driver,
d89b3e
                            virDomainObjPtr vm,
d89b3e
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
d89b3e
index 76054ec..63d1261 100644
d89b3e
--- a/src/qemu/qemu_domain.h
d89b3e
+++ b/src/qemu/qemu_domain.h
d89b3e
@@ -416,4 +416,6 @@ int qemuDomainJobInfoToParams(qemuDomainJobInfoPtr jobInfo,
d89b3e
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2)
d89b3e
     ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4);
d89b3e
 
d89b3e
+bool qemuDomainDiskBlockJobIsActive(virDomainDiskDefPtr disk);
d89b3e
+
d89b3e
 #endif /* __QEMU_DOMAIN_H__ */
d89b3e
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
d89b3e
index a19281d..2bd4a1d 100644
d89b3e
--- a/src/qemu/qemu_driver.c
d89b3e
+++ b/src/qemu/qemu_driver.c
d89b3e
@@ -4490,6 +4490,7 @@ processBlockJobEvent(virQEMUDriverPtr driver,
d89b3e
             disk->mirrorJob = VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN;
d89b3e
             ignore_value(qemuDomainDetermineDiskChain(driver, vm, disk,
d89b3e
                                                       true, true));
d89b3e
+            disk->blockjob = false;
d89b3e
             break;
d89b3e
 
d89b3e
         case VIR_DOMAIN_BLOCK_JOB_READY:
d89b3e
@@ -4505,6 +4506,7 @@ processBlockJobEvent(virQEMUDriverPtr driver,
d89b3e
                 VIR_DOMAIN_DISK_MIRROR_STATE_ABORT : VIR_DOMAIN_DISK_MIRROR_STATE_NONE;
d89b3e
             disk->mirrorJob = VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN;
d89b3e
             save = true;
d89b3e
+            disk->blockjob = false;
d89b3e
             break;
d89b3e
 
d89b3e
         case VIR_DOMAIN_BLOCK_JOB_LAST:
d89b3e
@@ -15583,6 +15585,7 @@ qemuDomainBlockPivot(virConnectPtr conn,
d89b3e
         disk->mirror = NULL;
d89b3e
         disk->mirrorState = VIR_DOMAIN_DISK_MIRROR_STATE_NONE;
d89b3e
         disk->mirrorJob = VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN;
d89b3e
+        disk->blockjob = false;
d89b3e
     }
d89b3e
     if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
d89b3e
         ret = -1;
d89b3e
@@ -15679,12 +15682,9 @@ qemuDomainBlockJobImpl(virDomainObjPtr vm,
d89b3e
         goto endjob;
d89b3e
     disk = vm->def->disks[idx];
d89b3e
 
d89b3e
-    if (mode == BLOCK_JOB_PULL && disk->mirror) {
d89b3e
-        virReportError(VIR_ERR_BLOCK_COPY_ACTIVE,
d89b3e
-                       _("disk '%s' already in active block job"),
d89b3e
-                       disk->dst);
d89b3e
+    if (mode == BLOCK_JOB_PULL && qemuDomainDiskBlockJobIsActive(disk))
d89b3e
         goto endjob;
d89b3e
-    }
d89b3e
+
d89b3e
     if (mode == BLOCK_JOB_ABORT) {
d89b3e
         if ((flags & VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT) &&
d89b3e
             !(async && disk->mirror)) {
d89b3e
@@ -15756,6 +15756,8 @@ qemuDomainBlockJobImpl(virDomainObjPtr vm,
d89b3e
         if (mode == BLOCK_JOB_ABORT && disk->mirror)
d89b3e
             disk->mirrorState = VIR_DOMAIN_DISK_MIRROR_STATE_NONE;
d89b3e
         goto endjob;
d89b3e
+    } else if (mode == BLOCK_JOB_PULL) {
d89b3e
+        disk->blockjob = true;
d89b3e
     }
d89b3e
 
d89b3e
     /* Snoop block copy operations, so future cancel operations can
d89b3e
@@ -15943,12 +15945,8 @@ qemuDomainBlockCopy(virDomainObjPtr vm,
d89b3e
         goto endjob;
d89b3e
     }
d89b3e
     disk = vm->def->disks[idx];
d89b3e
-    if (disk->mirror) {
d89b3e
-        virReportError(VIR_ERR_BLOCK_COPY_ACTIVE,
d89b3e
-                       _("disk '%s' already in active block job"),
d89b3e
-                       disk->dst);
d89b3e
+    if (qemuDomainDiskBlockJobIsActive(disk))
d89b3e
         goto endjob;
d89b3e
-    }
d89b3e
 
d89b3e
     if (!(virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DRIVE_MIRROR) &&
d89b3e
           virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKJOB_ASYNC))) {
d89b3e
@@ -16074,6 +16072,7 @@ qemuDomainBlockCopy(virDomainObjPtr vm,
d89b3e
     disk->mirror = mirror;
d89b3e
     mirror = NULL;
d89b3e
     disk->mirrorJob = VIR_DOMAIN_BLOCK_JOB_TYPE_COPY;
d89b3e
+    disk->blockjob = true;
d89b3e
 
d89b3e
     if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
d89b3e
         VIR_WARN("Unable to save status on vm %s after state change",
d89b3e
@@ -16232,12 +16231,9 @@ qemuDomainBlockCommit(virDomainPtr dom,
d89b3e
                        disk->dst);
d89b3e
         goto endjob;
d89b3e
     }
d89b3e
-    if (disk->mirror) {
d89b3e
-        virReportError(VIR_ERR_BLOCK_COPY_ACTIVE,
d89b3e
-                       _("disk '%s' already in active block job"),
d89b3e
-                       disk->dst);
d89b3e
+
d89b3e
+    if (qemuDomainDiskBlockJobIsActive(disk))
d89b3e
         goto endjob;
d89b3e
-    }
d89b3e
     if (qemuDomainDetermineDiskChain(driver, vm, disk, false, true) < 0)
d89b3e
         goto endjob;
d89b3e
 
d89b3e
@@ -16358,6 +16354,8 @@ qemuDomainBlockCommit(virDomainPtr dom,
d89b3e
                                  bandwidth);
d89b3e
     qemuDomainObjExitMonitor(driver, vm);
d89b3e
 
d89b3e
+    disk->blockjob = true;
d89b3e
+
d89b3e
     if (mirror) {
d89b3e
         if (ret == 0) {
d89b3e
             virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
d89b3e
-- 
d89b3e
2.3.3
d89b3e