qemu 1.3 will be adding a 'block-commit' monitor command, per qemu.git commit ed61fc1. It matches nicely to the libvirt API virDomainBlockCommit. * src/qemu/qemu_capabilities.h (QEMU_CAPS_BLOCK_COMMIT): New bit. * src/qemu/qemu_capabilities.c (qemuCapsProbeQMPCommands): Set it. * src/qemu/qemu_monitor.h (qemuMonitorBlockCommit): New prototype. * src/qemu/qemu_monitor_json.h (qemuMonitorJSONBlockCommit): Likewise. * src/qemu/qemu_monitor.c (qemuMonitorBlockCommit): Implement it. * src/qemu/qemu_monitor_json.c (qemuMonitorJSONBlockCommit): Likewise. (qemuMonitorJSONHandleBlockJobImpl) (qemuMonitorJSONGetBlockJobInfoOne): Handle new event type. --- Change from v1: upstream qemu now has the commit recalculate backing chain after commit completes src/qemu/qemu_capabilities.c | 3 +++ src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_monitor.c | 30 ++++++++++++++++++++++++++++++ src/qemu/qemu_monitor.h | 7 +++++++ src/qemu/qemu_monitor_json.c | 34 ++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 7 +++++++ src/qemu/qemu_process.c | 15 +++++++++------ 7 files changed, 91 insertions(+), 6 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index fb0fe54..73a12f1 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -187,6 +187,7 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST, "reboot-timeout", /* 110 */ "dump-guest-core", "seamless-migration", + "block-commit", ); struct _qemuCaps { @@ -1881,6 +1882,8 @@ qemuCapsProbeQMPCommands(qemuCapsPtr caps, qemuCapsSet(caps, QEMU_CAPS_SPICE); else if (STREQ(name, "query-kvm")) qemuCapsSet(caps, QEMU_CAPS_KVM); + else if (STREQ(name, "block-commit")) + qemuCapsSet(caps, QEMU_CAPS_BLOCK_COMMIT); VIR_FREE(name); } VIR_FREE(commands); diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 5d343c1..6939c45 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -150,6 +150,7 @@ enum qemuCapsFlags { QEMU_CAPS_REBOOT_TIMEOUT = 110, /* -boot reboot-timeout */ QEMU_CAPS_DUMP_GUEST_CORE = 111, /* dump-guest-core-parameter */ QEMU_CAPS_SEAMLESS_MIGRATION = 112, /* seamless-migration for SPICE */ + QEMU_CAPS_BLOCK_COMMIT = 113, /* block-commit */ QEMU_CAPS_LAST, /* this must always be the last item */ }; diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 85b0bc2..68c6d3f 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -2786,6 +2786,36 @@ qemuMonitorTransaction(qemuMonitorPtr mon, virJSONValuePtr actions) return ret; } +/* Start a block-commit block job. bandwidth is in MB/sec. */ +int +qemuMonitorBlockCommit(qemuMonitorPtr mon, const char *device, + const char *top, const char *base, + unsigned long bandwidth) +{ + int ret = -1; + unsigned long long speed; + + VIR_DEBUG("mon=%p, device=%s, top=%s, base=%s, bandwidth=%ld", + mon, device, NULLSTR(top), NULLSTR(base), bandwidth); + + /* 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 = qemuMonitorJSONBlockCommit(mon, device, top, base, speed); + else + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("block-commit requires JSON monitor")); + return ret; +} + int qemuMonitorArbitraryCommand(qemuMonitorPtr mon, const char *cmd, char **reply, diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 54b3a99..9bdc802 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -521,6 +521,13 @@ int qemuMonitorDiskSnapshot(qemuMonitorPtr mon, int qemuMonitorTransaction(qemuMonitorPtr mon, virJSONValuePtr actions) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); +int qemuMonitorBlockCommit(qemuMonitorPtr mon, + const char *device, + const char *top, + const char *base, + unsigned long bandwidth) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); + int qemuMonitorArbitraryCommand(qemuMonitorPtr mon, const char *cmd, char **reply, diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index bd52ce4..501b338 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -803,6 +803,8 @@ qemuMonitorJSONHandleBlockJobImpl(qemuMonitorPtr mon, if (STREQ(type_str, "stream")) type = VIR_DOMAIN_BLOCK_JOB_TYPE_PULL; + else if (STREQ(type_str, "commit")) + type = VIR_DOMAIN_BLOCK_JOB_TYPE_COMMIT; switch ((virConnectDomainEventBlockJobStatus) event) { case VIR_DOMAIN_BLOCK_JOB_COMPLETED: @@ -3269,6 +3271,36 @@ cleanup: return ret; } +/* speed is in bytes/sec */ +int +qemuMonitorJSONBlockCommit(qemuMonitorPtr mon, const char *device, + const char *top, const char *base, + unsigned long speed) +{ + int ret = -1; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + + cmd = qemuMonitorJSONMakeCommand("block-commit", + "s:device", device, + "U:speed", speed, + "s:top", top, + base ? "s:base" : NULL, base, + 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, char **reply_str, @@ -3385,6 +3417,8 @@ static int qemuMonitorJSONGetBlockJobInfoOne(virJSONValuePtr entry, } if (STREQ(type, "stream")) info->type = VIR_DOMAIN_BLOCK_JOB_TYPE_PULL; + else if (STREQ(type, "commit")) + info->type = VIR_DOMAIN_BLOCK_JOB_TYPE_COMMIT; else info->type = VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN; diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 63b84c6..71bc6aa 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -235,6 +235,13 @@ int qemuMonitorJSONDiskSnapshot(qemuMonitorPtr mon, bool reuse); int qemuMonitorJSONTransaction(qemuMonitorPtr mon, virJSONValuePtr actions); +int qemuMonitorJSONBlockCommit(qemuMonitorPtr mon, + const char *device, + const char *top, + const char *base, + unsigned long bandwidth) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); + int qemuMonitorJSONArbitraryCommand(qemuMonitorPtr mon, const char *cmd_str, char **reply_str, diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 58cd8da..3396258 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -909,12 +909,15 @@ qemuProcessHandleBlockJob(qemuMonitorPtr mon ATTRIBUTE_UNUSED, if (disk) { path = disk->src; event = virDomainEventBlockJobNewFromObj(vm, path, type, status); - /* XXX If we completed a block pull, then recompute the cached - * backing chain to match. Better would be storing the chain - * ourselves rather than reprobing, but this requires - * modifying domain_conf and our XML to fully track the chain - * across libvirtd restarts. */ - if (type == VIR_DOMAIN_BLOCK_JOB_TYPE_PULL && + /* XXX If we completed a block pull or commit, then recompute + * the cached backing chain to match. Better would be storing + * the chain ourselves rather than reprobing, but this + * requires modifying domain_conf and our XML to fully track + * the chain across libvirtd restarts. For that matter, if + * qemu gains support for committing the active layer, we have + * to update disk->src. */ + if ((type == VIR_DOMAIN_BLOCK_JOB_TYPE_PULL || + type == VIR_DOMAIN_BLOCK_JOB_TYPE_COMMIT) && status == VIR_DOMAIN_BLOCK_JOB_COMPLETED) qemuDomainDetermineDiskChain(driver, disk, true); } -- 1.7.11.7 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list