On 2/23/19 3:00 PM, Eric Blake wrote:
The existing qemu snapshot code has a slight bug: if the domain
is currently pmsuspended, you can't use the _REDEFINE flag even
though the current domain state should have no bearing on being
able to recreate metadata state; and conversely, you can use the
_REDEFINE flag to create snapshot metadata claiming to be
pmsuspended as a bypass to the normal restrictions that you can't
create an original qemu snapshot in that state (the restriction
against pmsuspend is specific to qemu, rather than part of the
driver-agnostic snapshot_conf code).
Fix this by factoring out the snapshot validation into a helper
routine (which will also be useful in a later patch adding bulk
redefine), and by adjusting the state being checked to the one
supplied by the snapshot XML for redefinition, vs. the current
domain state for original creation. However, since snapshots
have one additional state beyond virDomainState (namely, the
"disk-snapshot" state), and given the way virDomainSnapshotState
was defined as an extension enum on top of virDomainState, we
lose out on gcc's ability to force type-based validation that
all switch branches are covered.
Would it be worth adding some sort of compiler warning that
VIR_DOMAIN_SNAPSHOT_STATE_LAST must be VIR_DOMAIN_DISK_SNAPSHOT + 1.
That would cause future additions to virDomainSnapshotState to rework
the math - verify seems to be used for some places. Perhaps something
worthwhile for any other one of these overlaid structs.
In the process, observe that the qemu code already rejects _LIVE
with _REDEFINE, but that this rejection occurs after parsing, and
with a rather confusing message. Hoist that particular exclusive
flag check earlier, so it gets a better error message, and is not
inadvertently skipped when bulk redefine is added later (as that
addition will occur prior to parsing).
Fixes the second problem mentioned in
https://bugzilla.redhat.com/1680304
Signed-off-by: Eric Blake <eblake(a)redhat.com>
---
src/qemu/qemu_driver.c | 117 +++++++++++++++++++++++++----------------
1 file changed, 71 insertions(+), 46 deletions(-)
It seems there are multiple things going on, some code refactoring and
then a couple bug fixes. IDC if they're combined - separating for easier
backporting is always nice...
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index fe1b7801e9..1f37107a20 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -15669,6 +15669,70 @@ qemuDomainSnapshotCreateActiveExternal(virQEMUDriverPtr driver,
}
+/* Validate that a snapshot object does not violate any qemu-specific
+ * constraints. @state is virDomainState if flags implies creation, or
+ * virDomainSnapshotState if flags includes _REDEFINE (the latter
+ * enum is a superset of the former). */
+static int
+qemuDomainSnapshotValidate(virDomainSnapshotDefPtr def, int state,
+ unsigned int flags)
+{
+ /* reject snapshot names containing slashes or starting with dot as
+ * snapshot definitions are saved in files named by the snapshot name */
+ if (!(flags & VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA)) {
+ if (strchr(def->name, '/')) {
+ virReportError(VIR_ERR_XML_DETAIL,
+ _("invalid snapshot name '%s': "
+ "name can't contain '/'"),
+ def->name);
+ return -1;
+ }
+
+ if (def->name[0] == '.') {
+ virReportError(VIR_ERR_XML_DETAIL,
+ _("invalid snapshot name '%s': "
+ "name can't start with '.'"),
+ def->name);
+ return -1;
+ }
+ }
+
+ /* allow snapshots only in certain states */
+ switch (state) {
+ /* valid states */
+ case VIR_DOMAIN_RUNNING:
+ case VIR_DOMAIN_PAUSED:
+ case VIR_DOMAIN_SHUTDOWN:
+ case VIR_DOMAIN_SHUTOFF:
+ case VIR_DOMAIN_CRASHED:
+ break;
+
+ case VIR_DOMAIN_DISK_SNAPSHOT:
+ if (!(flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, _("Invalid domain state
%s"),
+ virDomainSnapshotStateTypeToString(state));
I assume this is part of the fix - is there perhaps a way or a desire to
distinguish between this and the invalid states below? That is a
slightly different message to more easily know what went wrong without
having to dig into the code.
+ return -1;
+ }
+ break;
+
+ case VIR_DOMAIN_PMSUSPENDED:
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+ _("qemu doesn't support taking snapshots of "
+ "PMSUSPENDED guests"));
+ return -1;
+
+ /* invalid states */
+ case VIR_DOMAIN_NOSTATE:
+ case VIR_DOMAIN_BLOCKED: /* invalid state, unused in qemu */
+ default:
+ virReportError(VIR_ERR_INTERNAL_ERROR, _("Invalid domain state %s"),
+ virDomainSnapshotStateTypeToString(state));
+ return -1;
+ }
+
+ return 0;
+}
+
static virDomainSnapshotPtr
qemuDomainSnapshotCreateXML(virDomainPtr domain,
const char *xmlDesc,
@@ -15703,6 +15767,9 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain,
VIR_REQUIRE_FLAG_RET(VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE,
VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY,
NULL);
+ VIR_EXCLUSIVE_FLAGS_RET(VIR_DOMAIN_SNAPSHOT_CREATE_LIVE,
+ VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE,
+ NULL);
And perhaps this is a 3rd bug fix in the same patch .
if ((redefine && !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT)) ||
(flags & VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA))
@@ -15740,62 +15807,20 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain,
parse_flags)))
goto cleanup;
- /* reject snapshot names containing slashes or starting with dot as
- * snapshot definitions are saved in files named by the snapshot name */
- if (!(flags & VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA)) {
- if (strchr(def->name, '/')) {
- virReportError(VIR_ERR_XML_DETAIL,
- _("invalid snapshot name '%s': "
- "name can't contain '/'"),
- def->name);
- goto cleanup;
- }
-
- if (def->name[0] == '.') {
- virReportError(VIR_ERR_XML_DETAIL,
- _("invalid snapshot name '%s': "
- "name can't start with '.'"),
- def->name);
- goto cleanup;
- }
- }
+ if (qemuDomainSnapshotValidate(def, redefine ? def->state : vm->state.state,
Is passing of a different state value the 2nd bug?
+ flags) < 0)
+ goto cleanup;
/* reject the VIR_DOMAIN_SNAPSHOT_CREATE_LIVE flag where not supported */
if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_LIVE &&
(!virDomainObjIsActive(vm) ||
- def->memory != VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL ||
- redefine)) {
Was this part of what I called the 3rd bug?
Probably would be good to separate if you think that's wise/feasible.
Since this is a bug fix it is a change that could be accepted post
freeze. I'll let you decide how to proceed -
Reviewed-by: John Ferlan <jferlan(a)redhat.com>
John
+ def->memory != VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL))
{
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
_("live snapshot creation is supported only "
"with external checkpoints"));
goto cleanup;
}
- /* allow snapshots only in certain states */
- switch ((virDomainState) vm->state.state) {
- /* valid states */
- case VIR_DOMAIN_RUNNING:
- case VIR_DOMAIN_PAUSED:
- case VIR_DOMAIN_SHUTDOWN:
- case VIR_DOMAIN_SHUTOFF:
- case VIR_DOMAIN_CRASHED:
- break;
-
- case VIR_DOMAIN_PMSUSPENDED:
- virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
- _("qemu doesn't support taking snapshots of "
- "PMSUSPENDED guests"));
- goto cleanup;
-
- /* invalid states */
- case VIR_DOMAIN_NOSTATE:
- case VIR_DOMAIN_BLOCKED: /* invalid state, unused in qemu */
- case VIR_DOMAIN_LAST:
- virReportError(VIR_ERR_INTERNAL_ERROR, _("Invalid domain state %s"),
- virDomainStateTypeToString(vm->state.state));
- goto cleanup;
- }
-
/* We are going to modify the domain below. Internal snapshots would use
* a regular job, so we need to set the job mask to disallow query as
* 'savevm' blocks the monitor. External snapshot will then modify the