Adds 'quiesced' status into qemuDomainObjPrivate that tracks whether
FSFreeze is requested in the domain.
It modifies error code from qemuDomainSnapshotFSFreeze and
qemuDomainSnapshotFSThaw, so that a caller can know whether the command is
actually sent to the guest agent. If the error is caused before sending a
freeze command, a counterpart thaw command shouldn't be sent either, not to
confuse fsfreeze status tracking.
Signed-off-by: Tomoki Sekiyama <tomoki.sekiyama(a)hds.com>
---
src/qemu/qemu_domain.c | 5 +++
src/qemu/qemu_domain.h | 2 +
src/qemu/qemu_driver.c | 70 +++++++++++++++++++++++++++++++++++++++---------
3 files changed, 64 insertions(+), 13 deletions(-)
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index a3c1b1c..642120a 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -357,6 +357,9 @@ qemuDomainObjPrivateXMLFormat(virBufferPtr buf, void *data)
virBufferAddLit(buf, "</devices>\n");
}
+ if (priv->quiesced)
+ virBufferAddLit(buf, "<quiesced/>\n");
+
return 0;
}
@@ -518,6 +521,8 @@ qemuDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt, void *data)
}
VIR_FREE(nodes);
+ priv->quiesced = virXPathBoolean("boolean(./quiesced)", ctxt) == 1;
+
return 0;
error:
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
index 31611b5..ab27f15 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -176,6 +176,8 @@ struct _qemuDomainObjPrivate {
char **qemuDevices; /* NULL-terminated list of devices aliases known to QEMU */
bool hookRun; /* true if there was a hook run over this domain */
+
+ bool quiesced; /* true if filesystems are quiesced */
};
typedef enum {
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index bf19c6e..05e4c17 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -12060,32 +12060,62 @@ qemuDomainPrepareDiskChainElement(virQEMUDriverPtr driver,
}
+/* Return -1 if request is not sent to agent due to misconfig, -2 if request
+ * is sent but failed, and number of frozen filesystems on success. If -2 is
+ * returned, FSThaw should be called revert the quiesced status. */
static int
-qemuDomainSnapshotFSFreeze(virDomainObjPtr vm)
+qemuDomainSnapshotFSFreeze(virQEMUDriverPtr driver,
+ virDomainObjPtr vm)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
+ virQEMUDriverConfigPtr cfg;
int freezed;
+ if (priv->quiesced) {
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("domain is already quiesced"));
+ return -1;
+ }
+
if (!qemuDomainAgentAvailable(priv, true))
return -1;
+ priv->quiesced = true;
+
+ cfg = virQEMUDriverGetConfig(driver);
+ if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) {
+ priv->quiesced = false;
+ virObjectUnref(cfg);
+ return -1;
+ }
+ virObjectUnref(cfg);
+
qemuDomainObjEnterAgent(vm);
freezed = qemuAgentFSFreeze(priv->agent);
qemuDomainObjExitAgent(vm);
-
- return freezed;
+ return freezed < 0 ? -2 : freezed;
}
+/* Return -1 on error, otherwise number of thawed filesystems. */
static int
-qemuDomainSnapshotFSThaw(virDomainObjPtr vm, bool report)
+qemuDomainSnapshotFSThaw(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ bool report)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
+ virQEMUDriverConfigPtr cfg;
int thawed;
virErrorPtr err = NULL;
if (!qemuDomainAgentAvailable(priv, report))
return -1;
+ if (!priv->quiesced && report) {
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("domain is not quiesced"));
+ return -1;
+ }
+
qemuDomainObjEnterAgent(vm);
if (!report)
err = virSaveLastError();
@@ -12095,6 +12125,19 @@ qemuDomainSnapshotFSThaw(virDomainObjPtr vm, bool report)
qemuDomainObjExitAgent(vm);
virFreeError(err);
+
+ if (!report || thawed >= 0) {
+ priv->quiesced = false;
+
+ cfg = virQEMUDriverGetConfig(driver);
+ if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) {
+ /* Revert the statuses when we failed to save them. */
+ priv->quiesced = true;
+ thawed = -1;
+ }
+ virObjectUnref(cfg);
+ }
+
return thawed;
}
@@ -13091,17 +13134,18 @@ qemuDomainSnapshotCreateActiveExternal(virConnectPtr conn,
goto cleanup;
/* If quiesce was requested, then issue a freeze command, and a
- * counterpart thaw command, no matter what. The command will
- * fail if the guest is paused or the guest agent is not
- * running. */
+ * counterpart thaw command when it is actually sent to agent.
+ * The command will fail if the guest is paused or the guest agent
+ * is not running, or is already quiesced. */
if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE) {
- if (qemuDomainSnapshotFSFreeze(vm) < 0) {
- /* helper reported the error */
- thaw = -1;
+ int freeze = qemuDomainSnapshotFSFreeze(driver, vm);
+ if (freeze < 0) {
+ /* the helper reported the error */
+ if (freeze == -2)
+ thaw = -1; /* the command is sent but agent failed */
goto endjob;
- } else {
- thaw = 1;
}
+ thaw = 1;
}
/* We need to track what state the guest is in, since taking the
@@ -13242,7 +13286,7 @@ qemuDomainSnapshotCreateActiveExternal(virConnectPtr conn,
goto cleanup;
}
if (vm && thaw != 0 &&
- qemuDomainSnapshotFSThaw(vm, thaw > 0) < 0) {
+ qemuDomainSnapshotFSThaw(driver, vm, thaw > 0) < 0) {
/* helper reported the error, if it was needed */
if (thaw > 0)
ret = -1;