Adds 'quiesced' counter into qemuDomainObjPrivate that tracks how many times
fsfreeze is requested in the domain.
When qemuDomainSnapshotFSFreeze is called, the counter is incremented. The
fsfreeze request is sent to the guest agent when the counter changes from 0
to 1. qemuDomainSnapshotFSThaw decrements the counter and requests fsthaw
when it becomes 0.
It also modify 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.
Signed-off-by: Tomoki Sekiyama <tomoki.sekiyama(a)hds.com>
---
src/qemu/qemu_domain.c | 6 ++++
src/qemu/qemu_domain.h | 2 +
src/qemu/qemu_driver.c | 65 ++++++++++++++++++++++++++++++++++++++----------
3 files changed, 59 insertions(+), 14 deletions(-)
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index cdd4601..6ed3d67 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)
+ virBufferAsprintf(buf, "<quiesced depth='%d'/>\n",
priv->quiesced);
+
return 0;
}
@@ -518,6 +521,9 @@ qemuDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt, void *data)
}
VIR_FREE(nodes);
+ if (virXPathInt("string(./quiesced/@depth)", ctxt, &priv->quiesced)
< 0)
+ priv->quiesced = 0;
+
return 0;
error:
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
index b2830c4..620a258 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 */
+
+ int quiesced; /* count how many times filesystems are quiesced */
};
typedef enum {
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 9a2de12..2bb5fa9 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -12100,32 +12100,68 @@ 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. */
static int
-qemuDomainSnapshotFSFreeze(virDomainObjPtr vm)
+qemuDomainSnapshotFSFreeze(virQEMUDriverPtr driver, virDomainObjPtr vm)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
+ virQEMUDriverConfigPtr cfg;
int freezed;
if (!qemuDomainAgentAvailable(priv, true))
return -1;
+ priv->quiesced++;
+ cfg = virQEMUDriverGetConfig(driver);
+ if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) {
+ virObjectUnref(cfg);
+ priv->quiesced--;
+ return -1;
+ }
+ virObjectUnref(cfg);
+
+ if (priv->quiesced > 1)
+ return 0;
+
qemuDomainObjEnterAgent(vm);
freezed = qemuAgentFSFreeze(priv->agent);
qemuDomainObjExitAgent(vm);
-
- return freezed;
+ return freezed < 0 ? -2 : freezed;
}
+/* Return -1 if request is not sent to agent due to misconfig, -2 if request
+ * is sent but failed, and number of thawed filesystems on success. */
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;
+ }
+
+ priv->quiesced--;
+ cfg = virQEMUDriverGetConfig(driver);
+ if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) {
+ virObjectUnref(cfg);
+ priv->quiesced++;
+ return -1;
+ }
+ virObjectUnref(cfg);
+
+ if (priv->quiesced)
+ return 0;
+
qemuDomainObjEnterAgent(vm);
if (!report)
err = virSaveLastError();
@@ -12135,7 +12171,7 @@ qemuDomainSnapshotFSThaw(virDomainObjPtr vm, bool report)
qemuDomainObjExitAgent(vm);
virFreeError(err);
- return thawed;
+ return thawed < 0 ? -2 : thawed;
}
/* The domain is expected to be locked and inactive. */
@@ -13116,17 +13152,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
@@ -13267,7 +13304,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;