[libvirt] [PATCH 0/6] Support online block resizing

Upstream QEMU introduced online block resizing to resize the block device when domain is running since commit 6d4a2b3a4795. It simply reuses existing "bdrv_truncate" method which is used by "qemu-img" to resize the images. This means it supports to resize all the format that "qemu-img resize" supports. E.g. qcow2, raw, qed, qcow, etc. (NB, it doesn't support to shrink size of qcow2 image, and QEMU reports "An undefined error has ocurred" in this case). For block device of virtio bus, the guest can update the device size automatically, needs kernel support, since kernel-2.6.32-117: http://patchwork.usersys.redhat.com/patch/33040/ For block device of SCSI bus, one needs to execute command like below in the guest (linux) to update the size: % echo > /sys/class/scsi_device/0:0:0:0/device/rescan For block device of IDE bus, seems there is no way to let guest update the size after resizing. The new API is defined as: int virDomainBlockResize (virDomainPtr dom, const char *device, unsigned long long size, unsigned int flags) * @device is the name of block device, E.g. vda, vdb. * Units for @size is KB. [PATCH 1/6] block_resize: Define the new API [PATCH 2/6] block_resize: Implemente the public API [PATCH 3/6] block_resize: Wire up the remote protocol [PATCH 4/6] block_resize: Implemente the qemu monitor functions [PATCH 5/6] block_resize: Implemente the internal API for qemu [PATCH 6/6] block_resize: Expose the new API in virsh Regards, Osier

--- include/libvirt/libvirt.h.in | 4 ++++ src/driver.h | 7 +++++++ src/libvirt_public.syms | 5 +++++ 3 files changed, 16 insertions(+), 0 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index c51a5b9..bec470b 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -1184,6 +1184,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/src/driver.h b/src/driver.h index 80d6628..86cbbc5 100644 --- a/src/driver.h +++ b/src/driver.h @@ -367,6 +367,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) @@ -800,6 +806,7 @@ struct _virDriver { virDrvDomainMigratePrepare domainMigratePrepare; virDrvDomainMigratePerform domainMigratePerform; virDrvDomainMigrateFinish domainMigrateFinish; + virDrvDomainBlockResize domainBlockResize; virDrvDomainBlockStats domainBlockStats; virDrvDomainInterfaceStats domainInterfaceStats; virDrvDomainMemoryStats domainMemoryStats; 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/libvirt.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 67 insertions(+), 0 deletions(-) diff --git a/src/libvirt.c b/src/libvirt.c index e4a21b6..a9b4b3c 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -6620,6 +6620,73 @@ error: } /** + * virDomainBlockResize: + * @dom: pointer to the domain object + * @devname: name of the block device + * @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. + * + * @devname is the name of the block device. Get this by calling + * virDomainGetXMLDesc and finding the <target dev='...'> + * attribute within //domain/devices/disk. (For example, "xvda"). + * + * 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 *devname, + unsigned long long size, + unsigned int flags) +{ + virConnectPtr conn; + + VIR_DOMAIN_DEBUG(dom, "devname=%s, size=%llu, flags=%x", + devname, 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 (!devname) { + virLibDomainError(VIR_ERR_INVALID_ARG, + _("devname is NULL")); + goto error; + } + + if (conn->driver->domainBlockResize) { + int ret; + ret =conn->driver->domainBlockResize(dom, devname, 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 -- 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 603d589..e01a655 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -4306,6 +4306,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 715b26e..7098b5c 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 f37c98c..7fff906 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -820,6 +820,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 | 103 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 103 insertions(+), 0 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 4e8c691..061f7ea 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -6767,6 +6767,108 @@ 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 *devname, + 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 (devname[0] == '\0') { + qemuReportError(VIR_ERR_INVALID_ARG, + "%s", _("empty devname")); + 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 (STREQ(devname, vm->def->disks[i]->dst)) { + disk = vm->def->disks[i]; + break; + } + } + + if (!disk) { + qemuReportError(VIR_ERR_INVALID_ARG, + _("no domain disk matching name: %s"), devname); + goto cleanup; + } + + if (!disk->info.alias) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("missing disk device alias name for %s"), disk->dst); + goto cleanup; + } + + 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. @@ -9500,6 +9602,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

Add new command "block_resize": * Units for option "size" is KB. * "--device" is used to specify the device name. E.g. vda, vdb. --- 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 49034ae..fcd1be6 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -5269,6 +5269,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")}, + {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("device name 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 *device = NULL; + unsigned long long size = 0; + unsigned int flags = 0; + int ret = false; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (vshCommandOptString(cmd, "device", (const char **) &device) < 0) { + vshError(ctl, "%s", _("Device 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, device, size, flags) < 0) { + vshError(ctl, _("Failed to resize block device '%s'"), device); + } else { + vshPrint(ctl, _("Block device '%s' is resized"), device); + ret = true; + } + + virDomainFree(dom); + return ret; +} + +/* * "blockjobinfo" command */ static const vshCmdInfo info_block_job[] = { @@ -12537,8 +12595,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 2cd0f73..fb41063 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -419,6 +419,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 Wed, Aug 31, 2011 at 09:31:58PM +0800, Osier Yang wrote:
Upstream QEMU introduced online block resizing to resize the block device when domain is running since commit 6d4a2b3a4795. It simply reuses existing "bdrv_truncate" method which is used by "qemu-img" to resize the images. This means it supports to resize all the format that "qemu-img resize" supports. E.g. qcow2, raw, qed, qcow, etc. (NB, it doesn't support to shrink size of qcow2 image, and QEMU reports "An undefined error has ocurred" in this case).
For block device of virtio bus, the guest can update the device size automatically, needs kernel support, since kernel-2.6.32-117:
http://patchwork.usersys.redhat.com/patch/33040/
For block device of SCSI bus, one needs to execute command like below in the guest (linux) to update the size:
% echo > /sys/class/scsi_device/0:0:0:0/device/rescan
For block device of IDE bus, seems there is no way to let guest update the size after resizing.
Your API proprosal looks reasonable, but unfortunately the QEMU command 'block_resize' is either broken, or incomplete since it does not have a way to notify the guest that a block device has been resized, independantly of actually resizing the host file. This is required in order for guest disk resize to work on LVM, SCSI, iSCSI, etc block devices, since QEMU cannot itself do a resize of the block devices. The resize has to be done either by libvirt using host commands, or by the SAN administrator on the remote storage appliance. IMHO, we should not commit to the libvirt API design, until we can get confirmation from QEMU about whether they will fix the block_resize command to work for block devices, or add a new command for just notifying guests of external block device resizes Regards, 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 Thu, Sep 01, 2011 at 02:14:23PM +0100, Daniel P. Berrange wrote:
On Wed, Aug 31, 2011 at 09:31:58PM +0800, Osier Yang wrote:
Upstream QEMU introduced online block resizing to resize the block device when domain is running since commit 6d4a2b3a4795. It simply reuses existing "bdrv_truncate" method which is used by "qemu-img" to resize the images. This means it supports to resize all the format that "qemu-img resize" supports. E.g. qcow2, raw, qed, qcow, etc. (NB, it doesn't support to shrink size of qcow2 image, and QEMU reports "An undefined error has ocurred" in this case).
For block device of virtio bus, the guest can update the device size automatically, needs kernel support, since kernel-2.6.32-117:
http://patchwork.usersys.redhat.com/patch/33040/
For block device of SCSI bus, one needs to execute command like below in the guest (linux) to update the size:
% echo > /sys/class/scsi_device/0:0:0:0/device/rescan
For block device of IDE bus, seems there is no way to let guest update the size after resizing.
Your API proprosal looks reasonable, but unfortunately the QEMU command 'block_resize' is either broken, or incomplete since it does not have a way to notify the guest that a block device has been resized, independantly of actually resizing the host file. This is required in order for guest disk resize to work on LVM, SCSI, iSCSI, etc block devices, since QEMU cannot itself do a resize of the block devices. The resize has to be done either by libvirt using host commands, or by the SAN administrator on the remote storage appliance.
IMHO, we should not commit to the libvirt API design, until we can get confirmation from QEMU about whether they will fix the block_resize command to work for block devices, or add a new command for just notifying guests of external block device resizes
See this thread... http://lists.nongnu.org/archive/html/qemu-devel/2011-09/msg00068.html 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 :|

于 2011年09月01日 21:37, Daniel P. Berrange 写道:
On Thu, Sep 01, 2011 at 02:14:23PM +0100, Daniel P. Berrange wrote:
Upstream QEMU introduced online block resizing to resize the block device when domain is running since commit 6d4a2b3a4795. It simply reuses existing "bdrv_truncate" method which is used by "qemu-img" to resize the images. This means it supports to resize all the format that "qemu-img resize" supports. E.g. qcow2, raw, qed, qcow, etc. (NB, it doesn't support to shrink size of qcow2 image, and QEMU reports "An undefined error has ocurred" in this case).
For block device of virtio bus, the guest can update the device size automatically, needs kernel support, since kernel-2.6.32-117:
http://patchwork.usersys.redhat.com/patch/33040/
For block device of SCSI bus, one needs to execute command like below in the guest (linux) to update the size:
% echo> /sys/class/scsi_device/0:0:0:0/device/rescan
For block device of IDE bus, seems there is no way to let guest update the size after resizing. Your API proprosal looks reasonable, but unfortunately the QEMU command 'block_resize' is either broken, or incomplete since it does not have a way to notify the guest that a block device has been resized, independantly of actually resizing the host file. This is required in order for guest disk resize to work on LVM, SCSI, iSCSI, etc block devices, since QEMU cannot itself do a resize of the block devices. The resize has to be done either by libvirt using host commands, or by the SAN administrator on
On Wed, Aug 31, 2011 at 09:31:58PM +0800, Osier Yang wrote: the remote storage appliance.
IMHO, we should not commit to the libvirt API design, until we can get confirmation from QEMU about whether they will fix the block_resize command to work for block devices, or add a new command for just notifying guests of external block device resizes See this thread...
http://lists.nongnu.org/archive/html/qemu-devel/2011-09/msg00068.html
Daniel
Thanks for clarifying the requirement to QEMU guys, Daniel. Osier
participants (2)
-
Daniel P. Berrange
-
Osier Yang