[libvirt] [PATCH 0/3] add to blockrebase implementation

0.9.10 added virDomainBlockRebase as a way to expose the pending qemu 'block_stream' monitor command planned for qemu 1.1, including it's optional base parameter, but didn't wire up that part of the new API due to time constraints. RHEL 6.2 backported an earlier version of block_stream that only supports qed, not qcow2, and which lacked the base parameter). I still have plans to further improve the situation in libvirt - we need to express the backing file chain information in XML, and keep that representation up-to-date when doing snapshot and pull operations. But this series is a bare minimum to actually make use of the base parameter, with the burden on the user to pass in a valid base name. Eric Blake (3): qemu: require json for block jobs qemu: pass block pull backing file to monitor virsh: expose partial pull src/qemu/qemu_driver.c | 15 ++-- src/qemu/qemu_monitor.c | 14 ++-- src/qemu/qemu_monitor.h | 6 +- src/qemu/qemu_monitor_json.c | 26 +++++-- src/qemu/qemu_monitor_json.h | 3 +- src/qemu/qemu_monitor_text.c | 175 +----------------------------------------- src/qemu/qemu_monitor_text.h | 8 +-- tools/virsh.c | 19 ++++- tools/virsh.pod | 12 ++- 9 files changed, 63 insertions(+), 215 deletions(-) -- 1.7.7.6

Block job commands are not part of upstream qemu until 1.1; and proper support of job completion and cancellation depends on being able to receive QMP events, which implies the JSON monitor. Additionally, some early versions of block job commands were backported to RHEL qemu, but these versions lacked asynchronous job cancellation and partial block pull, so there are several patches that will still be needed in this area of libvirt code to support both flavors of block job commands. Due to earlier patches in libvirt, we are guaranteed that all versions of qemu that support block job commands already require libvirt to use the JSON monitor. That means that the text version of block jobs will not be used, and having to refactor two copies of the block job handlers makes no sense. So instead, we delete the text handlers. * src/qemu/qemu_monitor.c (qemuMonitorBlockJob): Drop text monitor support. * src/qemu/qemu_monitor_text.h (qemuMonitorTextBlockJob): Delete. * src/qemu/qemu_monitor_text.c (qemuMonitorTextParseBlockJobOne) (qemuMonitorTextParseBlockJob, qemuMonitorTextBlockJob): Likewise. --- src/qemu/qemu_monitor.c | 9 +- src/qemu/qemu_monitor_text.c | 175 +----------------------------------------- src/qemu/qemu_monitor_text.h | 8 +-- 3 files changed, 7 insertions(+), 185 deletions(-) diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 93f3505..903463d 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -1,7 +1,7 @@ /* * qemu_monitor.c: interaction with QEMU monitor console * - * Copyright (C) 2006-2011 Red Hat, Inc. + * Copyright (C) 2006-2012 Red Hat, Inc. * Copyright (C) 2006 Daniel P. Berrange * * This library is free software; you can redistribute it and/or @@ -2657,15 +2657,16 @@ int qemuMonitorBlockJob(qemuMonitorPtr mon, virDomainBlockJobInfoPtr info, int mode) { - int ret; + int ret = -1; - VIR_DEBUG("mon=%p, device=%p, bandwidth=%lu, info=%p, mode=%o", + VIR_DEBUG("mon=%p, device=%s, bandwidth=%lu, info=%p, mode=%o", mon, device, bandwidth, info, mode); if (mon->json) ret = qemuMonitorJSONBlockJob(mon, device, bandwidth, info, mode); else - ret = qemuMonitorTextBlockJob(mon, device, bandwidth, info, mode); + qemuReportError(VIR_ERR_INVALID_ARG, "%s", + _("block jobs require JSON monitor")); return ret; } diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index f051a86..d6f7dac 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -1,7 +1,7 @@ /* * qemu_monitor_text.c: interaction with QEMU monitor console * - * Copyright (C) 2006-2011 Red Hat, Inc. + * Copyright (C) 2006-2012 Red Hat, Inc. * Copyright (C) 2006 Daniel P. Berrange * * This library is free software; you can redistribute it and/or @@ -3280,179 +3280,6 @@ cleanup: return ret; } -static int qemuMonitorTextParseBlockJobOne(const char *text, - const char *device, - virDomainBlockJobInfoPtr info, - const char **next) -{ - virDomainBlockJobInfo tmp; - char *p; - unsigned long long speed_bytes; - int mismatch = 0; - - if (next == NULL) - return -1; - *next = NULL; - - /* - * Each active stream will appear on its own line in the following format: - * Streaming device <device>: Completed <cur> of <end> bytes - */ - if ((text = STRSKIP(text, "Streaming device ")) == NULL) - return -EINVAL; - - if (!STREQLEN(text, device, strlen(device))) - mismatch = 1; - - if ((text = strstr(text, ": Completed ")) == NULL) - return -EINVAL; - text += 11; - - if (virStrToLong_ull (text, &p, 10, &tmp.cur)) - return -EINVAL; - text = p; - - if (!STRPREFIX(text, " of ")) - return -EINVAL; - text += 4; - - if (virStrToLong_ull (text, &p, 10, &tmp.end)) - return -EINVAL; - text = p; - - if (!STRPREFIX(text, " bytes, speed limit ")) - return -EINVAL; - text += 20; - - if (virStrToLong_ull (text, &p, 10, &speed_bytes)) - return -EINVAL; - text = p; - - if (!STRPREFIX(text, " bytes/s")) - return -EINVAL; - - if (mismatch) { - *next = STRSKIP(text, "\n"); - return -EAGAIN; - } - - if (info) { - info->cur = tmp.cur; - info->end = tmp.end; - info->bandwidth = speed_bytes / 1024ULL / 1024ULL; - info->type = VIR_DOMAIN_BLOCK_JOB_TYPE_PULL; - } - return 1; -} - -static int qemuMonitorTextParseBlockJob(const char *text, - const char *device, - virDomainBlockJobInfoPtr info) -{ - const char *next = NULL; - int ret = 0; - - /* Check error: Device not found */ - if (strstr(text, "Device '") && strstr(text, "' not found")) { - qemuReportError(VIR_ERR_OPERATION_INVALID, "%s", _("Device not found")); - return -1; - } - - /* Check error: Job already active on this device */ - if (strstr(text, "Device '") && strstr(text, "' is in use")) { - qemuReportError(VIR_ERR_OPERATION_FAILED, _("Device %s in use"), - device); - return -1; - } - - /* Check error: Stop non-existent job */ - if (strstr(text, "has not been activated")) { - qemuReportError(VIR_ERR_OPERATION_INVALID,\ - _("No active operation on device: %s"), device); - return -1; - } - - /* This is not an error condition, there are just no results to report. */ - if (strstr(text, "No active jobs")) { - return 0; - } - - /* Check for unsupported operation */ - if (strstr(text, "Operation is not supported")) { - qemuReportError(VIR_ERR_OPERATION_INVALID, - _("Operation is not supported for device: %s"), device); - return -1; - } - - /* No output indicates success for Pull, JobAbort, and JobSetSpeed */ - if (STREQ(text, "")) - return 0; - - /* Now try to parse BlockJobInfo */ - do { - ret = qemuMonitorTextParseBlockJobOne(text, device, info, &next); - text = next; - } while (text && ret == -EAGAIN); - - if (ret < 0) - return -1; - return ret; -} - -int qemuMonitorTextBlockJob(qemuMonitorPtr mon, - const char *device, - unsigned long bandwidth, - virDomainBlockJobInfoPtr info, - int mode) -{ - char *cmd = NULL; - char *reply = NULL; - int ret; - const char *cmd_name = NULL; - - if (mode == BLOCK_JOB_ABORT) { - cmd_name = "block_job_cancel"; - ret = virAsprintf(&cmd, "%s %s", cmd_name, device); - } else if (mode == BLOCK_JOB_INFO) { - cmd_name = "info block-jobs"; - ret = virAsprintf(&cmd, "%s", cmd_name); - } else if (mode == BLOCK_JOB_SPEED) { - cmd_name = "block_job_set_speed"; - ret = virAsprintf(&cmd, "%s %s %luM", cmd_name, device, bandwidth); - } else if (mode == BLOCK_JOB_PULL) { - cmd_name = "block_stream"; - ret = virAsprintf(&cmd, "%s %s", cmd_name, device); - } else { - return -1; - } - - if (ret < 0) { - virReportOOMError(); - return -1; - } - - if (qemuMonitorHMPCommand(mon, cmd, &reply) < 0) { - qemuReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("cannot run monitor command")); - ret = -1; - goto cleanup; - } - - if (qemuMonitorTextCommandNotFound(cmd_name, reply)) { - qemuReportError(VIR_ERR_OPERATION_INVALID, - _("Command '%s' is not found"), cmd_name); - ret = -1; - goto cleanup; - } - - ret = qemuMonitorTextParseBlockJob(reply, device, info); - -cleanup: - VIR_FREE(cmd); - VIR_FREE(reply); - return ret; -} - int qemuMonitorTextOpenGraphics(qemuMonitorPtr mon, const char *protocol, diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index 050c30e..719fc82 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -1,7 +1,7 @@ /* * qemu_monitor_text.h: interaction with QEMU monitor console * - * Copyright (C) 2006-2009, 2011 Red Hat, Inc. + * Copyright (C) 2006-2009, 2011-2012 Red Hat, Inc. * Copyright (C) 2006 Daniel P. Berrange * * This library is free software; you can redistribute it and/or @@ -233,12 +233,6 @@ int qemuMonitorTextSendKey(qemuMonitorPtr mon, int qemuMonitorTextScreendump(qemuMonitorPtr mon, const char *file); -int qemuMonitorTextBlockJob(qemuMonitorPtr mon, - const char *device, - unsigned long bandwidth, - virDomainBlockJobInfoPtr info, - int mode); - int qemuMonitorTextSetLink(qemuMonitorPtr mon, const char *name, enum virDomainNetInterfaceLinkState state); -- 1.7.7.6

On 02/18/2012 12:44 PM, Eric Blake wrote:
Block job commands are not part of upstream qemu until 1.1; and proper support of job completion and cancellation depends on being able to receive QMP events, which implies the JSON monitor. Additionally, some early versions of block job commands were backported to RHEL qemu, but these versions lacked asynchronous job cancellation and partial block pull, so there are several patches that will still be needed in this area of libvirt code to support both flavors of block job commands.
Due to earlier patches in libvirt, we are guaranteed that all versions of qemu that support block job commands already require libvirt to use the JSON monitor. That means that the text version of block jobs will not be used, and having to refactor two copies of the block job handlers makes no sense. So instead, we delete the text handlers.
* src/qemu/qemu_monitor.c (qemuMonitorBlockJob): Drop text monitor support. * src/qemu/qemu_monitor_text.h (qemuMonitorTextBlockJob): Delete. * src/qemu/qemu_monitor_text.c (qemuMonitorTextParseBlockJobOne) (qemuMonitorTextParseBlockJob, qemuMonitorTextBlockJob): Likewise. --- src/qemu/qemu_monitor.c | 9 +- src/qemu/qemu_monitor_text.c | 175 +----------------------------------------- src/qemu/qemu_monitor_text.h | 8 +-- 3 files changed, 7 insertions(+), 185 deletions(-)
I'm sure you were very pleased with yourself for creating a diffstat like this :-) The reasoning behind the removal makes sense to me. ACK.

This actually wires up the new optional parameter to block_stream: http://wiki.qemu.org/Features/LiveBlockMigration/ImageStreamingAPI The error checking is still sparse, since libvirt must not use qemu-img or header probing on a qcow2 file in use by qemu to check if the backing file name is valid; so for now, libvirt is relying on qemu to diagnose an incorrect backing name. Fixing this will require libvirt to track the entire backing file chain at the time qemu is started and keeps it updated with snapshot and pull operations. * src/qemu/qemu_monitor_json.c (qemuMonitorJSONBlockJob): Add parameter, and update callers. * src/qemu/qemu_monitor_json.h (qemuMonitorJSONBlockJob): Update signature. * src/qemu/qemu_monitor.h (qemuMonitorBlockJob): Likewise. * src/qemu/qemu_driver.c (qemuDomainBlockJobImpl): Update caller. * src/qemu/qemu_monitor.c (qemuMonitorBlockJob): Likewise. --- src/qemu/qemu_driver.c | 15 ++++++--------- src/qemu/qemu_monitor.c | 7 ++++--- src/qemu/qemu_monitor.h | 6 ++++-- src/qemu/qemu_monitor_json.c | 26 +++++++++++++++++++------- src/qemu/qemu_monitor_json.h | 3 ++- 5 files changed, 35 insertions(+), 22 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 717bdf1..8308b3b 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -11367,14 +11367,6 @@ qemuDomainBlockJobImpl(virDomainPtr dom, const char *path, const char *base, if (!device) { goto cleanup; } - /* XXX - add a qemu capability check; if qemu 1.1 or newer, then - * validate and convert non-NULL base into something that can - * be passed as optional base argument. */ - if (base) { - qemuReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", - _("partial block pull is not supported with this QEMU binary")); - goto cleanup; - } if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0) goto cleanup; @@ -11387,7 +11379,12 @@ qemuDomainBlockJobImpl(virDomainPtr dom, const char *path, const char *base, qemuDomainObjEnterMonitorWithDriver(driver, vm); priv = vm->privateData; - ret = qemuMonitorBlockJob(priv->mon, device, bandwidth, info, mode); + /* XXX - add a qemu capability check, since only qemu 1.1 or newer + * supports the base argument. + * XXX - libvirt should really be tracking the backing file chain + * itself, and validating that base is on the chain, rather than + * relying on qemu to do this. */ + ret = qemuMonitorBlockJob(priv->mon, device, base, bandwidth, info, mode); qemuDomainObjExitMonitorWithDriver(driver, vm); endjob: diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 903463d..70ef1d6 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -2653,17 +2653,18 @@ int qemuMonitorScreendump(qemuMonitorPtr mon, int qemuMonitorBlockJob(qemuMonitorPtr mon, const char *device, + const char *base, unsigned long bandwidth, virDomainBlockJobInfoPtr info, int mode) { int ret = -1; - VIR_DEBUG("mon=%p, device=%s, bandwidth=%lu, info=%p, mode=%o", - mon, device, bandwidth, info, mode); + VIR_DEBUG("mon=%p, device=%s, base=%s, bandwidth=%lu, info=%p, mode=%o", + mon, device, NULLSTR(base), bandwidth, info, mode); if (mon->json) - ret = qemuMonitorJSONBlockJob(mon, device, bandwidth, info, mode); + ret = qemuMonitorJSONBlockJob(mon, device, base, bandwidth, info, mode); else qemuReportError(VIR_ERR_INVALID_ARG, "%s", _("block jobs require JSON monitor")); diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 7c6c52b..1d2caea 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -1,7 +1,7 @@ /* * qemu_monitor.h: interaction with QEMU monitor console * - * Copyright (C) 2006-2011 Red Hat, Inc. + * Copyright (C) 2006-2012 Red Hat, Inc. * Copyright (C) 2006 Daniel P. Berrange * * This library is free software; you can redistribute it and/or @@ -518,9 +518,11 @@ typedef enum { int qemuMonitorBlockJob(qemuMonitorPtr mon, const char *device, + const char *back, unsigned long bandwidth, virDomainBlockJobInfoPtr info, - int mode); + int mode) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(5); int qemuMonitorOpenGraphics(qemuMonitorPtr mon, const char *protocol, diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 513788a..2677423 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -3229,17 +3229,25 @@ static int qemuMonitorJSONGetBlockJobInfo(virJSONValuePtr reply, } -int qemuMonitorJSONBlockJob(qemuMonitorPtr mon, - const char *device, - unsigned long bandwidth, - virDomainBlockJobInfoPtr info, - int mode) +int +qemuMonitorJSONBlockJob(qemuMonitorPtr mon, + const char *device, + const char *base, + unsigned long bandwidth, + virDomainBlockJobInfoPtr info, + int mode) { int ret = -1; virJSONValuePtr cmd = NULL; virJSONValuePtr reply = NULL; const char *cmd_name = NULL; + if (base && mode != BLOCK_JOB_PULL) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("only block pull supports base: %s"), base); + return -1; + } + if (mode == BLOCK_JOB_ABORT) { cmd_name = "block_job_cancel"; cmd = qemuMonitorJSONMakeCommand(cmd_name, "s:device", device, NULL); @@ -3254,8 +3262,12 @@ int qemuMonitorJSONBlockJob(qemuMonitorPtr mon, NULL); } else if (mode == BLOCK_JOB_PULL) { cmd_name = "block_stream"; - cmd = qemuMonitorJSONMakeCommand(cmd_name, "s:device", - device, NULL); + if (base) + cmd = qemuMonitorJSONMakeCommand(cmd_name, "s:device", + device, "s:base", base, NULL); + else + cmd = qemuMonitorJSONMakeCommand(cmd_name, "s:device", + device, NULL); } if (!cmd) diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index d0b3000..e307649 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -1,7 +1,7 @@ /* * qemu_monitor_json.h: interaction with QEMU monitor console * - * Copyright (C) 2006-2009, 2011 Red Hat, Inc. + * Copyright (C) 2006-2009, 2011-2012 Red Hat, Inc. * Copyright (C) 2006 Daniel P. Berrange * * This library is free software; you can redistribute it and/or @@ -246,6 +246,7 @@ int qemuMonitorJSONScreendump(qemuMonitorPtr mon, int qemuMonitorJSONBlockJob(qemuMonitorPtr mon, const char *device, + const char *base, unsigned long bandwidth, virDomainBlockJobInfoPtr info, int mode); -- 1.7.7.6

On 02/18/2012 12:44 PM, Eric Blake wrote:
This actually wires up the new optional parameter to block_stream: http://wiki.qemu.org/Features/LiveBlockMigration/ImageStreamingAPI
The error checking is still sparse, since libvirt must not use qemu-img or header probing on a qcow2 file in use by qemu to check if the backing file name is valid; so for now, libvirt is relying on qemu to diagnose an incorrect backing name. Fixing this will require libvirt to track the entire backing file chain at the time qemu is started and keeps it updated with snapshot and pull operations.
Looks like mostly pushing the new parameter down the callstack, moving the location (and conditions) of the check for base being specified at an inappropriate time, and changing the json command sent to actually use base in certain cases. ACK.
* src/qemu/qemu_monitor_json.c (qemuMonitorJSONBlockJob): Add parameter, and update callers. * src/qemu/qemu_monitor_json.h (qemuMonitorJSONBlockJob): Update signature. * src/qemu/qemu_monitor.h (qemuMonitorBlockJob): Likewise. * src/qemu/qemu_driver.c (qemuDomainBlockJobImpl): Update caller. * src/qemu/qemu_monitor.c (qemuMonitorBlockJob): Likewise. --- src/qemu/qemu_driver.c | 15 ++++++--------- src/qemu/qemu_monitor.c | 7 ++++--- src/qemu/qemu_monitor.h | 6 ++++-- src/qemu/qemu_monitor_json.c | 26 +++++++++++++++++++------- src/qemu/qemu_monitor_json.h | 3 ++- 5 files changed, 35 insertions(+), 22 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 717bdf1..8308b3b 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -11367,14 +11367,6 @@ qemuDomainBlockJobImpl(virDomainPtr dom, const char *path, const char *base, if (!device) { goto cleanup; } - /* XXX - add a qemu capability check; if qemu 1.1 or newer, then - * validate and convert non-NULL base into something that can - * be passed as optional base argument. */ - if (base) { - qemuReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", - _("partial block pull is not supported with this QEMU binary")); - goto cleanup; - }
if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0) goto cleanup; @@ -11387,7 +11379,12 @@ qemuDomainBlockJobImpl(virDomainPtr dom, const char *path, const char *base,
qemuDomainObjEnterMonitorWithDriver(driver, vm); priv = vm->privateData; - ret = qemuMonitorBlockJob(priv->mon, device, bandwidth, info, mode); + /* XXX - add a qemu capability check, since only qemu 1.1 or newer + * supports the base argument. + * XXX - libvirt should really be tracking the backing file chain + * itself, and validating that base is on the chain, rather than + * relying on qemu to do this. */ + ret = qemuMonitorBlockJob(priv->mon, device, base, bandwidth, info, mode); qemuDomainObjExitMonitorWithDriver(driver, vm);
endjob: diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 903463d..70ef1d6 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -2653,17 +2653,18 @@ int qemuMonitorScreendump(qemuMonitorPtr mon,
int qemuMonitorBlockJob(qemuMonitorPtr mon, const char *device, + const char *base, unsigned long bandwidth, virDomainBlockJobInfoPtr info, int mode) { int ret = -1;
- VIR_DEBUG("mon=%p, device=%s, bandwidth=%lu, info=%p, mode=%o", - mon, device, bandwidth, info, mode); + VIR_DEBUG("mon=%p, device=%s, base=%s, bandwidth=%lu, info=%p, mode=%o", + mon, device, NULLSTR(base), bandwidth, info, mode);
if (mon->json) - ret = qemuMonitorJSONBlockJob(mon, device, bandwidth, info, mode); + ret = qemuMonitorJSONBlockJob(mon, device, base, bandwidth, info, mode); else qemuReportError(VIR_ERR_INVALID_ARG, "%s", _("block jobs require JSON monitor")); diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 7c6c52b..1d2caea 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -1,7 +1,7 @@ /* * qemu_monitor.h: interaction with QEMU monitor console * - * Copyright (C) 2006-2011 Red Hat, Inc. + * Copyright (C) 2006-2012 Red Hat, Inc. * Copyright (C) 2006 Daniel P. Berrange * * This library is free software; you can redistribute it and/or @@ -518,9 +518,11 @@ typedef enum {
int qemuMonitorBlockJob(qemuMonitorPtr mon, const char *device, + const char *back, unsigned long bandwidth, virDomainBlockJobInfoPtr info, - int mode); + int mode) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(5);
int qemuMonitorOpenGraphics(qemuMonitorPtr mon, const char *protocol, diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 513788a..2677423 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -3229,17 +3229,25 @@ static int qemuMonitorJSONGetBlockJobInfo(virJSONValuePtr reply, }
-int qemuMonitorJSONBlockJob(qemuMonitorPtr mon, - const char *device, - unsigned long bandwidth, - virDomainBlockJobInfoPtr info, - int mode) +int +qemuMonitorJSONBlockJob(qemuMonitorPtr mon, + const char *device, + const char *base, + unsigned long bandwidth, + virDomainBlockJobInfoPtr info, + int mode) { int ret = -1; virJSONValuePtr cmd = NULL; virJSONValuePtr reply = NULL; const char *cmd_name = NULL;
+ if (base && mode != BLOCK_JOB_PULL) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("only block pull supports base: %s"), base); + return -1; + } + if (mode == BLOCK_JOB_ABORT) { cmd_name = "block_job_cancel"; cmd = qemuMonitorJSONMakeCommand(cmd_name, "s:device", device, NULL); @@ -3254,8 +3262,12 @@ int qemuMonitorJSONBlockJob(qemuMonitorPtr mon, NULL); } else if (mode == BLOCK_JOB_PULL) { cmd_name = "block_stream"; - cmd = qemuMonitorJSONMakeCommand(cmd_name, "s:device", - device, NULL); + if (base) + cmd = qemuMonitorJSONMakeCommand(cmd_name, "s:device", + device, "s:base", base, NULL); + else + cmd = qemuMonitorJSONMakeCommand(cmd_name, "s:device", + device, NULL); }
if (!cmd) diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index d0b3000..e307649 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -1,7 +1,7 @@ /* * qemu_monitor_json.h: interaction with QEMU monitor console * - * Copyright (C) 2006-2009, 2011 Red Hat, Inc. + * Copyright (C) 2006-2009, 2011-2012 Red Hat, Inc. * Copyright (C) 2006 Daniel P. Berrange * * This library is free software; you can redistribute it and/or @@ -246,6 +246,7 @@ int qemuMonitorJSONScreendump(qemuMonitorPtr mon,
int qemuMonitorJSONBlockJob(qemuMonitorPtr mon, const char *device, + const char *base, unsigned long bandwidth, virDomainBlockJobInfoPtr info, int mode);

Now virsh can call virDomainBlockRebase. * tools/virsh.c (cmdBlockPull): Add --base parameter. (blockJobImpl): Use it to expose BlockRebase API. * tools/virsh.pod (blockpull): Document it. --- tools/virsh.c | 19 ++++++++++++++----- tools/virsh.pod | 12 ++++++++---- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index 66ba61c..588c7dd 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -7193,14 +7193,21 @@ blockJobImpl(vshControl *ctl, const vshCmd *cmd, goto cleanup; } - if (mode == VSH_CMD_BLOCK_JOB_ABORT) + if (mode == VSH_CMD_BLOCK_JOB_ABORT) { ret = virDomainBlockJobAbort(dom, path, 0); - else if (mode == VSH_CMD_BLOCK_JOB_INFO) + } else if (mode == VSH_CMD_BLOCK_JOB_INFO) { ret = virDomainGetBlockJobInfo(dom, path, info, 0); - else if (mode == VSH_CMD_BLOCK_JOB_SPEED) + } else if (mode == VSH_CMD_BLOCK_JOB_SPEED) { ret = virDomainBlockJobSetSpeed(dom, path, bandwidth, 0); - else if (mode == VSH_CMD_BLOCK_JOB_PULL) - ret = virDomainBlockPull(dom, path, bandwidth, 0); + } else if (mode == VSH_CMD_BLOCK_JOB_PULL) { + const char *base = NULL; + if (vshCommandOptString(cmd, "base", &base) < 0) + goto cleanup; + if (base) + ret = virDomainBlockRebase(dom, path, base, bandwidth, 0); + else + ret = virDomainBlockPull(dom, path, bandwidth, 0); + } cleanup: if (dom) @@ -7221,6 +7228,8 @@ static const vshCmdOptDef opts_block_pull[] = { {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, {"path", VSH_OT_DATA, VSH_OFLAG_REQ, N_("Fully-qualified path of disk")}, {"bandwidth", VSH_OT_DATA, VSH_OFLAG_NONE, N_("Bandwidth limit in MB/s")}, + {"base", VSH_OT_DATA, VSH_OFLAG_NONE, + N_("path of backing file in chain for a partial pull")}, {NULL, 0, 0, NULL} }; diff --git a/tools/virsh.pod b/tools/virsh.pod index 6730b8b..f497acd 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -575,10 +575,14 @@ currently in use by a running domain. Other contexts that require a MAC address of virtual interface (such as I<detach-interface> or I<domif-setlink>) will accept the MAC address printed by this command. -=item B<blockpull> I<domain> I<path> [I<bandwidth>] - -Populate a disk from its backing image. Once all data from its backing -image has been pulled, the disk no longer depends on the backing image. +=item B<blockpull> I<domain> I<path> [I<bandwidth>] [I<base>] + +Populate a disk from its backing image chain. By default, this command +flattens the entire chain; but if I<base> is specified, containing the +name of one of the backing files in the chain, then that file becomes +the new backing file and only the intermediate portion of the chain is +pulled. Once all requested data from the backing image chain has been +pulled, the disk no longer depends on that portion of the backing chain. It pulls data for the entire disk in the background, the process of the operation can be checked with B<blockjob>. -- 1.7.7.6

On 02/29/2012 03:08 AM, Laine Stump wrote:
On 02/18/2012 12:44 PM, Eric Blake wrote:
Now virsh can call virDomainBlockRebase.
ACK.
Series pushed. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
participants (2)
-
Eric Blake
-
Laine Stump