[libvirt] [RFC PATCH 0/5] Support online resizing of block devices.

This patch series introduce new API "virDomainBlockResize" to expose qemu monitor command "block_size", which is for resizing the a block device while the domain is running. The prototype for the new API is: int virDomainBlockResize (virDomainPtr dom, const char *path, unsigned long long size, unsigned int flags) * "@path" is the absolute path of the block device, which can be extraced from domain xml. * The units for "@size" is kilobytes, which might be not quite properly. (qemu HMP uses Megabytes as the default units, QMP uses Bytes as the default units, so it means we need to divice "@size" by 1024 for HMP, and multiply "@size" by 1024 for QMP. On the other hand, we need to check the overflowing). Any ideas on this is welcomed. * "@flags" is unused currently. [PATCH 1/5] block_resize: Define the new API [PATCH 2/5] block_resize: Wire up the remote protocol [PATCH 3/5] block_resize: Implement qemu monitor functions [PATCH 4/5] block_resize: Implement qemu driver method [PATCH 5/5] block_resize: Expose the new API to virsh

The new API is named as "virDomainBlockResize", intending to add support for qemu monitor command "block_resize" (both HMP and QMP). Similar with APIs like "virDomainSetMemoryFlags", the units for argument "size" is kilobytes. --- include/libvirt/libvirt.h.in | 4 ++ python/generator.py | 1 + src/driver.h | 7 ++++ src/libvirt.c | 68 ++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 5 +++ 5 files changed, 85 insertions(+), 0 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 5771ba7..0fd20b6 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -1180,6 +1180,10 @@ int virDomainBlockPeek (virDomainPtr dom, size_t size, void *buffer, unsigned int flags); +int virDomainBlockResize (virDomainPtr dom, + const char *path, + unsigned long long size, + unsigned int flags); /** virDomainBlockInfo: diff --git a/python/generator.py b/python/generator.py index d0d3ae6..28c15c1 100755 --- a/python/generator.py +++ b/python/generator.py @@ -370,6 +370,7 @@ skip_impl = ( 'virNodeGetCPUStats', 'virNodeGetMemoryStats', 'virDomainGetBlockJobInfo', + 'virDomainBlockResize', ) diff --git a/src/driver.h b/src/driver.h index 5136fb5..ad6b541 100644 --- a/src/driver.h +++ b/src/driver.h @@ -366,6 +366,12 @@ typedef int unsigned long long offset, size_t size, void *buffer, unsigned int flags); +typedef int + (*virDrvDomainBlockResize) + (virDomainPtr domain, + const char *path, + unsigned long long size, + unsigned int flags); typedef int (*virDrvDomainMemoryPeek) @@ -799,6 +805,7 @@ struct _virDriver { virDrvDomainMigratePrepare domainMigratePrepare; virDrvDomainMigratePerform domainMigratePerform; virDrvDomainMigrateFinish domainMigrateFinish; + virDrvDomainBlockResize domainBlockResize; virDrvDomainBlockStats domainBlockStats; virDrvDomainInterfaceStats domainInterfaceStats; virDrvDomainMemoryStats domainMemoryStats; diff --git a/src/libvirt.c b/src/libvirt.c index 5ff8d89..3deafd1 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -6533,6 +6533,74 @@ error: } /** + * virDomainBlockResize: + * @dom: pointer to the domain object + * @path: path to the block image + * @size: new size of the block image in kilobytes + * @flags: unused, always pass 0 + * + * Note that this call may fail if the underlying virtualization hypervisor + * does not support it. And this call requires privileged access to the + * hypervisor. + * + * 'path' must be a device or file corresponding to the domain. + * In other words it must be the precise string returned in + * a <disk><source dev='...'/></disk> from + * virDomainGetXMLDesc. + * + * Resize a block device of domain while the domain is running. + * + * Returns: 0 in case of success or -1 in case of failure. + */ + +int +virDomainBlockResize (virDomainPtr dom, + const char *path, + unsigned long long size, + unsigned int flags) +{ + virConnectPtr conn; + + VIR_DOMAIN_DEBUG(dom, "path=%s, size=%llu, flags=%x", + path, size, flags); + + virResetLastError(); + + if (!VIR_IS_CONNECTED_DOMAIN (dom)) { + virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + conn = dom->conn; + + if (dom->conn->flags & VIR_CONNECT_RO) { + virLibDomainError(VIR_ERR_OPERATION_DENIED, __FUNCTION__); + goto error; + } + + if (!path) { + virLibDomainError(VIR_ERR_INVALID_ARG, + _("path is NULL")); + goto error; + } + + if (conn->driver->domainBlockResize) { + int ret; + ret =conn->driver->domainBlockResize(dom, path, size, flags); + if (ret < 0) + goto error; + return ret; + } + + virLibDomainError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(dom->conn); + return -1; +} + + +/** * virDomainMemoryPeek: * @dom: pointer to the domain object * @start: start of memory to peek diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index c2b6666..448209d 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -480,4 +480,9 @@ LIBVIRT_0.9.4 { virDomainBlockPull; } LIBVIRT_0.9.3; +LIBVIRT_0.9.5 { + global: + virDomainBlockResize; +} LIBVIRT_0.9.4; + # .... define new API here using predicted next version number .... -- 1.7.6

--- src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 10 +++++++++- src/remote_protocol-structs | 7 +++++++ 3 files changed, 17 insertions(+), 1 deletions(-) diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 0652e0d..abb9015 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -4286,6 +4286,7 @@ static virDriver remote_driver = { .domainMigratePrepare = remoteDomainMigratePrepare, /* 0.3.2 */ .domainMigratePerform = remoteDomainMigratePerform, /* 0.3.2 */ .domainMigrateFinish = remoteDomainMigrateFinish, /* 0.3.2 */ + .domainBlockResize = remoteDomainBlockResize, /* 0.9.5 */ .domainBlockStats = remoteDomainBlockStats, /* 0.3.2 */ .domainInterfaceStats = remoteDomainInterfaceStats, /* 0.3.2 */ .domainMemoryStats = remoteDomainMemoryStats, /* 0.7.5 */ diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 8f68808..cd98e25 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -587,6 +587,13 @@ struct remote_domain_block_peek_ret { opaque buffer<REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX>; }; +struct remote_domain_block_resize_args { + remote_nonnull_domain dom; + remote_nonnull_string path; + unsigned hyper size; + unsigned int flags; +}; + struct remote_domain_memory_peek_args { remote_nonnull_domain dom; unsigned hyper offset; @@ -2475,7 +2482,8 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_BLOCK_JOB_SET_SPEED = 239, /* autogen autogen */ REMOTE_PROC_DOMAIN_BLOCK_PULL = 240, /* autogen autogen */ - REMOTE_PROC_DOMAIN_EVENT_BLOCK_JOB = 241 /* skipgen skipgen */ + REMOTE_PROC_DOMAIN_EVENT_BLOCK_JOB = 241, /* skipgen skipgen */ + REMOTE_PROC_DOMAIN_BLOCK_RESIZE = 242 /* autogen autogen */ /* * Notice how the entries are grouped in sets of 10 ? diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 91b3ca5..af3046a 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -315,6 +315,12 @@ struct remote_domain_block_peek_ret { char * buffer_val; } buffer; }; +struct remote_domain_block_resize_args { + remote_nonnull_domain dom; + remote_nonnull_string path; + uint64_t size; + u_int flags; +} struct remote_domain_memory_peek_args { remote_nonnull_domain dom; uint64_t offset; @@ -1936,4 +1942,5 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_BLOCK_JOB_SET_SPEED = 239, REMOTE_PROC_DOMAIN_BLOCK_PULL = 240, REMOTE_PROC_DOMAIN_EVENT_BLOCK_JOB = 241, + REMOTE_PROC_DOMAIN_BLOCK_RESIZE = 242, }; -- 1.7.6

Implements functions for both HMP and QMP mode. (command "block_resize" is supported by qemu in both HMP and QMP mode). In HMP mode, qemu uses "M" as the units by default, so the passed "sized" is divided by 1024. In QMP mode, qemu uses "Bytes" as the units by default, the passed "sized" is multiplied by 1024. All of the monitor functions return -1 on failure, 0 on success, or -2 if not supported. --- src/qemu/qemu_monitor.c | 16 ++++++++++++++++ src/qemu/qemu_monitor.h | 3 +++ src/qemu/qemu_monitor_json.c | 33 +++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 3 +++ src/qemu/qemu_monitor_text.c | 33 +++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 3 +++ 6 files changed, 91 insertions(+), 0 deletions(-) diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index db6107c..26302f2 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -1243,6 +1243,22 @@ int qemuMonitorGetBlockExtent(qemuMonitorPtr mon, return ret; } +int qemuMonitorBlockResize(qemuMonitorPtr mon, + const char *device, + unsigned long long size) +{ + int ret; + VIR_DEBUG("mon=%p, fd=%d, devname=%p size=%llu", + mon, mon->fd, device, size); + + if (mon->json) + ret = qemuMonitorJSONBlockResize(mon, device, size); + else + ret = qemuMonitorTextBlockResize(mon, device, size); + + return ret; +} + int qemuMonitorSetVNCPassword(qemuMonitorPtr mon, const char *password) diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index f241c9e..ba63550 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -220,6 +220,9 @@ int qemuMonitorGetBlockExtent(qemuMonitorPtr mon, const char *devname, unsigned long long *extent); +int qemuMonitorBlockResize(qemuMonitorPtr mon, + const char *devname, + unsigned long long size); int qemuMonitorSetVNCPassword(qemuMonitorPtr mon, const char *password); diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index b7a6a12..4e519e5 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -1520,6 +1520,39 @@ cleanup: } +/* Return 0 on success, -1 on failure, or -2 if not supported. */ +int qemuMonitorJSONBlockResize(qemuMonitorPtr mon, + const char *device, + unsigned long long size) +{ + int ret; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + + cmd = qemuMonitorJSONMakeCommand("block_resize", + "s:device", device, + "U:size", size * 1024, + NULL); + if (!cmd) + return -1; + + ret = qemuMonitorJSONCommand(mon, cmd, &reply); + + if (ret == 0) { + if (qemuMonitorJSONHasError(reply, "CommandNotFound")) { + ret = -2; + goto cleanup; + } + + ret = qemuMonitorJSONCheckError(cmd, reply); + } + +cleanup: + virJSONValueFree(cmd); + virJSONValueFree(reply); + return ret; +} + int qemuMonitorJSONSetVNCPassword(qemuMonitorPtr mon, const char *password) { diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 9512793..8f511a3 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -70,6 +70,9 @@ int qemuMonitorJSONGetBlockStatsInfo(qemuMonitorPtr mon, int qemuMonitorJSONGetBlockExtent(qemuMonitorPtr mon, const char *devname, unsigned long long *extent); +int qemuMonitorJSONBlockResize(qemuMonitorPtr mon, + const char *devce, + unsigned long long size); int qemuMonitorJSONSetVNCPassword(qemuMonitorPtr mon, diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 84941f9..f0e1a12 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -786,6 +786,39 @@ int qemuMonitorTextGetBlockExtent(qemuMonitorPtr mon ATTRIBUTE_UNUSED, return -1; } +/* Return 0 on success, -1 on failure, or -2 if not supported. */ +int qemuMonitorTextBlockResize(qemuMonitorPtr mon, + const char *device, + unsigned long long size) +{ + char *cmd = NULL; + char *reply = NULL; + int ret = -1; + + if (virAsprintf(&cmd, "block_resize %s %llu", + device, VIR_DIV_UP(size, 1024)) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (qemuMonitorHMPCommand(mon, cmd, &reply) < 0) { + qemuReportError(VIR_ERR_OPERATION_FAILED, + "%s", _("failed to resize block")); + goto cleanup; + } + + if (strstr(reply, "unknown command:")) { + ret = -2; + goto cleanup; + } + + ret = 0; + +cleanup: + VIR_FREE(cmd); + VIR_FREE(reply); + return ret; +} static int qemuMonitorSendVNCPassphrase(qemuMonitorPtr mon ATTRIBUTE_UNUSED, diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index b250738..0c2f916 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -67,6 +67,9 @@ int qemuMonitorTextGetBlockStatsInfo(qemuMonitorPtr mon, int qemuMonitorTextGetBlockExtent(qemuMonitorPtr mon, const char *devname, unsigned long long *extent); +int qemuMonitorTextBlockResize(qemuMonitorPtr mon, + const char *device, + unsigned long long size); int qemuMonitorTextSetVNCPassword(qemuMonitorPtr mon, const char *password); -- 1.7.6

It requires the domain is running, otherwise fails. Resize to a lower size is supported, but should be used with extreme caution. In order to prohibit the "size" overflowing after multiplied by 1024. We do checking in the codes. This might be not quite properly, as for QMP mode, the default units is Bytes, the passed size needs to be multiplied by 1024, however, for HMP mode, the default units is "Megabytes", the passed "size" needs to be divided by 1024 then. --- src/qemu/qemu_driver.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 98 insertions(+), 0 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 5df58b1..6ee24b7 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -6513,6 +6513,103 @@ qemuGetSchedulerParameters(virDomainPtr dom, VIR_DOMAIN_AFFECT_CURRENT); } +/** + * Resize a block device while a guest is running. Resize to a lower size + * is supported, but should be used with extreme caution. Note that it + * only supports to resize image files, it can not resize block devices + * like LVM volumes. + */ +static int +qemuDomainBlockResize (virDomainPtr dom, + const char *path, + unsigned long long size, + unsigned int flags) +{ + struct qemud_driver *driver = dom->conn->privateData; + virDomainObjPtr vm; + qemuDomainObjPrivatePtr priv; + int ret = -1, i; + char *device = NULL; + bool found = false; + + virCheckFlags(0, -1); + + if (path[0] == '\0') { + qemuReportError(VIR_ERR_INVALID_ARG, + "%s", _("empty path")); + return -1; + } + + if (size > ULLONG_MAX / 1024) { + qemuReportError(VIR_ERR_INVALID_ARG, + _("size must be less than %llu"), + ULLONG_MAX / 1024); + return -1; + } + + qemuDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + qemuDriverUnlock(driver); + + if (!vm) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(dom->uuid, uuidstr); + qemuReportError(VIR_ERR_NO_DOMAIN, + _("no domain matching uuid '%s'"), uuidstr); + goto cleanup; + } + + priv = vm->privateData; + + if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0) + goto cleanup; + + if (!virDomainObjIsActive(vm)) { + qemuReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("domain is not running")); + goto endjob; + } + + for (i = 0 ; i < vm->def->ndisks ; i++) { + if (vm->def->disks[i]->src != NULL && + STREQ (vm->def->disks[i]->src, path)) { + found = true; + break; + } + } + + if (!found) { + qemuReportError(VIR_ERR_INVALID_ARG, + _("no domain disk matching path '%s'"), path); + goto endjob; + } + + if (virAsprintf(&device, "%s%s", QEMU_DRIVE_HOST_PREFIX, + vm->def->disks[i]->info.alias) < 0) { + virReportOOMError(); + goto endjob; + } + + ignore_value(qemuDomainObjEnterMonitor(driver, vm)); + if (qemuMonitorBlockResize(priv->mon, device, size) < 0) { + qemuDomainObjExitMonitor(driver, vm); + goto endjob; + } + qemuDomainObjExitMonitor(driver, vm); + + ret = 0; + +endjob: + if (qemuDomainObjEndJob(driver, vm) == 0) + vm = NULL; + +cleanup: + VIR_FREE(device); + if (vm) + virDomainObjUnlock(vm); + return ret; +} + /* This uses the 'info blockstats' monitor command which was * integrated into both qemu & kvm in late 2007. If the command is * not supported we detect this and return the appropriate error. @@ -9189,6 +9286,7 @@ static virDriver qemuDriver = { .domainSetSchedulerParameters = qemuSetSchedulerParameters, /* 0.7.0 */ .domainSetSchedulerParametersFlags = qemuSetSchedulerParametersFlags, /* 0.9.2 */ .domainMigratePerform = qemudDomainMigratePerform, /* 0.5.0 */ + .domainBlockResize = qemuDomainBlockResize, /* 0.9.5 */ .domainBlockStats = qemudDomainBlockStats, /* 0.4.1 */ .domainInterfaceStats = qemudDomainInterfaceStats, /* 0.4.1 */ .domainMemoryStats = qemudDomainMemoryStats, /* 0.7.5 */ -- 1.7.6

The units for "size" is kilobytes, "path" is the absolute path of the disk image, which can be extract from the disk XML. E.g. (<disk><source file='$path'/><disk>). --- tools/virsh.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- tools/virsh.pod | 8 +++++++ 2 files changed, 68 insertions(+), 1 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index 21c3124..02719fb 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -5229,6 +5229,64 @@ cmdBlockPull(vshControl *ctl, const vshCmd *cmd) } /* + * "blockresize" command + */ +static const vshCmdInfo info_block_resize[] = { + {"help", N_("Resize block device of domain.")}, + {"desc", N_("Resize block device of domain.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_block_resize[] = { + {"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 block device")}, + {"size", VSH_OT_INT, VSH_OFLAG_REQ, N_("New size of the block device in kilobytes, " + "the size must be integer")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdBlockResize(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + const char *path = NULL; + unsigned long long size = 0; + unsigned int flags = 0; + int ret = false; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (vshCommandOptString(cmd, "path", (const char **) &path) < 0) { + vshError(ctl, "%s", _("Path must not be empty")); + return false; + } + + if (vshCommandOptULongLong(cmd, "size", &size) < 0) { + vshError(ctl, "%s", _("Unable to parse integer")); + return false; + } + + if (size > ULLONG_MAX / 1024) { + vshError(ctl, _("Size must be less than %llu"), ULLONG_MAX / 1024); + return false; + } + + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) + return false; + + if (virDomainBlockResize(dom, path, size, flags) < 0) { + vshError(ctl, _("Failed to resize block device '%s'"), path); + } else { + vshPrint(ctl, _("Block device '%s' is resized"), path); + ret = true; + } + + virDomainFree(dom); + return ret; +} + +/* * "blockjobinfo" command */ static const vshCmdInfo info_block_job[] = { @@ -12434,8 +12492,9 @@ static const vshCmdDef domManagementCmds[] = { info_attach_interface, 0}, {"autostart", cmdAutostart, opts_autostart, info_autostart, 0}, {"blkiotune", cmdBlkiotune, opts_blkiotune, info_blkiotune, 0}, - {"blockpull", cmdBlockPull, opts_block_pull, info_block_pull, 0}, {"blockjob", cmdBlockJob, opts_block_job, info_block_job, 0}, + {"blockpull", cmdBlockPull, opts_block_pull, info_block_pull, 0}, + {"blockresize", cmdBlockResize, opts_block_resize, info_block_resize, 0}, #ifndef WIN32 {"console", cmdConsole, opts_console, info_console, 0}, #endif diff --git a/tools/virsh.pod b/tools/virsh.pod index 93ae50a..9aebca7 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -414,6 +414,14 @@ the B<shutdown> command instead. However, this does not delete any storage volumes used by the guest, and if the domain is persistent, it can be restarted later. +=item B<blockresize> I<domain> I<--path> I<--size> + +Resize a block device of domain while the domain is running, I<--path> +specifies the absolute path of the block device, I<--size> specifies the +new size in kilobytes + +The I<--managed-save> flag guarantees that any managed save image(see + =item B<domblkstat> I<domain> I<block-device> Get device block stats for a running domain. -- 1.7.6

On 07/25/2011 11:51 PM, Osier Yang wrote:
This patch series introduce new API "virDomainBlockResize" to expose qemu monitor command "block_size", which is for resizing the a block device while the domain is running.
The prototype for the new API is:
int virDomainBlockResize (virDomainPtr dom, const char *path, unsigned long long size, unsigned int flags)
Sounds nice, but it missed the rc1 freeze. This will have to wait for 0.9.5. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

On 07/25/2011 11:51 PM, Osier Yang wrote:
This patch series introduce new API "virDomainBlockResize" to expose qemu monitor command "block_size", which is for resizing the a block device while the domain is running.
The prototype for the new API is:
int virDomainBlockResize (virDomainPtr dom, const char *path, unsigned long long size, unsigned int flags)
While looking through old mails, I noticed this had never been applied. Is it something you could revive and rebase to the latest libvirt.git? -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On Mon, Nov 28, 2011 at 02:24:52PM -0700, Eric Blake wrote:
On 07/25/2011 11:51 PM, Osier Yang wrote:
This patch series introduce new API "virDomainBlockResize" to expose qemu monitor command "block_size", which is for resizing the a block device while the domain is running.
The prototype for the new API is:
int virDomainBlockResize (virDomainPtr dom, const char *path, unsigned long long size, unsigned int flags)
While looking through old mails, I noticed this had never been applied. Is it something you could revive and rebase to the latest libvirt.git?
IIRC, at the time the blocker was a question mark over the impl of the underlying QEMU command. We have since resolved the QEMU issue, so there's no reason not to apply this now. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
participants (3)
-
Daniel P. Berrange
-
Eric Blake
-
Osier Yang