With this flag, virDomainSnapshotCreate will use fs-freeze and
fs-thaw guest agent commands to quiesce guest's disks.
---
include/libvirt/libvirt.h.in | 4 ++
src/libvirt.c | 6 ++
src/qemu/qemu_driver.c | 118 ++++++++++++++++++++++++++++++++++++-----
3 files changed, 113 insertions(+), 15 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 5e6e488..182065d 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -3125,6 +3125,10 @@ typedef enum {
system checkpoint */
VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT = (1 << 5), /* reuse any existing
external files */
+ VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE = (1 << 6), /* use guest agent to
+ quiesce all mounted
+ file systems within
+ the domain */
} virDomainSnapshotCreateFlags;
/* Take a snapshot of the current VM state */
diff --git a/src/libvirt.c b/src/libvirt.c
index 96ad3d5..d9b8d88 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -16602,6 +16602,12 @@ virDomainSnapshotGetConnect(virDomainSnapshotPtr snapshot)
* inconsistent (as if power had been pulled), and specifying this
* with the VIR_DOMAIN_SNAPSHOT_CREATE_HALT flag risks data loss.
*
+ * If @flags includes VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE, then the
+ * libvirt will attempt to use guest agent to freeze and thaw all
+ * file systems in use within domain OS. However, if the guest agent
+ * is not present, an error is trowed. Moreover, this flags requires
+ * VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY to be passed as well.
+ *
* By default, if the snapshot involves external files, and any of the
* destination files already exist as a regular file, the snapshot is
* rejected to avoid losing contents of those files. However, if
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index c81289a..14ad30b 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -9461,6 +9461,56 @@ static int qemuDomainSnapshotIsAllowed(virDomainObjPtr vm)
return 1;
}
+static int
+qemuDomainSnapshotFSFreeze(struct qemud_driver *driver,
+ virDomainObjPtr vm) {
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ int freezed;
+
+ if (priv->agentError) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("QEMU guest agent is not "
+ "available due to an error"));
+ return -1;
+ }
+ if (!priv->agent) {
+ qemuReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+ _("QEMU guest agent is not configured"));
+ return -1;
+ }
+
+ qemuDomainObjEnterAgent(driver, vm);
+ freezed = qemuAgentFSFreeze(priv->agent);
+ qemuDomainObjExitAgent(driver, vm);
+
+ return freezed;
+}
+
+static int
+qemuDomainSnapshotFSThaw(struct qemud_driver *driver,
+ virDomainObjPtr vm) {
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ int thawed;
+
+ if (priv->agentError) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("QEMU guest agent is not "
+ "available due to an error"));
+ return -1;
+ }
+ if (!priv->agent) {
+ qemuReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+ _("QEMU guest agent is not configured"));
+ return -1;
+ }
+
+ qemuDomainObjEnterAgent(driver, vm);
+ thawed = qemuAgentFSThaw(priv->agent);
+ qemuDomainObjExitAgent(driver, vm);
+
+ return thawed;
+}
+
/* The domain is expected to be locked and inactive. */
static int
qemuDomainSnapshotCreateInactive(struct qemud_driver *driver,
@@ -9493,6 +9543,13 @@ qemuDomainSnapshotCreateActive(virConnectPtr conn,
}
if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
+ if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE) &&
+ (qemuDomainSnapshotFSFreeze(driver, vm) < 0)) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Unable to freeze domain's file systems"));
+ goto endjob;
+ }
+
/* savevm monitor command pauses the domain emitting an event which
* confuses libvirt since it's not notified when qemu resumes the
* domain. Thus we stop and start CPUs ourselves.
@@ -9532,13 +9589,21 @@ qemuDomainSnapshotCreateActive(virConnectPtr conn,
}
cleanup:
- if (resume && virDomainObjIsActive(vm) &&
- qemuProcessStartCPUs(driver, vm, conn,
- VIR_DOMAIN_RUNNING_UNPAUSED,
- QEMU_ASYNC_JOB_NONE) < 0 &&
- virGetLastError() == NULL) {
- qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
- _("resuming after snapshot failed"));
+ if (resume && virDomainObjIsActive(vm)) {
+ if (qemuProcessStartCPUs(driver, vm, conn,
+ VIR_DOMAIN_RUNNING_UNPAUSED,
+ QEMU_ASYNC_JOB_NONE) < 0 &&
+ virGetLastError() == NULL) {
+ qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
+ _("resuming after snapshot failed"));
+ goto endjob;
+ }
+
+ if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE) &&
+ qemuDomainSnapshotFSThaw(driver, vm) < 0) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Unable to thaw domain's file systems"));
+ }
}
endjob:
@@ -9773,6 +9838,13 @@ qemuDomainSnapshotCreateDiskActive(virConnectPtr conn,
if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
+ if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE) &&
+ (qemuDomainSnapshotFSFreeze(driver, vm) < 0)) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Unable to freeze domain's file systems"));
+ goto endjob;
+ }
+
/* In qemu, snapshot_blkdev on a single disk will pause cpus,
* but this confuses libvirt since notifications are not given
* when qemu resumes. And for multiple disks, libvirt must
@@ -9840,13 +9912,21 @@ qemuDomainSnapshotCreateDiskActive(virConnectPtr conn,
}
cleanup:
- if (resume && virDomainObjIsActive(vm) &&
- qemuProcessStartCPUs(driver, vm, conn,
- VIR_DOMAIN_RUNNING_UNPAUSED,
- QEMU_ASYNC_JOB_NONE) < 0 &&
- virGetLastError() == NULL) {
- qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
- _("resuming after snapshot failed"));
+ if (resume && virDomainObjIsActive(vm)) {
+ if (qemuProcessStartCPUs(driver, vm, conn,
+ VIR_DOMAIN_RUNNING_UNPAUSED,
+ QEMU_ASYNC_JOB_NONE) < 0 &&
+ virGetLastError() == NULL) {
+ qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
+ _("resuming after snapshot failed"));
+ goto endjob;
+ }
+
+ if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE) &&
+ qemuDomainSnapshotFSThaw(driver, vm) < 0) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Unable to thaw domain's file systems"));
+ }
}
if (vm) {
@@ -9888,7 +9968,15 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain,
VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA |
VIR_DOMAIN_SNAPSHOT_CREATE_HALT |
VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY |
- VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT, NULL);
+ VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT |
+ VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE, NULL);
+
+ if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE) &&
+ !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY)) {
+ qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("quiesce requires disk-only"));
+ return NULL;
+ }
if (((flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE) &&
!(flags & VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT)) ||
--
1.7.3.4