diff --git a/src/qemu/qemu_agent.c b/src/qemu/qemu_agent.c index 4082331fb6bc8474b1ad4db843deddd57743ed93..57c7cc53b14518690fc9c5ee7004622a570ea520 100644 --- a/src/qemu/qemu_agent.c +++ b/src/qemu/qemu_agent.c @@ -1235,6 +1235,32 @@ qemuAgentMakeCommand(const char *cmdname, return NULL; } +static virJSONValuePtr +qemuAgentMakeStringsArray(const char **strings, unsigned int len) +{ + size_t i; + virJSONValuePtr ret = virJSONValueNewArray(), str; + + if (!ret) + return NULL; + + for (i = 0; i < len; i++) { + str = virJSONValueNewString(strings[i]); + if (!str) + goto error; + + if (virJSONValueArrayAppend(ret, str) < 0) { + virJSONValueFree(str); + goto error; + } + } + return ret; + + error: + virJSONValueFree(ret); + return NULL; +} + void qemuAgentNotifyEvent(qemuAgentPtr mon, qemuAgentEvent event) { @@ -1287,21 +1313,34 @@ int qemuAgentShutdown(qemuAgentPtr mon, /* * qemuAgentFSFreeze: * @mon: Agent + * @mountpoints: Array of mountpoint paths to be frozen, or NULL for all + * @nmountpoints: Number of mountpoints to be frozen, or 0 for all * * Issue guest-fsfreeze-freeze command to guest agent, - * which freezes all mounted file systems and returns + * which freezes file systems mounted on specified mountpoints + * (or all file systems when @mountpoints is NULL), and returns * number of frozen file systems on success. * * Returns: number of file system frozen on success, * -1 on error. */ -int qemuAgentFSFreeze(qemuAgentPtr mon) +int qemuAgentFSFreeze(qemuAgentPtr mon, const char **mountpoints, + unsigned int nmountpoints) { int ret = -1; - virJSONValuePtr cmd; + virJSONValuePtr cmd, arg; virJSONValuePtr reply = NULL; - cmd = qemuAgentMakeCommand("guest-fsfreeze-freeze", NULL); + if (mountpoints && nmountpoints) { + arg = qemuAgentMakeStringsArray(mountpoints, nmountpoints); + if (!arg) + return -1; + + cmd = qemuAgentMakeCommand("guest-fsfreeze-freeze", + "a:mountpoints", arg, NULL); + } else { + cmd = qemuAgentMakeCommand("guest-fsfreeze-freeze", NULL); + } if (!cmd) return -1; diff --git a/src/qemu/qemu_agent.h b/src/qemu/qemu_agent.h index 5fbacdbc6ed9964ee936e7aca2d719fedf901e59..58531d55ab6e6aa503ce2464919df2be35f27050 100644 --- a/src/qemu/qemu_agent.h +++ b/src/qemu/qemu_agent.h @@ -70,7 +70,8 @@ typedef enum { int qemuAgentShutdown(qemuAgentPtr mon, qemuAgentShutdownMode mode); -int qemuAgentFSFreeze(qemuAgentPtr mon); +int qemuAgentFSFreeze(qemuAgentPtr mon, + const char **mountpoints, unsigned int nmountpoints); int qemuAgentFSThaw(qemuAgentPtr mon); int qemuAgentSuspend(qemuAgentPtr mon, diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 24c7781add50699d07b52d757fa9ce1c3a6d0ad0..e1e7f4cab4550e95b1ff3f578a5e99931ffecd97 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -12087,7 +12087,9 @@ qemuDomainPrepareDiskChainElement(virQEMUDriverPtr driver, * returned, FSThaw should be called revert the quiesced status. */ static int qemuDomainSnapshotFSFreeze(virQEMUDriverPtr driver, - virDomainObjPtr vm) + virDomainObjPtr vm, + const char **mountpoints, + unsigned int nmountpoints) { qemuDomainObjPrivatePtr priv = vm->privateData; virQEMUDriverConfigPtr cfg; @@ -12113,7 +12115,7 @@ qemuDomainSnapshotFSFreeze(virQEMUDriverPtr driver, virObjectUnref(cfg); qemuDomainObjEnterAgent(vm); - frozen = qemuAgentFSFreeze(priv->agent); + frozen = qemuAgentFSFreeze(priv->agent, mountpoints, nmountpoints); qemuDomainObjExitAgent(vm); return frozen < 0 ? -2 : frozen; } @@ -13160,7 +13162,7 @@ qemuDomainSnapshotCreateActiveExternal(virConnectPtr conn, * 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) { - int freeze = qemuDomainSnapshotFSFreeze(driver, vm); + int freeze = qemuDomainSnapshotFSFreeze(driver, vm, NULL, 0); if (freeze < 0) { /* the helper reported the error */ if (freeze == -2) @@ -16561,12 +16563,6 @@ qemuDomainFSFreeze(virDomainPtr dom, virCheckFlags(0, -1); - if (mountpoints || nmountpoints) { - virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", - _("specifying mountpoints is not supported")); - return ret; - } - if (!(vm = qemuDomObjFromDomain(dom))) goto cleanup; @@ -16582,7 +16578,7 @@ qemuDomainFSFreeze(virDomainPtr dom, goto endjob; } - ret = qemuDomainSnapshotFSFreeze(driver, vm); + ret = qemuDomainSnapshotFSFreeze(driver, vm, mountpoints, nmountpoints); if (ret == -2) { qemuDomainSnapshotFSThaw(driver, vm, false); ret = -1; diff --git a/tests/qemuagenttest.c b/tests/qemuagenttest.c index 1131d98864a3d5ff4e17e1d2926d18dc184645bb..be207e85622c4fb22dc78b271dfb2a84820a858b 100644 --- a/tests/qemuagenttest.c +++ b/tests/qemuagenttest.c @@ -36,6 +36,7 @@ testQemuAgentFSFreeze(const void *data) { virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data; qemuMonitorTestPtr test = qemuMonitorTestNewAgent(xmlopt); + const char *mountpoints[] = {"/fs1", "/fs2", "/fs3", "/fs4", "/fs5"}; int ret = -1; if (!test) @@ -55,7 +56,8 @@ testQemuAgentFSFreeze(const void *data) "{ \"return\" : 7 }") < 0) goto cleanup; - if ((ret = qemuAgentFSFreeze(qemuMonitorTestGetAgent(test))) < 0) + if ((ret = qemuAgentFSFreeze(qemuMonitorTestGetAgent(test), + mountpoints, 5)) < 0) goto cleanup; if (ret != 5) { @@ -64,7 +66,7 @@ testQemuAgentFSFreeze(const void *data) goto cleanup; } - if ((ret = qemuAgentFSFreeze(qemuMonitorTestGetAgent(test))) < 0) + if ((ret = qemuAgentFSFreeze(qemuMonitorTestGetAgent(test), NULL, 0)) < 0) goto cleanup; if (ret != 7) { @@ -547,7 +549,7 @@ testQemuAgentTimeout(const void *data) NULL, NULL) < 0) goto cleanup; - if (qemuAgentFSFreeze(qemuMonitorTestGetAgent(test)) != -1) { + if (qemuAgentFSFreeze(qemuMonitorTestGetAgent(test), NULL, 0) != -1) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", "agent command should have failed"); goto cleanup;