[PATCH v2 0/3] qemu: Add infrastructure to prevent accidental disk shrink via 'virDomainBlockResize' (part 1)
Shrinking a disk accidentally equals data loss and thus very bad time for anyone mis-typing. This series adds a new flag to virDomainBlockResize to prevent such a thing if the user only intends to extend the disk. v2: - extracted only the first part of the series adding the flag preventing shrink and exposing it - the second part dealing with detecting if the flag is supported will be posted later along with a better approach to probe flags Peter Krempa (3): virDomainBlockResizeFlags: Convert to prefix-style docs API/qemu: Introduce 'VIR_DOMAIN_BLOCK_RESIZE_EXTEND' for 'virDomainBlockResize' virsh: blockresize: Introduce '--extend' flag docs/manpages/virsh.rst | 7 ++++++- include/libvirt/libvirt-domain.h | 10 ++++++++-- src/libvirt-domain.c | 5 +++++ src/qemu/qemu_driver.c | 32 +++++++++++++++++++++++++++++++- tools/virsh-domain.c | 7 +++++++ 5 files changed, 57 insertions(+), 4 deletions(-) -- 2.53.0
From: Peter Krempa <pkrempa@redhat.com> Upcoming patches will want to add more extensive docs for one of the new flags so this format will make it more readable. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- include/libvirt/libvirt-domain.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index 09a797cab6..084debbf21 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -2346,8 +2346,11 @@ int virDomainBlockPeek (virDomainPtr dom, * Since: 0.9.11 */ typedef enum { - VIR_DOMAIN_BLOCK_RESIZE_BYTES = 1 << 0, /* size in bytes instead of KiB (Since: 0.9.11) */ - VIR_DOMAIN_BLOCK_RESIZE_CAPACITY = 1 << 1, /* resize to full the capacity of the source (Since: 10.0.0) */ + /* size in bytes instead of KiB (Since: 0.9.11) */ + VIR_DOMAIN_BLOCK_RESIZE_BYTES = 1 << 0, + + /* resize to full the capacity of the source (Since: 10.0.0) */ + VIR_DOMAIN_BLOCK_RESIZE_CAPACITY = 1 << 1, } virDomainBlockResizeFlags; int virDomainBlockResize (virDomainPtr dom, -- 2.53.0
From: Peter Krempa <pkrempa@redhat.com> Introduce a new flag VIR_DOMAIN_BLOCK_RESIZE_EXTEND which will prevent accidental shrinking of the block device. Warn callers that they ought to use it. While this won't prevent any old uses without the flag (which we couldn't change due to our API guarantees) it will give the users tools to handle the resizing of devices more safely. Implement it in the qemu driver. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- include/libvirt/libvirt-domain.h | 3 +++ src/libvirt-domain.c | 5 +++++ src/qemu/qemu_driver.c | 32 +++++++++++++++++++++++++++++++- 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index 084debbf21..4a8e3114b3 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -2351,6 +2351,9 @@ typedef enum { /* resize to full the capacity of the source (Since: 10.0.0) */ VIR_DOMAIN_BLOCK_RESIZE_CAPACITY = 1 << 1, + + /* Disallow shrinking (Since: 12.3.0) */ + VIR_DOMAIN_BLOCK_RESIZE_EXTEND = 1 << 2, } virDomainBlockResizeFlags; int virDomainBlockResize (virDomainPtr dom, diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c index ed51180c91..db9eea5774 100644 --- a/src/libvirt-domain.c +++ b/src/libvirt-domain.c @@ -6451,6 +6451,11 @@ virDomainBlockPeek(virDomainPtr dom, * size. Depending on the file format, the hypervisor may round up * to the next alignment boundary. * + * *BEWARE*: The block device may be shrunk if @size is less than the current + * guest visible size. Callers who wish to only extend @disk should always pass + * VIR_DOMAIN_BLOCK_RESIZE_EXTEND (since 12.3.0) in @flags which instructs the + * hypervisor to deny an attempt to shrink the device. + * * If @flag contains VIR_DOMAIN_BLOCK_RESIZE_CAPACITY (since 10.0.0) the * hypervisor will resize the guest block device to fully fill the source. * @size must be either set to zero, or to the exact size of the block diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 2d31d4aa31..b5ea0086b9 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -9448,7 +9448,8 @@ qemuDomainBlockResize(virDomainPtr dom, virDomainDiskDef *persistDisk = NULL; virCheckFlags(VIR_DOMAIN_BLOCK_RESIZE_BYTES | - VIR_DOMAIN_BLOCK_RESIZE_CAPACITY, -1); + VIR_DOMAIN_BLOCK_RESIZE_CAPACITY | + VIR_DOMAIN_BLOCK_RESIZE_EXTEND, -1); /* We prefer operating on bytes. */ if ((flags & VIR_DOMAIN_BLOCK_RESIZE_BYTES) == 0) { @@ -9587,11 +9588,40 @@ qemuDomainBlockResize(virDomainPtr dom, if (!qemuDiskBusIsSD(disk->bus)) { nodename = qemuBlockStorageSourceGetEffectiveNodename(disk->src); } else { + if (flags & VIR_DOMAIN_BLOCK_RESIZE_EXTEND) { + /* technically possible, just not implemented */ + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("cannot prevent shrink on SD devices")); + goto endjob; + } + if (!(device = qemuAliasDiskDriveFromDisk(disk))) goto endjob; } qemuDomainObjEnterMonitor(vm); + + if (flags & VIR_DOMAIN_BLOCK_RESIZE_EXTEND) { + g_autoptr(GHashTable) blockNamedNodeData = qemuMonitorBlockGetNamedNodeData(priv->mon); + qemuBlockNamedNodeData *entry; + + if (!(entry = virHashLookup(blockNamedNodeData, nodename))) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, + _("failed to determine current size of '%1$s'"), + path); + qemuDomainObjExitMonitor(vm); + goto endjob; + } + + if (entry->capacity > size) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("resize of '%1$s' would shrink it from '%2$llu' to '%3$llu' bytes"), + path, entry->capacity, size); + qemuDomainObjExitMonitor(vm); + goto endjob; + } + } + if (qemuMonitorBlockResize(priv->mon, device, nodename, size) < 0) { qemuDomainObjExitMonitor(vm); goto endjob; -- 2.53.0
From: Peter Krempa <pkrempa@redhat.com> Use the new VIR_DOMAIN_BLOCK_RESIZE_EXTEND to prevent accidentally shrinking a disk and thus destroying data. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- docs/manpages/virsh.rst | 7 ++++++- tools/virsh-domain.c | 7 +++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst index 4b8bbec7d6..80b0ea14a8 100644 --- a/docs/manpages/virsh.rst +++ b/docs/manpages/virsh.rst @@ -1642,7 +1642,7 @@ blockresize :: - blockresize domain path ([size] | [--capacity]) + blockresize domain path ([size] | [--capacity]) [--extend] Resize a block device of domain while the domain is running, *path* specifies the absolute path of the block device; it corresponds @@ -1650,6 +1650,11 @@ to a unique target name (<target dev='name'/>) or source file (<source file='name'/>) for one of the disk devices attached to *domain* (see also ``domblklist`` for listing these names). +The *--extend* flag instructs the hypervisor to ensure that the new size isn't +smaller than the old size, thus prevents (accidental) shrinking of the block +device which may lead to data loss. Users are encouraged to always use this +flag unless communicating with an older hypervisor. + For image formats without metadata (raw) stored inside fixed-size storage (e.g. block devices) the --capacity flag can be used to resize the device to the full size of the backing device. diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index a17c8b42e2..08a1ce3953 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -3339,6 +3339,10 @@ static const vshCmdOptDef opts_blockresize[] = { .type = VSH_OT_BOOL, .help = N_("resize to capacity of source (block device)") }, + {.name = "extend", + .type = VSH_OT_BOOL, + .help = N_("ensure that the new size is larger than actual capacity (prevent shrink)") + }, {.name = NULL} }; @@ -3352,6 +3356,9 @@ cmdBlockresize(vshControl *ctl, const vshCmd *cmd) VSH_ALTERNATIVE_OPTIONS("size", "capacity"); + if (vshCommandOptBool(cmd, "extend")) + flags |= VIR_DOMAIN_BLOCK_RESIZE_EXTEND; + if (vshCommandOptString(ctl, cmd, "path", (const char **) &path) < 0) return false; -- 2.53.0
On 4/15/26 10:04, Peter Krempa via Devel wrote:
Shrinking a disk accidentally equals data loss and thus very bad time for anyone mis-typing.
This series adds a new flag to virDomainBlockResize to prevent such a thing if the user only intends to extend the disk.
v2: - extracted only the first part of the series adding the flag preventing shrink and exposing it
- the second part dealing with detecting if the flag is supported will be posted later along with a better approach to probe flags
Peter Krempa (3): virDomainBlockResizeFlags: Convert to prefix-style docs API/qemu: Introduce 'VIR_DOMAIN_BLOCK_RESIZE_EXTEND' for 'virDomainBlockResize' virsh: blockresize: Introduce '--extend' flag
docs/manpages/virsh.rst | 7 ++++++- include/libvirt/libvirt-domain.h | 10 ++++++++-- src/libvirt-domain.c | 5 +++++ src/qemu/qemu_driver.c | 32 +++++++++++++++++++++++++++++++- tools/virsh-domain.c | 7 +++++++ 5 files changed, 57 insertions(+), 4 deletions(-)
Reviewed-by: Michal Privoznik <mprivozn@redhat.com> Michal
participants (2)
-
Michal Prívozník -
Peter Krempa