"seamless-migration",
"block-commit",
"vnc",
+
+ "drive-mirror", /* 115 */
);
struct _qemuCaps {
qemuCapsSet(caps, QEMU_CAPS_BLOCK_COMMIT);
else if (STREQ(name, "query-vnc"))
qemuCapsSet(caps, QEMU_CAPS_VNC);
+ else if (STREQ(name, "drive-mirror"))
+ qemuCapsSet(caps, QEMU_CAPS_DRIVE_MIRROR);
VIR_FREE(name);
}
VIR_FREE(commands);
QEMU_CAPS_SEAMLESS_MIGRATION = 112, /* seamless-migration for SPICE */
QEMU_CAPS_BLOCK_COMMIT = 113, /* block-commit */
QEMU_CAPS_VNC = 114, /* Is -vnc available? */
+ QEMU_CAPS_DRIVE_MIRROR = 115, /* drive-mirror monitor command */
QEMU_CAPS_LAST, /* this must always be the last item */
};
return ret;
}
+/* Start a drive-mirror block job. bandwidth is in MiB/sec. */
+int
+qemuMonitorDriveMirror(qemuMonitorPtr mon,
+ const char *device, const char *file,
+ const char *format, unsigned long bandwidth,
+ unsigned int flags)
+{
+ int ret = -1;
+ unsigned long long speed;
+
+ VIR_DEBUG("mon=%p, device=%s, file=%s, format=%s, bandwidth=%ld, "
+ "flags=%x",
+ mon, device, file, NULLSTR(format), bandwidth, flags);
+
+ /* Convert bandwidth MiB to bytes */
+ speed = bandwidth;
+ if (speed > ULLONG_MAX / 1024 / 1024) {
+ virReportError(VIR_ERR_OVERFLOW,
+ _("bandwidth must be less than %llu"),
+ ULLONG_MAX / 1024 / 1024);
+ return -1;
+ }
+ speed <<= 20;
+
+ if (mon->json)
+ ret = qemuMonitorJSONDriveMirror(mon, device, file, format, speed,
+ flags);
+ else
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("drive-mirror requires JSON monitor"));
+ return ret;
+}
+
/* Use the transaction QMP command to run atomic snapshot commands. */
int
qemuMonitorTransaction(qemuMonitorPtr mon, virJSONValuePtr actions)
return ret;
}
-/* Start a block-commit block job. bandwidth is in MB/sec. */
+/* Start a block-commit block job. bandwidth is in MiB/sec. */
int
qemuMonitorBlockCommit(qemuMonitorPtr mon, const char *device,
const char *top, const char *base,
return ret;
}
+/* Use the block-job-complete monitor command to pivot a block copy
+ * job. */
+int
+qemuMonitorDrivePivot(qemuMonitorPtr mon, const char *device,
+ const char *file, const char *format)
+{
+ int ret = -1;
+
+ VIR_DEBUG("mon=%p, device=%s, file=%s, format=%s",
+ mon, device, file, NULLSTR(format));
+
+ if (mon->json)
+ ret = qemuMonitorJSONDrivePivot(mon, device, file, format);
+ else
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("drive pivot requires JSON monitor"));
+ return ret;
+}
+
int qemuMonitorArbitraryCommand(qemuMonitorPtr mon,
const char *cmd,
char **reply,
return ret;
}
-/* bandwidth is in MB/sec */
+/* bandwidth is in MiB/sec */
int qemuMonitorBlockJob(qemuMonitorPtr mon,
const char *device,
const char *base,
bool reuse);
int qemuMonitorTransaction(qemuMonitorPtr mon, virJSONValuePtr actions)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+int qemuMonitorDriveMirror(qemuMonitorPtr mon,
+ const char *device,
+ const char *file,
+ const char *format,
+ unsigned long bandwidth,
+ unsigned int flags)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
+int qemuMonitorDrivePivot(qemuMonitorPtr mon,
+ const char *device,
+ const char *file,
+ const char *format)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
int qemuMonitorBlockCommit(qemuMonitorPtr mon,
const char *device,
return ret;
}
+/* speed is in bytes/sec */
+int
+qemuMonitorJSONDriveMirror(qemuMonitorPtr mon,
+ const char *device, const char *file,
+ const char *format, unsigned long long speed,
+ unsigned int flags)
+{
+ int ret = -1;
+ virJSONValuePtr cmd;
+ virJSONValuePtr reply = NULL;
+ bool shallow = (flags & VIR_DOMAIN_BLOCK_REBASE_SHALLOW) != 0;
+ bool reuse = (flags & VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT) != 0;
+
+ cmd = qemuMonitorJSONMakeCommand("drive-mirror",
+ "s:device", device,
+ "s:target", file,
+ "U:speed", speed,
+ "s:sync", shallow ? "top" : "full",
+ "s:mode",
+ reuse ? "existing" : "absolute-paths",
+ format ? "s:format" : NULL, format,
+ NULL);
+ if (!cmd)
+ return -1;
+
+ if ((ret = qemuMonitorJSONCommand(mon, cmd, &reply)) < 0)
+ goto cleanup;
+ ret = qemuMonitorJSONCheckError(cmd, reply);
+
+cleanup:
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
+
int
qemuMonitorJSONTransaction(qemuMonitorPtr mon, virJSONValuePtr actions)
{
return ret;
}
+int
+qemuMonitorJSONDrivePivot(qemuMonitorPtr mon, const char *device,
+ const char *file ATTRIBUTE_UNUSED,
+ const char *format ATTRIBUTE_UNUSED)
+{
+ int ret;
+ virJSONValuePtr cmd;
+ virJSONValuePtr reply = NULL;
+
+ cmd = qemuMonitorJSONMakeCommand("block-job-complete",
+ "s:device", device,
+ NULL);
+ if (!cmd)
+ return -1;
+
+ if ((ret = qemuMonitorJSONCommand(mon, cmd, &reply)) < 0)
+ goto cleanup;
+ ret = qemuMonitorJSONCheckError(cmd, reply);
+
+cleanup:
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
+
int qemuMonitorJSONArbitraryCommand(qemuMonitorPtr mon,
const char *cmd_str,
const char *device,
const char *file,
const char *format,
- bool reuse);
-int qemuMonitorJSONTransaction(qemuMonitorPtr mon, virJSONValuePtr actions);
+ bool reuse)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3)
+ ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5);
+int qemuMonitorJSONTransaction(qemuMonitorPtr mon, virJSONValuePtr actions)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+int qemuMonitorJSONDriveMirror(qemuMonitorPtr mon,
+ const char *device,
+ const char *file,
+ const char *format,
+ unsigned long long speed,
+ unsigned int flags)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
+int qemuMonitorJSONDrivePivot(qemuMonitorPtr mon,
+ const char *device,
+ const char *file,
+ const char *format)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
int qemuMonitorJSONBlockCommit(qemuMonitorPtr mon,
const char *device,