[libvirt] [PATCH 0/5 v2] Support block device online resizing

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 *disk, unsigned long long size, unsigned int flags) * "@disk" is the absolute source path or device target shorthand of the block device. * The units for "@size" is kilobytes. * "@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 v1: http://www.redhat.com/archives/libvir-list/2011-July/msg01788.html v1 ~ v2: * Nearly just rebasing, with small improvements, nothing new except updating the API definitions to be consistent with commit 3ac26e26. Regards, Osier

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 | 5 ++- src/driver.h | 8 ++++- src/libvirt.c | 68 ++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 1 + 4 files changed, 80 insertions(+), 2 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 0787f18..0ec4959 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -1384,7 +1384,10 @@ int virDomainBlockPeek (virDomainPtr dom, size_t size, void *buffer, unsigned int flags); - +int virDomainBlockResize (virDomainPtr dom, + const char *disk, + unsigned long long size, + unsigned int flags); /** virDomainBlockInfo: * diff --git a/src/driver.h b/src/driver.h index 9e78257..015afc5 100644 --- a/src/driver.h +++ b/src/driver.h @@ -377,7 +377,12 @@ typedef int unsigned long long offset, size_t size, void *buffer, unsigned int flags); - +typedef int + (*virDrvDomainBlockResize) + (virDomainPtr domain, + const char *disk, + unsigned long long size, + unsigned int flags); typedef int (*virDrvDomainMemoryPeek) (virDomainPtr domain, @@ -841,6 +846,7 @@ struct _virDriver { virDrvDomainMigratePrepare domainMigratePrepare; virDrvDomainMigratePerform domainMigratePerform; virDrvDomainMigrateFinish domainMigrateFinish; + virDrvDomainBlockResize domainBlockResize; virDrvDomainBlockStats domainBlockStats; virDrvDomainBlockStatsFlags domainBlockStatsFlags; virDrvDomainInterfaceStats domainInterfaceStats; diff --git a/src/libvirt.c b/src/libvirt.c index b428fe6..7efa4a3 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -7028,6 +7028,74 @@ error: } /** + * virDomainBlockResize: + * @dom: pointer to the domain object + * @disk: path to the block image, or shorthand + * @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. + * + * The @disk parameter is either an unambiguous source name of the + * block device (the <source file='...'/> sub-element, such as + * "/path/to/image"), or (since 0.9.5) the device target shorthand + * (the <target dev='...'/> sub-element, such as "xvda"). Valid names + * can be found by calling virDomainGetXMLDesc() and inspecting + * elements within //domain/devices/disk. + * + * 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 *disk, + unsigned long long size, + unsigned int flags) +{ + virConnectPtr conn; + + VIR_DOMAIN_DEBUG(dom, "disk=%s, size=%llu, flags=%x", disk, 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 (!disk) { + virLibDomainError(VIR_ERR_INVALID_ARG, + _("disk is NULL")); + goto error; + } + + if (conn->driver->domainBlockResize) { + int ret; + ret =conn->driver->domainBlockResize(dom, disk, 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 6ba1526..e78f353 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -502,6 +502,7 @@ LIBVIRT_0.9.8 { global: virConnectIsAlive; virConnectSetKeepAlive; + virDomainBlockResize; } LIBVIRT_0.9.7; # .... define new API here using predicted next version number .... -- 1.7.7.3

On Tue, Nov 29, 2011 at 04:27:32PM +0800, Osier Yang wrote:
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 | 5 ++- src/driver.h | 8 ++++- src/libvirt.c | 68 ++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 1 + 4 files changed, 80 insertions(+), 2 deletions(-)
ACK 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 :|

On 2011年11月29日 17:00, Daniel P. Berrange wrote:
On Tue, Nov 29, 2011 at 04:27:32PM +0800, Osier Yang wrote:
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 | 5 ++- src/driver.h | 8 ++++- src/libvirt.c | 68 ++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 1 + 4 files changed, 80 insertions(+), 2 deletions(-)
ACK
Daniel
Thanks, series pushed. Regards, Osier

--- src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletions(-) diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index cc8f580..4a6da20 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -4552,6 +4552,7 @@ static virDriver remote_driver = { .domainMigratePrepare = remoteDomainMigratePrepare, /* 0.3.2 */ .domainMigratePerform = remoteDomainMigratePerform, /* 0.3.2 */ .domainMigrateFinish = remoteDomainMigrateFinish, /* 0.3.2 */ + .domainBlockResize = remoteDomainBlockResize, /* 0.9.8 */ .domainBlockStats = remoteDomainBlockStats, /* 0.3.2 */ .domainBlockStatsFlags = remoteDomainBlockStatsFlags, /* 0.9.5 */ .domainInterfaceStats = remoteDomainInterfaceStats, /* 0.3.2 */ diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 5ea1114..0d53e7d 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -537,6 +537,13 @@ struct remote_domain_get_memory_parameters_ret { int nparams; }; +struct remote_domain_block_resize_args { + remote_nonnull_domain dom; + remote_nonnull_string disk; + unsigned hyper size; + unsigned int flags; +}; + struct remote_domain_block_stats_args { remote_nonnull_domain dom; remote_nonnull_string path; @@ -2564,7 +2571,8 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_SNAPSHOT_NUM_CHILDREN = 246, /* autogen autogen priority:high */ REMOTE_PROC_DOMAIN_SNAPSHOT_LIST_CHILDREN_NAMES = 247, /* autogen autogen priority:high */ REMOTE_PROC_DOMAIN_EVENT_DISK_CHANGE = 248, /* skipgen skipgen */ - REMOTE_PROC_DOMAIN_OPEN_GRAPHICS = 249 /* skipgen skipgen */ + REMOTE_PROC_DOMAIN_OPEN_GRAPHICS = 249, /* skipgen skipgen */ + REMOTE_PROC_DOMAIN_BLOCK_RESIZE = 250 /* autogen autogen */ /* * Notice how the entries are grouped in sets of 10 ? -- 1.7.7.3

On Tue, Nov 29, 2011 at 04:27:33PM +0800, Osier Yang wrote:
--- src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletions(-)
ACK 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 :|

Implements functions for both HMP and QMP mode. For HMP mode, qemu uses "M" as the units by default, so the passed "sized" is divided by 1024. For 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 | 15 +++++++++++++++ src/qemu/qemu_monitor.h | 5 +++-- src/qemu/qemu_monitor_json.c | 32 ++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 4 +++- src/qemu/qemu_monitor_text.c | 33 +++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 4 +++- 6 files changed, 89 insertions(+), 4 deletions(-) diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 73e5ea9..6423bf7 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -1307,6 +1307,21 @@ 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, device=%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 883e0aa..41b8da2 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -255,8 +255,9 @@ int qemuMonitorGetBlockStatsParamsNumber(qemuMonitorPtr mon, int qemuMonitorGetBlockExtent(qemuMonitorPtr mon, const char *dev_name, unsigned long long *extent); - - +int qemuMonitorBlockResize(qemuMonitorPtr mon, + const char *device, + unsigned long long size); int qemuMonitorSetVNCPassword(qemuMonitorPtr mon, const char *password); int qemuMonitorSetPassword(qemuMonitorPtr mon, diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 56a62db..2ea5e48 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -1775,6 +1775,38 @@ cleanup: return ret; } +/* 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 f10d7d2..d31b32b 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -81,7 +81,9 @@ int qemuMonitorJSONGetBlockStatsParamsNumber(qemuMonitorPtr mon, int qemuMonitorJSONGetBlockExtent(qemuMonitorPtr mon, const char *dev_name, unsigned long long *extent); - +int qemuMonitorJSONBlockResize(qemuMonitorPtr mon, + const char *device, + unsigned long long size); int qemuMonitorJSONSetVNCPassword(qemuMonitorPtr mon, const char *password); diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 5de4d24..728bea8 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -1075,6 +1075,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 f32fce0..cece21c 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -78,7 +78,9 @@ int qemuMonitorTextGetBlockStatsParamsNumber(qemuMonitorPtr mon, int qemuMonitorTextGetBlockExtent(qemuMonitorPtr mon, const char *dev_name, unsigned long long *extent); - +int qemuMonitorTextBlockResize(qemuMonitorPtr mon, + const char *device, + unsigned long long size); int qemuMonitorTextSetVNCPassword(qemuMonitorPtr mon, const char *password); int qemuMonitorTextSetPassword(qemuMonitorPtr mon, -- 1.7.7.3

On Tue, Nov 29, 2011 at 04:27:34PM +0800, Osier Yang wrote:
Implements functions for both HMP and QMP mode.
For HMP mode, qemu uses "M" as the units by default, so the passed "sized" is divided by 1024.
For 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 | 15 +++++++++++++++ src/qemu/qemu_monitor.h | 5 +++-- src/qemu/qemu_monitor_json.c | 32 ++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 4 +++- src/qemu/qemu_monitor_text.c | 33 +++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 4 +++- 6 files changed, 89 insertions(+), 4 deletions(-)
ACK 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 :|

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. 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 | 91 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 91 insertions(+), 0 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 6cfdd1d..697182d 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -7055,6 +7055,96 @@ 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't 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; + virDomainDiskDefPtr disk = NULL; + + virCheckFlags(0, -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; + } + + if ((i = virDomainDiskIndexByName(vm->def, path, false)) < 0) { + qemuReportError(VIR_ERR_INVALID_ARG, + _("invalid path: %s"), path); + goto cleanup; + } + disk = vm->def->disks[i]; + + if (virAsprintf(&device, "%s%s", QEMU_DRIVE_HOST_PREFIX, + disk->info.alias) < 0) { + virReportOOMError(); + goto endjob; + } + + 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. @@ -10848,6 +10938,7 @@ static virDriver qemuDriver = { .domainSetSchedulerParameters = qemuSetSchedulerParameters, /* 0.7.0 */ .domainSetSchedulerParametersFlags = qemuSetSchedulerParametersFlags, /* 0.9.2 */ .domainMigratePerform = qemudDomainMigratePerform, /* 0.5.0 */ + .domainBlockResize = qemuDomainBlockResize, /* 0.9.8 */ .domainBlockStats = qemuDomainBlockStats, /* 0.4.1 */ .domainBlockStatsFlags = qemuDomainBlockStatsFlags, /* 0.9.5 */ .domainInterfaceStats = qemudDomainInterfaceStats, /* 0.4.1 */ -- 1.7.7.3

On Tue, Nov 29, 2011 at 04:27:35PM +0800, Osier Yang wrote:
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. 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 | 91 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 91 insertions(+), 0 deletions(-)
ACK 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 :|

--- tools/virsh.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 6 +++++ 2 files changed, 64 insertions(+), 0 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index 6ed249b..27ecaf3 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -6028,6 +6028,63 @@ cmdBlockJob(vshControl *ctl, const vshCmd *cmd) return true; } +/* + * "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 source path or device " + "target shorthand of the 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; +} /* * "net-autostart" command @@ -14698,6 +14755,7 @@ static const vshCmdDef domManagementCmds[] = { {"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}, + {"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 db872dd..a5758f4 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -583,6 +583,12 @@ If I<--info> is specified, the active job information on the specified disk will be printed. I<bandwidth> can be used to set bandwidth limit for the active job. +=item B<blockresize> I<domain> I<--path> I<--size> + +Resize a block device of domain while the domain is running, I<--path> +specifies fully-qualified source path or device target shorthand of +the block device, I<--size> specifies the new size in kilobytes. + =item B<dominfo> I<domain-id> Returns basic information about the domain. -- 1.7.7.3

On Tue, Nov 29, 2011 at 04:27:36PM +0800, Osier Yang wrote:
--- tools/virsh.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 6 +++++ 2 files changed, 64 insertions(+), 0 deletions(-)
ACK 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 (2)
-
Daniel P. Berrange
-
Osier Yang