[libvirt] [PATCH v2 0/5] Expose FSFreeze/FSThaw within the guest as API

Hello, This is patchset v2 to add FSFreeze/FSThaw API for custom disk snapshotting. Changes to v1: * added quiesced status tracking to avoid double fsfreeze in qemu driver * removed unused 'mountPoint' argument * use "@acl: domain:write" in remote driver * rebased to master (v1: http://www.redhat.com/archives/libvir-list/2013-November/msg00610.html ) === Description === Currently FSFreeze and FSThaw are supported by qemu guest agent and they are used internally in snapshot-create command with --quiesce option. However, when users want to utilize the native snapshot feature of storage devices (such as LVM over iSCSI, enterprise storage appliances, etc.), they need to issue fsfreeze command separately from libvirt-driven snapshots. (OpenStack cinder provides these storages' snapshot feature, but it cannot quiesce the guest filesystems automatically for now.) Although virDomainQemuGuestAgent() API could be used for this purpose, it is only for debugging and is not supported officially. This patchset adds virDomainFSFreeze()/virDomainFSThaw() APIs and virsh domfsfreeze/domfsthaw commands to enable the users to freeze and thaw domain's filesystems cleanly. The APIs have flags option currently unsupported for future extension. --- Tomoki Sekiyama (5): Introduce virDomainFSFreeze() and virDomainFSThaw() public API remote: Implement virDomainFSFreeze and virDomainFSThaw qemu: Track domain quiesced status qemu: Implement virDomainFSFreeze and virDomainFSThaw virsh: Expose new virDomainFSFreeze and virDomainFSThaw API include/libvirt/libvirt.h.in | 6 ++ src/driver.h | 10 ++++ src/libvirt.c | 70 +++++++++++++++++++++++++ src/libvirt_public.syms | 5 ++ src/qemu/qemu_domain.h | 2 + src/qemu/qemu_driver.c | 119 ++++++++++++++++++++++++++++++++++++++---- src/remote/remote_driver.c | 2 + src/remote/remote_protocol.x | 23 ++++++++ src/remote_protocol-structs | 9 +++ src/rpc/gendispatch.pl | 2 + tools/virsh-domain.c | 92 ++++++++++++++++++++++++++++++++ tools/virsh.pod | 15 +++++ 12 files changed, 344 insertions(+), 11 deletions(-)

New rules are added in fixup_name in gendispatch.pl to keep the name FSFreeze and FSThaw. Signed-off-by: Tomoki Sekiyama <tomoki.sekiyama@hds.com> --- src/remote/remote_driver.c | 2 ++ src/remote/remote_protocol.x | 23 ++++++++++++++++++++++- src/remote_protocol-structs | 9 +++++++++ src/rpc/gendispatch.pl | 2 ++ 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 955465a..8a4efe4 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -7660,6 +7660,8 @@ static virDriver remote_driver = { .domainMigrateFinish3Params = remoteDomainMigrateFinish3Params, /* 1.1.0 */ .domainMigrateConfirm3Params = remoteDomainMigrateConfirm3Params, /* 1.1.0 */ .connectGetCPUModelNames = remoteConnectGetCPUModelNames, /* 1.1.3 */ + .domainFSFreeze = remoteDomainFSFreeze, /* 1.2.3 */ + .domainFSThaw = remoteDomainFSThaw, /* 1.2.3 */ }; static virNetworkDriver network_driver = { diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index f1f2359..3585f63 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -2952,6 +2952,15 @@ struct remote_network_event_lifecycle_msg { int detail; }; +struct remote_domain_fsfreeze_args { + remote_nonnull_domain dom; + unsigned int flags; +}; + +struct remote_domain_fsthaw_args { + remote_nonnull_domain dom; + unsigned int flags; +}; /*----- Protocol. -----*/ @@ -5262,5 +5271,17 @@ enum remote_procedure { * @generate: both * @acl: none */ - REMOTE_PROC_DOMAIN_EVENT_CALLBACK_DEVICE_REMOVED = 333 + REMOTE_PROC_DOMAIN_EVENT_CALLBACK_DEVICE_REMOVED = 333, + + /** + * @generate: both + * @acl: domain:write + */ + REMOTE_PROC_DOMAIN_FSFREEZE = 334, + + /** + * @generate: both + * @acl: domain:write + */ + REMOTE_PROC_DOMAIN_FSTHAW = 335 }; diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 5636d55..07086a0 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -2420,6 +2420,13 @@ struct remote_network_event_lifecycle_msg { remote_nonnull_network net; int event; int detail; +struct remote_domain_fsfreeze_args { + remote_nonnull_domain dom; + u_int flags; +}; +struct remote_domain_fsthaw_args { + remote_nonnull_domain dom; + u_int flags; }; enum remote_procedure { REMOTE_PROC_CONNECT_OPEN = 1, @@ -2755,4 +2762,6 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_EVENT_CALLBACK_BALLOON_CHANGE = 331, REMOTE_PROC_DOMAIN_EVENT_CALLBACK_PMSUSPEND_DISK = 332, REMOTE_PROC_DOMAIN_EVENT_CALLBACK_DEVICE_REMOVED = 333, + REMOTE_PROC_DOMAIN_FSFREEZE = 334, + REMOTE_PROC_DOMAIN_FSTHAW = 335, }; diff --git a/src/rpc/gendispatch.pl b/src/rpc/gendispatch.pl index ceb1ad8..0b256f3 100755 --- a/src/rpc/gendispatch.pl +++ b/src/rpc/gendispatch.pl @@ -64,6 +64,8 @@ sub fixup_name { $name =~ s/Nmi$/NMI/; $name =~ s/Pm/PM/; $name =~ s/Fstrim$/FSTrim/; + $name =~ s/Fsfreeze$/FSFreeze/; + $name =~ s/Fsthaw$/FSThaw/; $name =~ s/Scsi/SCSI/; $name =~ s/Wwn$/WWN/;

On Wed, Mar 05, 2014 at 02:53:03PM -0500, Tomoki Sekiyama wrote:
New rules are added in fixup_name in gendispatch.pl to keep the name FSFreeze and FSThaw.
Signed-off-by: Tomoki Sekiyama <tomoki.sekiyama@hds.com> --- src/remote/remote_driver.c | 2 ++ src/remote/remote_protocol.x | 23 ++++++++++++++++++++++- src/remote_protocol-structs | 9 +++++++++ src/rpc/gendispatch.pl | 2 ++ 4 files changed, 35 insertions(+), 1 deletion(-)
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 955465a..8a4efe4 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -7660,6 +7660,8 @@ static virDriver remote_driver = { .domainMigrateFinish3Params = remoteDomainMigrateFinish3Params, /* 1.1.0 */ .domainMigrateConfirm3Params = remoteDomainMigrateConfirm3Params, /* 1.1.0 */ .connectGetCPUModelNames = remoteConnectGetCPUModelNames, /* 1.1.3 */ + .domainFSFreeze = remoteDomainFSFreeze, /* 1.2.3 */ + .domainFSThaw = remoteDomainFSThaw, /* 1.2.3 */ };
static virNetworkDriver network_driver = {
@@ -5262,5 +5271,17 @@ enum remote_procedure { * @generate: both * @acl: none */ - REMOTE_PROC_DOMAIN_EVENT_CALLBACK_DEVICE_REMOVED = 333 + REMOTE_PROC_DOMAIN_EVENT_CALLBACK_DEVICE_REMOVED = 333, + + /** + * @generate: both + * @acl: domain:write + */ + REMOTE_PROC_DOMAIN_FSFREEZE = 334, + + /** + * @generate: both + * @acl: domain:write + */ + REMOTE_PROC_DOMAIN_FSTHAW = 335
I think this is a case where we should invent a new permission name. Add VIR_ACCESS_PERM_DOMAIN_FS_FREEZE to src/access/viraccessperm.h and use it for both of these RPC calls. We should also make the existing VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE flag for snapshot APIs uses this new permission. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

Hi Daniel, Thank you for the review.
@@ -5262,5 +5271,17 @@ enum remote_procedure { * @generate: both * @acl: none */ - REMOTE_PROC_DOMAIN_EVENT_CALLBACK_DEVICE_REMOVED = 333 + REMOTE_PROC_DOMAIN_EVENT_CALLBACK_DEVICE_REMOVED = 333, + + /** + * @generate: both + * @acl: domain:write + */ + REMOTE_PROC_DOMAIN_FSFREEZE = 334, + + /** + * @generate: both + * @acl: domain:write + */ + REMOTE_PROC_DOMAIN_FSTHAW = 335
I think this is a case where we should invent a new permission name. Add VIR_ACCESS_PERM_DOMAIN_FS_FREEZE to src/access/viraccessperm.h and use it for both of these RPC calls. We should also make the existing VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE flag for snapshot APIs uses this new permission.
I see. I will add the new acl for this and for VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE flag. Thanks, Tomoki Sekiyama

Adds an quiesced flag into qemuDomainObjPrivate that tracks whether guest filesystems of the domain is quiesced of not. 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 to avoid confusing the tracking of quiesced status. --- src/qemu/qemu_domain.h | 2 ++ src/qemu/qemu_driver.c | 41 +++++++++++++++++++++++++++++++---------- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index 0bed50b..8a79a00 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 the domain filesystems are quiesced */ }; typedef enum { diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 9aad2dc..8109e46 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -12040,6 +12040,8 @@ cleanup: } +/* Return -1 if request is not sent to agent due to misconfig, -2 on agent + * failure, and number of frozen filesystems on success. */ static int qemuDomainSnapshotFSFreeze(virDomainObjPtr vm) { qemuDomainObjPrivatePtr priv = vm->privateData; @@ -12056,14 +12058,24 @@ qemuDomainSnapshotFSFreeze(virDomainObjPtr vm) { _("QEMU guest agent is not configured")); return -1; } + if (priv->quiesced) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("domain is already quiesced")); + return -1; + } qemuDomainObjEnterAgent(vm); freezed = qemuAgentFSFreeze(priv->agent); qemuDomainObjExitAgent(vm); - return freezed; + if (freezed >= 0) + priv->quiesced = true; + + return freezed < 0 ? -2 : freezed; } +/* Return -1 if request is not sent to agent due to misconfig, -2 on agent + * failure, and number of thawed filesystems on success. */ static int qemuDomainSnapshotFSThaw(virDomainObjPtr vm, bool report) { @@ -12084,6 +12096,11 @@ qemuDomainSnapshotFSThaw(virDomainObjPtr vm, bool report) _("QEMU guest agent is not configured")); return -1; } + if (!priv->quiesced && report) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("domain is not quiesced")); + return -1; + } qemuDomainObjEnterAgent(vm); if (!report) @@ -12093,8 +12110,11 @@ qemuDomainSnapshotFSThaw(virDomainObjPtr vm, bool report) virSetError(err); qemuDomainObjExitAgent(vm); + if (thawed >= 0) + priv->quiesced = false; + virFreeError(err); - return thawed; + return thawed < 0 ? -2 : thawed; } /* The domain is expected to be locked and inactive. */ @@ -13069,17 +13089,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 the 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(vm); + if (freeze < 0) { + /* the helper reported the error */ + if (freeze != -1) + 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

On Wed, Mar 05, 2014 at 02:53:10PM -0500, Tomoki Sekiyama wrote:
Adds an quiesced flag into qemuDomainObjPrivate that tracks whether guest filesystems of the domain is quiesced of not. 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 to avoid confusing the tracking of quiesced status. --- src/qemu/qemu_domain.h | 2 ++ src/qemu/qemu_driver.c | 41 +++++++++++++++++++++++++++++++---------- 2 files changed, 33 insertions(+), 10 deletions(-)
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index 0bed50b..8a79a00 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 the domain filesystems are quiesced */ };
typedef enum {
You will also want to update qemuDomainObjPrivateXMLFormat and qemuDomainObjPrivateXMLParse so that this new 'quiesced' attribute is preserved in the live XML state across libvirtd restarts.
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 9aad2dc..8109e46 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -12040,6 +12040,8 @@ cleanup: }
+/* Return -1 if request is not sent to agent due to misconfig, -2 on agent + * failure, and number of frozen filesystems on success. */ static int qemuDomainSnapshotFSFreeze(virDomainObjPtr vm) { qemuDomainObjPrivatePtr priv = vm->privateData; @@ -12056,14 +12058,24 @@ qemuDomainSnapshotFSFreeze(virDomainObjPtr vm) { _("QEMU guest agent is not configured")); return -1; } + if (priv->quiesced) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("domain is already quiesced")); + return -1; + }
qemuDomainObjEnterAgent(vm); freezed = qemuAgentFSFreeze(priv->agent); qemuDomainObjExitAgent(vm);
- return freezed; + if (freezed >= 0) + priv->quiesced = true; + + return freezed < 0 ? -2 : freezed; }
+/* Return -1 if request is not sent to agent due to misconfig, -2 on agent + * failure, and number of thawed filesystems on success. */ static int qemuDomainSnapshotFSThaw(virDomainObjPtr vm, bool report) { @@ -12084,6 +12096,11 @@ qemuDomainSnapshotFSThaw(virDomainObjPtr vm, bool report) _("QEMU guest agent is not configured")); return -1; } + if (!priv->quiesced && report) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("domain is not quiesced")); + return -1; + }
qemuDomainObjEnterAgent(vm); if (!report) @@ -12093,8 +12110,11 @@ qemuDomainSnapshotFSThaw(virDomainObjPtr vm, bool report) virSetError(err); qemuDomainObjExitAgent(vm);
+ if (thawed >= 0) + priv->quiesced = false; + virFreeError(err); - return thawed; + return thawed < 0 ? -2 : thawed; }
And in both these methods you want to call virDomainSaveStatus after changing the priv->quiesced flag, to save the status XML to disk
/* The domain is expected to be locked and inactive. */ @@ -13069,17 +13089,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 the 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(vm); + if (freeze < 0) { + /* the helper reported the error */ + if (freeze != -1) + thaw = -1; /* the command is sent but agent failed */ goto endjob; - } else { - thaw = 1; } + thaw = 1; }
I'm not sure I understand why you're changing this ? Are you trying to deal with the case where the guest is already frozen, but someone has still supplied the VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE flag ? I'd probably argue that such usage is a bug we should report to the caller as an error. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On Wed, Mar 05, 2014 at 02:53:10PM -0500, Tomoki Sekiyama wrote:
Adds an quiesced flag into qemuDomainObjPrivate that tracks whether guest filesystems of the domain is quiesced of not. 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 to avoid confusing the tracking of quiesced status. --- src/qemu/qemu_domain.h | 2 ++ src/qemu/qemu_driver.c | 41 +++++++++++++++++++++++++++++++---------- 2 files changed, 33 insertions(+), 10 deletions(-)
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index 0bed50b..8a79a00 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 */ + v> + bool quiesced; /* true if the domain filesystems are quiesced */ };
typedef enum {
You will also want to update qemuDomainObjPrivateXMLFormat and qemuDomainObjPrivateXMLParse so that this new 'quiesced' attribute is preserved in the live XML state across libvirtd restarts.
OK, I will update them too.
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 9aad2dc..8109e46 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -12040,6 +12040,8 @@ cleanup: }
+/* Return -1 if request is not sent to agent due to misconfig, -2 on agent + * failure, and number of frozen filesystems on success. */ static int qemuDomainSnapshotFSFreeze(virDomainObjPtr vm) { qemuDomainObjPrivatePtr priv = vm->privateData; @@ -12056,14 +12058,24 @@ qemuDomainSnapshotFSFreeze(virDomainObjPtr vm) { _("QEMU guest agent is not configured")); return -1; } + if (priv->quiesced) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("domain is already quiesced")); + return -1; + }
qemuDomainObjEnterAgent(vm); freezed = qemuAgentFSFreeze(priv->agent); qemuDomainObjExitAgent(vm);
- return freezed; + if (freezed >= 0) + priv->quiesced = true; + + return freezed < 0 ? -2 : freezed; }
+/* Return -1 if request is not sent to agent due to misconfig, -2 on agent + * failure, and number of thawed filesystems on success. */ static int qemuDomainSnapshotFSThaw(virDomainObjPtr vm, bool report) { @@ -12084,6 +12096,11 @@ qemuDomainSnapshotFSThaw(virDomainObjPtr vm, bool report) _("QEMU guest agent is not configured")); return -1; } + if (!priv->quiesced && report) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("domain is not quiesced")); + return -1; + }
qemuDomainObjEnterAgent(vm); if (!report) @@ -12093,8 +12110,11 @@ qemuDomainSnapshotFSThaw(virDomainObjPtr vm, bool report) virSetError(err); qemuDomainObjExitAgent(vm);
+ if (thawed >= 0) + priv->quiesced = false; + virFreeError(err); - return thawed; + return thawed < 0 ? -2 : thawed; }
And in both these methods you want to call virDomainSaveStatus after changing the priv->quiesced flag, to save the status XML to disk
OK. Thanks for pointing this out.
/* The domain is expected to be locked and inactive. */ @@ -13069,17 +13089,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 the 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(vm); + if (freeze < 0) { + /* the helper reported the error */ + if (freeze != -1) + thaw = -1; /* the command is sent but agent failed */ goto endjob; - } else { - thaw = 1; } + thaw = 1; }
I'm not sure I understand why you're changing this ? Are you trying to deal with the case where the guest is already frozen, but someone has still supplied the VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE flag ?
Right. Without this change, if VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE flag is supplied for a frozen guest: 1. the caller will get 'domain is already quiesced' error 2. the guest is thawed by the error handling (because of 'thaw = 1;' ) 1 is expected behavior (error reporting to the caller), but 2 would be hardly expected from a user's viewpoint. The intention of this change is to avoid 2.
I'd probably argue that such usage is a bug we should report to the caller as an error.
Thanks, Tomoki Sekiyama

Use qemuDomainSnapshotFSFreeze() and qemuDomainSnapshotFSFreeze() which are already implemented for snapshot quiescing. Signed-off-by: Tomoki Sekiyama <tomoki.sekiyama@hds.com> --- src/qemu/qemu_driver.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 8109e46..29202a3 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -16598,6 +16598,82 @@ qemuConnectGetCPUModelNames(virConnectPtr conn, } +static int +qemuDomainFSFreeze(virDomainPtr dom, + unsigned int flags) +{ + virQEMUDriverPtr driver = dom->conn->privateData; + virDomainObjPtr vm; + int ret = -1; + + virCheckFlags(0, -1); + + if (!(vm = qemuDomObjFromDomain(dom))) + goto cleanup; + + if (virDomainFSFreezeEnsureACL(dom->conn, vm->def) < 0) + goto cleanup; + + if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0) + goto cleanup; + + if (!virDomainObjIsActive(vm)) { + virReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("domain is not running")); + goto endjob; + } + + ret = qemuDomainSnapshotFSFreeze(vm); + +endjob: + if (!qemuDomainObjEndJob(driver, vm)) + vm = NULL; + +cleanup: + if (vm) + virObjectUnlock(vm); + return ret; +} + + +static int +qemuDomainFSThaw(virDomainPtr dom, + unsigned int flags) +{ + virQEMUDriverPtr driver = dom->conn->privateData; + virDomainObjPtr vm; + int ret = -1; + + virCheckFlags(0, -1); + + if (!(vm = qemuDomObjFromDomain(dom))) + goto cleanup; + + if (virDomainFSThawEnsureACL(dom->conn, vm->def) < 0) + goto cleanup; + + if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0) + goto cleanup; + + if (!virDomainObjIsActive(vm)) { + virReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("domain is not running")); + goto endjob; + } + + ret = qemuDomainSnapshotFSThaw(vm, true); + +endjob: + if (!qemuDomainObjEndJob(driver, vm)) + vm = NULL; + +cleanup: + if (vm) + virObjectUnlock(vm); + return ret; +} + + static virDriver qemuDriver = { .no = VIR_DRV_QEMU, .name = QEMU_DRIVER_NAME, @@ -16785,6 +16861,8 @@ static virDriver qemuDriver = { .domainMigrateFinish3Params = qemuDomainMigrateFinish3Params, /* 1.1.0 */ .domainMigrateConfirm3Params = qemuDomainMigrateConfirm3Params, /* 1.1.0 */ .connectGetCPUModelNames = qemuConnectGetCPUModelNames, /* 1.1.3 */ + .domainFSFreeze = qemuDomainFSFreeze, /* 1.2.3 */ + .domainFSThaw = qemuDomainFSThaw, /* 1.2.3 */ };

These are exposed under domfsfreeze command and domfsthaw command. Signed-off-by: Tomoki Sekiyama <tomoki.sekiyama@hds.com> --- tools/virsh-domain.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 15 ++++++++ 2 files changed, 107 insertions(+) diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 1d3c5f0..329e32e 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -11201,6 +11201,86 @@ cleanup: return ret; } +static const vshCmdInfo info_domfsfreeze[] = { + {.name = "help", + .data = N_("Freeze domain's mounted filesystems.") + }, + {.name = "desc", + .data = N_("Freeze domain's mounted filesystems.") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_domfsfreeze[] = { + {.name = "domain", + .type = VSH_OT_DATA, + .flags = VSH_OFLAG_REQ, + .help = N_("domain name, id or uuid") + }, + {.name = NULL} +}; +static bool +cmdDomFSFreeze(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom = NULL; + bool ret = false; + unsigned int flags = 0; + + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) + return ret; + + if (virDomainFSFreeze(dom, flags) < 0) { + vshError(ctl, _("Unable to freeze filesystems")); + goto cleanup; + } + + ret = true; + +cleanup: + virDomainFree(dom); + return ret; +} + +static const vshCmdInfo info_domfsthaw[] = { + {.name = "help", + .data = N_("Thaw domain's mounted filesystems.") + }, + {.name = "desc", + .data = N_("Thaw domain's mounted filesystems.") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_domfsthaw[] = { + {.name = "domain", + .type = VSH_OT_DATA, + .flags = VSH_OFLAG_REQ, + .help = N_("domain name, id or uuid") + }, + {.name = NULL} +}; +static bool +cmdDomFSThaw(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom = NULL; + bool ret = false; + unsigned int flags = 0; + + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) + return ret; + + if (virDomainFSThaw(dom, flags) < 0) { + vshError(ctl, _("Unable to thaw filesystems")); + goto cleanup; + } + + ret = true; + +cleanup: + virDomainFree(dom); + return ret; +} + const vshCmdDef domManagementCmds[] = { {.name = "attach-device", .handler = cmdAttachDevice, @@ -11348,6 +11428,18 @@ const vshCmdDef domManagementCmds[] = { .info = info_domdisplay, .flags = 0 }, + {.name = "domfsfreeze", + .handler = cmdDomFSFreeze, + .opts = opts_domfsfreeze, + .info = info_domfsfreeze, + .flags = 0 + }, + {.name = "domfsthaw", + .handler = cmdDomFSThaw, + .opts = opts_domfsthaw, + .info = info_domfsthaw, + .flags = 0 + }, {.name = "domfstrim", .handler = cmdDomFSTrim, .opts = opts_domfstrim, diff --git a/tools/virsh.pod b/tools/virsh.pod index cafbb9a..e234bde 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -926,6 +926,21 @@ Output a URI which can be used to connect to the graphical display of the domain via VNC, SPICE or RDP. If I<--include-password> is specified, the SPICE channel password will be included in the URI. +=item B<domfsfreeze> I<domain> + +Freeze all mounted filesystems within a running domain to prepare for +consistent snapshots. + +Note that B<snapshot-create> command has a I<--quiesce> option to freeze +and thaw the filesystems automatically to keep snapshots consistent. +B<domfsfreeze> command is only needed when a user wants to utilize the +native snapshot features of storage devices not supported by libvirt yet. + +=item B<domfsthaw> I<domain> + +Thaw all mounted filesystems within a running domain, which are frozen +by domfsfreeze command. + =item B<domfstrim> I<domain> [I<--minimum> B<bytes>] [I<--mountpoint mountPoint>]

On Wed, Mar 05, 2014 at 02:52:49PM -0500, Tomoki Sekiyama wrote:
Hello,
This is patchset v2 to add FSFreeze/FSThaw API for custom disk snapshotting.
Patch 1 in your series hasn't arrived in my inbox, nor is it visible in the mail archves... Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On 3/6/14 4:32 , "Daniel P. Berrange" <berrange@redhat.com> wrote:
On Wed, Mar 05, 2014 at 02:52:49PM -0500, Tomoki Sekiyama wrote:
Hello,
This is patchset v2 to add FSFreeze/FSThaw API for custom disk snapshotting.
Patch 1 in your series hasn't arrived in my inbox, nor is it visible in the mail archves...
I'm sorry, it looks like the smtp server's spam filter dislike patch 1/5 by some reason.... (Although I received bcc-ed in my inbox...) I sent it again and this should be in the thread now. Sorry for confusion. Regards, Tomoki Sekiyama
Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

These will freeze and thaw filesystems within guest. The APIs take flags arguments which are currently not used, for future extensions. Signed-off-by: Tomoki Sekiyama <tomoki.sekiyama@hds.com> --- include/libvirt/libvirt.h.in | 6 ++++ src/driver.h | 10 ++++++ src/libvirt.c | 70 ++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 5 +++ 4 files changed, 91 insertions(+) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 295d551..22f373b 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -5245,6 +5245,12 @@ int virDomainFSTrim(virDomainPtr dom, unsigned long long minimum, unsigned int flags); +int virDomainFSFreeze(virDomainPtr dom, + unsigned int flags); + +int virDomainFSThaw(virDomainPtr dom, + unsigned int flags); + /** * virSchedParameterType: * diff --git a/src/driver.h b/src/driver.h index fbfaac4..7e6aec0 100644 --- a/src/driver.h +++ b/src/driver.h @@ -1130,6 +1130,14 @@ typedef int unsigned int flags, int cancelled); +typedef int +(*virDrvDomainFSFreeze)(virDomainPtr dom, + unsigned int flags); + +typedef int +(*virDrvDomainFSThaw)(virDomainPtr dom, + unsigned int flags); + typedef struct _virDriver virDriver; typedef virDriver *virDriverPtr; @@ -1341,6 +1349,8 @@ struct _virDriver { virDrvDomainMigrateFinish3Params domainMigrateFinish3Params; virDrvDomainMigrateConfirm3Params domainMigrateConfirm3Params; virDrvConnectGetCPUModelNames connectGetCPUModelNames; + virDrvDomainFSFreeze domainFSFreeze; + virDrvDomainFSThaw domainFSThaw; }; diff --git a/src/libvirt.c b/src/libvirt.c index a385935..84c9783 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -20552,3 +20552,73 @@ error: virDispatchError(dom->conn); return -1; } + +/** + * virDomainFSFreeze: + * @dom: a domain object + * @flags: extra flags, not used yet, so callers should always pass 0 + * + * Freeze filesystems within the guest (hence guest agent may be + * required depending on hypervisor used). + * + * Returns 0 on success, -1 otherwise. + */ +int +virDomainFSFreeze(virDomainPtr dom, + unsigned int flags) +{ + VIR_DOMAIN_DEBUG(dom, "flags=%x", flags); + + virResetLastError(); + + virCheckDomainReturn(dom, -1); + virCheckReadOnlyGoto(dom->conn->flags, error); + + if (dom->conn->driver->domainFSFreeze) { + int ret = dom->conn->driver->domainFSFreeze(dom, flags); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + +error: + virDispatchError(dom->conn); + return -1; +} + +/** + * virDomainFSThaw: + * @dom: a domain object + * @flags: extra flags, not used yet, so callers should always pass 0 + * + * Thaw the frozen filesystems within the guest (hence guest agent + * may be required depending on hypervisor used). + * + * Returns 0 on success, -1 otherwise. + */ +int +virDomainFSThaw(virDomainPtr dom, + unsigned int flags) +{ + VIR_DOMAIN_DEBUG(dom, "flags=%x", flags); + + virResetLastError(); + + virCheckDomainReturn(dom, -1); + virCheckReadOnlyGoto(dom->conn->flags, error); + + if (dom->conn->driver->domainFSThaw) { + int ret = dom->conn->driver->domainFSThaw(dom, flags); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + +error: + virDispatchError(dom->conn); + return -1; +} diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 6ed6ce6..9e49a9d 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -645,5 +645,10 @@ LIBVIRT_1.2.1 { virConnectNetworkEventDeregisterAny; } LIBVIRT_1.1.3; +LIBVIRT_1.2.3 { + global: + virDomainFSFreeze; + virDomainFSThaw; +} LIBVIRT_1.2.1; # .... define new API here using predicted next version number ....

On Thu, Mar 06, 2014 at 11:09:09AM -0500, Tomoki Sekiyama wrote:
These will freeze and thaw filesystems within guest. The APIs take flags arguments which are currently not used, for future extensions.
Signed-off-by: Tomoki Sekiyama <tomoki.sekiyama@hds.com> --- include/libvirt/libvirt.h.in | 6 ++++ src/driver.h | 10 ++++++ src/libvirt.c | 70 ++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 5 +++ 4 files changed, 91 insertions(+)
ACK Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
participants (2)
-
Daniel P. Berrange
-
Tomoki Sekiyama