diff --git a/src/Makefile.am b/src/Makefile.am
index 17cf318804a3527ebb821ce2f9a6959967c49646..73ac643c954a203e79b5cfbf488d792f7803735e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -714,6 +714,7 @@ VBOX_DRIVER_EXTRA_DIST = \
QEMU_DRIVER_SOURCES = \
qemu/qemu_agent.c qemu/qemu_agent.h \
+ qemu/qemu_blockjob.c qemu/qemu_blockjob.h \
qemu/qemu_capabilities.c qemu/qemu_capabilities.h \
qemu/qemu_command.c qemu/qemu_command.h \
qemu/qemu_domain.c qemu/qemu_domain.h \
diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
new file mode 100644
index 0000000000000000000000000000000000000000..e61ad8cce62ed8b8221dc7106c29f1b966f8ec4f
--- /dev/null
+++ b/src/qemu/qemu_blockjob.c
@@ -0,0 +1,167 @@
+/*
+ * qemu_blockjob.c: helper functions for QEMU block jobs
+ *
+ * Copyright (C) 2006-2015 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * .
+ */
+
+#include
+
+#include "internal.h"
+
+#include "qemu_blockjob.h"
+#include "qemu_domain.h"
+
+#include "conf/domain_conf.h"
+#include "conf/domain_event.h"
+
+#include "virlog.h"
+#include "virstoragefile.h"
+
+#define VIR_FROM_THIS VIR_FROM_QEMU
+
+VIR_LOG_INIT("qemu.qemu_blockjob");
+
+/**
+ * qemuBlockJobEventProcess:
+ * @driver: qemu driver
+ * @vm: domain
+ * @disk: domain disk
+ * @type: block job type
+ * @status: block job status
+ *
+ * Update disk's mirror state in response to a block job event
+ * from QEMU. For mirror state's that must survive libvirt
+ * restart, also update the domain's status XML.
+ *
+ * Returns 0 on success, -1 otherwise.
+ */
+void
+qemuBlockJobEventProcess(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ virDomainDiskDefPtr disk,
+ int type,
+ int status)
+{
+ virObjectEventPtr event = NULL;
+ virObjectEventPtr event2 = NULL;
+ const char *path;
+ virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+ virDomainDiskDefPtr persistDisk = NULL;
+ bool save = false;
+
+ /* Have to generate two variants of the event for old vs. new
+ * client callbacks */
+ if (type == VIR_DOMAIN_BLOCK_JOB_TYPE_COMMIT &&
+ disk->mirrorJob == VIR_DOMAIN_BLOCK_JOB_TYPE_ACTIVE_COMMIT)
+ type = disk->mirrorJob;
+ path = virDomainDiskGetSource(disk);
+ event = virDomainEventBlockJobNewFromObj(vm, path, type, status);
+ event2 = virDomainEventBlockJob2NewFromObj(vm, disk->dst, type, status);
+
+ /* If we completed a block pull or commit, then update the XML
+ * to match. */
+ switch ((virConnectDomainEventBlockJobStatus) status) {
+ case VIR_DOMAIN_BLOCK_JOB_COMPLETED:
+ if (disk->mirrorState == VIR_DOMAIN_DISK_MIRROR_STATE_PIVOT) {
+ if (vm->newDef) {
+ int indx = virDomainDiskIndexByName(vm->newDef, disk->dst, false);
+ virStorageSourcePtr copy = NULL;
+
+ if (indx >= 0) {
+ persistDisk = vm->newDef->disks[indx];
+ copy = virStorageSourceCopy(disk->mirror, false);
+ if (virStorageSourceInitChainElement(copy,
+ persistDisk->src,
+ true) < 0) {
+ VIR_WARN("Unable to update persistent definition "
+ "on vm %s after block job",
+ vm->def->name);
+ virStorageSourceFree(copy);
+ copy = NULL;
+ persistDisk = NULL;
+ }
+ }
+ if (copy) {
+ virStorageSourceFree(persistDisk->src);
+ persistDisk->src = copy;
+ }
+ }
+
+ /* XXX We want to revoke security labels and disk
+ * lease, as well as audit that revocation, before
+ * dropping the original source. But it gets tricky
+ * if both source and mirror share common backing
+ * files (we want to only revoke the non-shared
+ * portion of the chain); so for now, we leak the
+ * access to the original. */
+ virStorageSourceFree(disk->src);
+ disk->src = disk->mirror;
+ } else {
+ virStorageSourceFree(disk->mirror);
+ }
+
+ /* Recompute the cached backing chain to match our
+ * updates. Better would be storing the chain ourselves
+ * rather than reprobing, but we haven't quite completed
+ * that conversion to use our XML tracking. */
+ disk->mirror = NULL;
+ save = disk->mirrorState != VIR_DOMAIN_DISK_MIRROR_STATE_NONE;
+ disk->mirrorState = VIR_DOMAIN_DISK_MIRROR_STATE_NONE;
+ disk->mirrorJob = VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN;
+ ignore_value(qemuDomainDetermineDiskChain(driver, vm, disk,
+ true, true));
+ disk->blockjob = false;
+ break;
+
+ case VIR_DOMAIN_BLOCK_JOB_READY:
+ disk->mirrorState = VIR_DOMAIN_DISK_MIRROR_STATE_READY;
+ save = true;
+ break;
+
+ case VIR_DOMAIN_BLOCK_JOB_FAILED:
+ case VIR_DOMAIN_BLOCK_JOB_CANCELED:
+ virStorageSourceFree(disk->mirror);
+ disk->mirror = NULL;
+ disk->mirrorState = status == VIR_DOMAIN_BLOCK_JOB_FAILED ?
+ VIR_DOMAIN_DISK_MIRROR_STATE_ABORT : VIR_DOMAIN_DISK_MIRROR_STATE_NONE;
+ disk->mirrorJob = VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN;
+ save = true;
+ disk->blockjob = false;
+ break;
+
+ case VIR_DOMAIN_BLOCK_JOB_LAST:
+ break;
+ }
+
+ if (save) {
+ if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
+ VIR_WARN("Unable to save status on vm %s after block job",
+ vm->def->name);
+ if (persistDisk && virDomainSaveConfig(cfg->configDir,
+ vm->newDef) < 0)
+ VIR_WARN("Unable to update persistent definition on vm %s "
+ "after block job", vm->def->name);
+ }
+
+ if (event)
+ qemuDomainEventQueue(driver, event);
+ if (event2)
+ qemuDomainEventQueue(driver, event2);
+
+ virObjectUnref(cfg);
+}
diff --git a/src/qemu/qemu_blockjob.h b/src/qemu/qemu_blockjob.h
new file mode 100644
index 0000000000000000000000000000000000000000..abe1aa5e49d481e4fabb2ef5d19e61039d5a7b96
--- /dev/null
+++ b/src/qemu/qemu_blockjob.h
@@ -0,0 +1,33 @@
+/*
+ * qemu_blockjob.h: helper functions for QEMU block jobs
+ *
+ * Copyright (C) 2006-2015 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * .
+ */
+
+#ifndef __QEMU_BLOCKJOB_H__
+# define __QEMU_BLOCKJOB_H__
+
+# include "qemu_conf.h"
+
+void qemuBlockJobEventProcess(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ virDomainDiskDefPtr disk,
+ int type,
+ int status);
+
+#endif /* __QEMU_BLOCKJOB_H__ */
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 2fb4ac97f2b69b47b4b07b2d1ec41580b0c3c0d7..cfd96710d564479864db85c41bf3e5440d16cd26 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -55,6 +55,7 @@
#include "qemu_monitor.h"
#include "qemu_process.h"
#include "qemu_migration.h"
+#include "qemu_blockjob.h"
#include "virerror.h"
#include "virlog.h"
@@ -4534,123 +4535,6 @@ processSerialChangedEvent(virQEMUDriverPtr driver,
}
-static void
-qemuBlockJobEventProcess(virQEMUDriverPtr driver,
- virDomainObjPtr vm,
- virDomainDiskDefPtr disk,
- int type,
- int status)
-{
- virObjectEventPtr event = NULL;
- virObjectEventPtr event2 = NULL;
- const char *path;
- virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
- virDomainDiskDefPtr persistDisk = NULL;
- bool save = false;
-
- /* Have to generate two variants of the event for old vs. new
- * client callbacks */
- if (type == VIR_DOMAIN_BLOCK_JOB_TYPE_COMMIT &&
- disk->mirrorJob == VIR_DOMAIN_BLOCK_JOB_TYPE_ACTIVE_COMMIT)
- type = disk->mirrorJob;
- path = virDomainDiskGetSource(disk);
- event = virDomainEventBlockJobNewFromObj(vm, path, type, status);
- event2 = virDomainEventBlockJob2NewFromObj(vm, disk->dst, type, status);
-
- /* If we completed a block pull or commit, then update the XML
- * to match. */
- switch ((virConnectDomainEventBlockJobStatus) status) {
- case VIR_DOMAIN_BLOCK_JOB_COMPLETED:
- if (disk->mirrorState == VIR_DOMAIN_DISK_MIRROR_STATE_PIVOT) {
- if (vm->newDef) {
- int indx = virDomainDiskIndexByName(vm->newDef, disk->dst, false);
- virStorageSourcePtr copy = NULL;
-
- if (indx >= 0) {
- persistDisk = vm->newDef->disks[indx];
- copy = virStorageSourceCopy(disk->mirror, false);
- if (virStorageSourceInitChainElement(copy,
- persistDisk->src,
- true) < 0) {
- VIR_WARN("Unable to update persistent definition "
- "on vm %s after block job",
- vm->def->name);
- virStorageSourceFree(copy);
- copy = NULL;
- persistDisk = NULL;
- }
- }
- if (copy) {
- virStorageSourceFree(persistDisk->src);
- persistDisk->src = copy;
- }
- }
-
- /* XXX We want to revoke security labels and disk
- * lease, as well as audit that revocation, before
- * dropping the original source. But it gets tricky
- * if both source and mirror share common backing
- * files (we want to only revoke the non-shared
- * portion of the chain); so for now, we leak the
- * access to the original. */
- virStorageSourceFree(disk->src);
- disk->src = disk->mirror;
- } else {
- virStorageSourceFree(disk->mirror);
- }
-
- /* Recompute the cached backing chain to match our
- * updates. Better would be storing the chain ourselves
- * rather than reprobing, but we haven't quite completed
- * that conversion to use our XML tracking. */
- disk->mirror = NULL;
- save = disk->mirrorState != VIR_DOMAIN_DISK_MIRROR_STATE_NONE;
- disk->mirrorState = VIR_DOMAIN_DISK_MIRROR_STATE_NONE;
- disk->mirrorJob = VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN;
- ignore_value(qemuDomainDetermineDiskChain(driver, vm, disk,
- true, true));
- disk->blockjob = false;
- break;
-
- case VIR_DOMAIN_BLOCK_JOB_READY:
- disk->mirrorState = VIR_DOMAIN_DISK_MIRROR_STATE_READY;
- save = true;
- break;
-
- case VIR_DOMAIN_BLOCK_JOB_FAILED:
- case VIR_DOMAIN_BLOCK_JOB_CANCELED:
- virStorageSourceFree(disk->mirror);
- disk->mirror = NULL;
- disk->mirrorState = status == VIR_DOMAIN_BLOCK_JOB_FAILED ?
- VIR_DOMAIN_DISK_MIRROR_STATE_ABORT : VIR_DOMAIN_DISK_MIRROR_STATE_NONE;
- disk->mirrorJob = VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN;
- save = true;
- disk->blockjob = false;
- break;
-
- case VIR_DOMAIN_BLOCK_JOB_LAST:
- break;
- }
-
- if (save) {
- if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
- VIR_WARN("Unable to save status on vm %s after block job",
- vm->def->name);
- if (persistDisk && virDomainSaveConfig(cfg->configDir,
- vm->newDef) < 0)
- VIR_WARN("Unable to update persistent definition on vm %s "
- "after block job", vm->def->name);
- }
-
- if (event)
- qemuDomainEventQueue(driver, event);
- if (event2)
- qemuDomainEventQueue(driver, event2);
-
- virObjectUnref(cfg);
-}
-
-
static void
processBlockJobEvent(virQEMUDriverPtr driver,
virDomainObjPtr vm,