* [PATCH v2 0/5] block: refresh filter parents when child was resized
@ 2025-09-17 11:54 Fiona Ebner
2025-09-17 11:54 ` [PATCH v2 1/5] include/block/block_int-common: document when resize callback is used Fiona Ebner
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: Fiona Ebner @ 2025-09-17 11:54 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-block, fam, stefanha, hreitz, kwolf
Changes in v2:
* Check for BDRV_CHILD_FILTERED rather than bs->drv->is_filter which
is more generic and for example, also covers the case when the
child of a 'raw' node is resized.
* Expand commit message for main patch, i.e. 3/5.
* Add test for resizing the filtered 'file' node of a 'raw' node.
Resizing a node below a filter would result in the filter still
reporting the old size. Implement a 'resize' callback for the
child_of_bds class, that refreshes filter parents recursively.
Fiona Ebner (5):
include/block/block_int-common: document when resize callback is used
block: make bdrv_co_parent_cb_resize() a proper IO API function
block: implement 'resize' callback for child_of_bds class
iotests: add test for resizing a node below filters
iotests: add test for resizing a 'file' node below a 'raw' node
block.c | 12 +++
block/io.c | 9 +--
include/block/block_int-common.h | 5 +-
include/block/block_int-io.h | 6 ++
tests/qemu-iotests/tests/resize-below-filter | 73 +++++++++++++++++++
.../tests/resize-below-filter.out | 5 ++
tests/qemu-iotests/tests/resize-below-raw | 53 ++++++++++++++
tests/qemu-iotests/tests/resize-below-raw.out | 5 ++
8 files changed, 161 insertions(+), 7 deletions(-)
create mode 100755 tests/qemu-iotests/tests/resize-below-filter
create mode 100644 tests/qemu-iotests/tests/resize-below-filter.out
create mode 100755 tests/qemu-iotests/tests/resize-below-raw
create mode 100644 tests/qemu-iotests/tests/resize-below-raw.out
--
2.47.2
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2 1/5] include/block/block_int-common: document when resize callback is used
2025-09-17 11:54 [PATCH v2 0/5] block: refresh filter parents when child was resized Fiona Ebner
@ 2025-09-17 11:54 ` Fiona Ebner
2025-09-17 11:54 ` [PATCH v2 2/5] block: make bdrv_co_parent_cb_resize() a proper IO API function Fiona Ebner
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Fiona Ebner @ 2025-09-17 11:54 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-block, fam, stefanha, hreitz, kwolf
The 'resize' callback is only called by bdrv_parent_cb_resize() which
is only called by bdrv_co_write_req_finish() to notify the parent(s)
that the child was resized.
Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
---
include/block/block_int-common.h | 3 +++
1 file changed, 3 insertions(+)
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
index 034c0634c8..8a3d427356 100644
--- a/include/block/block_int-common.h
+++ b/include/block/block_int-common.h
@@ -1020,6 +1020,9 @@ struct BdrvChildClass {
* the I/O API.
*/
+ /*
+ * Notifies the parent that the child was resized.
+ */
void (*resize)(BdrvChild *child);
/*
--
2.47.2
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v2 2/5] block: make bdrv_co_parent_cb_resize() a proper IO API function
2025-09-17 11:54 [PATCH v2 0/5] block: refresh filter parents when child was resized Fiona Ebner
2025-09-17 11:54 ` [PATCH v2 1/5] include/block/block_int-common: document when resize callback is used Fiona Ebner
@ 2025-09-17 11:54 ` Fiona Ebner
2025-09-17 11:54 ` [PATCH v2 3/5] block: implement 'resize' callback for child_of_bds class Fiona Ebner
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Fiona Ebner @ 2025-09-17 11:54 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-block, fam, stefanha, hreitz, kwolf
In preparation for calling it via the bdrv_child_cb_resize() callback
that will be added by the next commit. Rename it to include the "_co_"
part while at it.
Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
---
block/io.c | 9 +++------
include/block/block_int-io.h | 6 ++++++
2 files changed, 9 insertions(+), 6 deletions(-)
diff --git a/block/io.c b/block/io.c
index 9bd8ba8431..928c02d1ad 100644
--- a/block/io.c
+++ b/block/io.c
@@ -46,9 +46,6 @@
/* Maximum read size for checking if data reads as zero, in bytes */
#define MAX_ZERO_CHECK_BUFFER (128 * KiB)
-static void coroutine_fn GRAPH_RDLOCK
-bdrv_parent_cb_resize(BlockDriverState *bs);
-
static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
int64_t offset, int64_t bytes, BdrvRequestFlags flags);
@@ -2038,7 +2035,7 @@ bdrv_co_write_req_finish(BdrvChild *child, int64_t offset, int64_t bytes,
end_sector > bs->total_sectors) &&
req->type != BDRV_TRACKED_DISCARD) {
bs->total_sectors = end_sector;
- bdrv_parent_cb_resize(bs);
+ bdrv_co_parent_cb_resize(bs);
bdrv_dirty_bitmap_truncate(bs, end_sector << BDRV_SECTOR_BITS);
}
if (req->bytes) {
@@ -3570,11 +3567,11 @@ int coroutine_fn bdrv_co_copy_range(BdrvChild *src, int64_t src_offset,
bytes, read_flags, write_flags);
}
-static void coroutine_fn GRAPH_RDLOCK
-bdrv_parent_cb_resize(BlockDriverState *bs)
+void coroutine_fn bdrv_co_parent_cb_resize(BlockDriverState *bs)
{
BdrvChild *c;
+ IO_CODE();
assert_bdrv_graph_readable();
QLIST_FOREACH(c, &bs->parents, next_parent) {
diff --git a/include/block/block_int-io.h b/include/block/block_int-io.h
index 4f94eb3c5a..ed8b5657d6 100644
--- a/include/block/block_int-io.h
+++ b/include/block/block_int-io.h
@@ -191,4 +191,10 @@ void bdrv_bsc_invalidate_range(BlockDriverState *bs,
*/
void bdrv_bsc_fill(BlockDriverState *bs, int64_t offset, int64_t bytes);
+/*
+ * Notify all parents that the size of the child changed.
+ */
+void coroutine_fn GRAPH_RDLOCK
+bdrv_co_parent_cb_resize(BlockDriverState *bs);
+
#endif /* BLOCK_INT_IO_H */
--
2.47.2
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v2 3/5] block: implement 'resize' callback for child_of_bds class
2025-09-17 11:54 [PATCH v2 0/5] block: refresh filter parents when child was resized Fiona Ebner
2025-09-17 11:54 ` [PATCH v2 1/5] include/block/block_int-common: document when resize callback is used Fiona Ebner
2025-09-17 11:54 ` [PATCH v2 2/5] block: make bdrv_co_parent_cb_resize() a proper IO API function Fiona Ebner
@ 2025-09-17 11:54 ` Fiona Ebner
2025-09-17 11:54 ` [PATCH v2 4/5] iotests: add test for resizing a node below filters Fiona Ebner
2025-09-17 11:54 ` [PATCH v2 5/5] iotests: add test for resizing a 'file' node below a 'raw' node Fiona Ebner
4 siblings, 0 replies; 6+ messages in thread
From: Fiona Ebner @ 2025-09-17 11:54 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-block, fam, stefanha, hreitz, kwolf
If a filtered child is resized, the size of the parent node is now
also refreshed (recursively for chains of filtered children).
For filter block drivers that do not implement .bdrv_co_getlength(),
this commit does not change the current behavior, because
bdrv_co_refresh_total_sectors() will used the current size via the
passed-in hint. This is the case for block drivers for (some) block
jobs, as well as copy-before-write.
Block jobs already set up a blocker preventing a QMP block_resize
operation while the job is running. That does not directly cover an
associated 'file' node of a 'raw' node, but resizing such a 'file'
node is already prevented too (backup, commit, mirror and stream were
checked).
The other case is copy-before-write. This commit does not change the
fact that the copy-before-write node still has the same size after its
filtered child is resized.
Block drivers that do implement .bdrv_co_getlength() and where
.is_filter is true, already returned the length of the file child, so
there is no change before and after this commit, with two exceptions:
1. preallocate can return an early data_end and otherwise queries the
file child, but that special casing is not changed.
2. blkverify returns the length of the test file. This commit does not
affect that behavior.
Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
---
Changes in v2:
* Check for BDRV_CHILD_FILTERED rather than bs->drv->is_filter which
is more generic and for example, also covers the case when the
child of a 'raw' node is resized.
* Expand commit message.
block.c | 12 ++++++++++++
include/block/block_int-common.h | 2 +-
2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/block.c b/block.c
index 8848e9a7ed..cf08e64add 100644
--- a/block.c
+++ b/block.c
@@ -1497,6 +1497,17 @@ static void GRAPH_WRLOCK bdrv_child_cb_detach(BdrvChild *child)
}
}
+static void coroutine_fn GRAPH_RDLOCK bdrv_child_cb_resize(BdrvChild *child)
+{
+ BlockDriverState *bs = child->opaque;
+
+ if (child->role & BDRV_CHILD_FILTERED) {
+ /* Best effort, ignore errors. */
+ bdrv_co_refresh_total_sectors(bs, bs->total_sectors);
+ bdrv_co_parent_cb_resize(bs);
+ }
+}
+
static int bdrv_child_cb_update_filename(BdrvChild *c, BlockDriverState *base,
const char *filename,
bool backing_mask_protocol,
@@ -1529,6 +1540,7 @@ const BdrvChildClass child_of_bds = {
.detach = bdrv_child_cb_detach,
.inactivate = bdrv_child_cb_inactivate,
.change_aio_ctx = bdrv_child_cb_change_aio_ctx,
+ .resize = bdrv_child_cb_resize,
.update_filename = bdrv_child_cb_update_filename,
.get_parent_aio_context = child_of_bds_get_parent_aio_context,
};
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
index 8a3d427356..c55b35da8e 100644
--- a/include/block/block_int-common.h
+++ b/include/block/block_int-common.h
@@ -1023,7 +1023,7 @@ struct BdrvChildClass {
/*
* Notifies the parent that the child was resized.
*/
- void (*resize)(BdrvChild *child);
+ void GRAPH_RDLOCK_PTR (*resize)(BdrvChild *child);
/*
* Returns a name that is supposedly more useful for human users than the
--
2.47.2
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v2 4/5] iotests: add test for resizing a node below filters
2025-09-17 11:54 [PATCH v2 0/5] block: refresh filter parents when child was resized Fiona Ebner
` (2 preceding siblings ...)
2025-09-17 11:54 ` [PATCH v2 3/5] block: implement 'resize' callback for child_of_bds class Fiona Ebner
@ 2025-09-17 11:54 ` Fiona Ebner
2025-09-17 11:54 ` [PATCH v2 5/5] iotests: add test for resizing a 'file' node below a 'raw' node Fiona Ebner
4 siblings, 0 replies; 6+ messages in thread
From: Fiona Ebner @ 2025-09-17 11:54 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-block, fam, stefanha, hreitz, kwolf
Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
---
tests/qemu-iotests/tests/resize-below-filter | 73 +++++++++++++++++++
.../tests/resize-below-filter.out | 5 ++
2 files changed, 78 insertions(+)
create mode 100755 tests/qemu-iotests/tests/resize-below-filter
create mode 100644 tests/qemu-iotests/tests/resize-below-filter.out
diff --git a/tests/qemu-iotests/tests/resize-below-filter b/tests/qemu-iotests/tests/resize-below-filter
new file mode 100755
index 0000000000..f55619cf34
--- /dev/null
+++ b/tests/qemu-iotests/tests/resize-below-filter
@@ -0,0 +1,73 @@
+#!/usr/bin/env python3
+# group: rw quick
+#
+# Test what happens when a node below filter nodes is resized.
+#
+# Copyright (C) Proxmox Server Solutions GmbH
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os
+import iotests
+from iotests import imgfmt, qemu_img_create, QMPTestCase
+
+image_size = 1 * 1024 * 1024
+image = os.path.join(iotests.test_dir, 'test.img')
+
+class TestResizeBelowFilter(QMPTestCase):
+ def setUp(self) -> None:
+ qemu_img_create('-f', imgfmt, image, str(image_size))
+
+ self.vm = iotests.VM()
+ self.vm.add_blockdev(self.vm.qmp_to_opts({
+ 'driver': imgfmt,
+ 'node-name': 'node0',
+ 'file': {
+ 'driver': 'file',
+ 'filename': image,
+ }
+ }))
+ self.vm.add_blockdev(self.vm.qmp_to_opts({
+ 'driver': 'compress',
+ 'node-name': 'comp0',
+ 'file': 'node0',
+ }))
+ self.vm.add_object('throttle-group,id=thrgr0')
+ self.vm.add_blockdev(self.vm.qmp_to_opts({
+ 'driver': 'throttle',
+ 'node-name': 'thr0',
+ 'throttle-group': 'thrgr0',
+ 'file': 'comp0',
+ }))
+ self.vm.add_object('throttle-group,id=thrgr1')
+ self.vm.add_blockdev(self.vm.qmp_to_opts({
+ 'driver': 'throttle',
+ 'node-name': 'thr1',
+ 'throttle-group': 'thrgr1',
+ 'file': 'node0',
+ }))
+ self.vm.launch()
+
+ def tearDown(self) -> None:
+ self.vm.shutdown()
+ os.remove(image)
+
+ def assert_size(self, size: int) -> None:
+ nodes = self.vm.qmp('query-named-block-nodes', flat=True)['return']
+ self.assertEqual(len(nodes), 5)
+ for node in nodes:
+ if node['drv'] == 'file':
+ continue
+ self.assertEqual(node['image']['virtual-size'], size)
+
+ def test_resize_below_filter(self) -> None:
+ self.assert_size(image_size)
+ self.vm.qmp('block_resize', node_name='thr0', size=2*image_size)
+ self.assert_size(2*image_size)
+ self.vm.qmp('block_resize', node_name='comp0', size=3*image_size)
+ self.assert_size(3*image_size)
+ self.vm.qmp('block_resize', node_name='node0', size=4*image_size)
+ self.assert_size(4*image_size)
+
+if __name__ == '__main__':
+ iotests.main(supported_fmts=['qcow2'], supported_protocols=['file'])
diff --git a/tests/qemu-iotests/tests/resize-below-filter.out b/tests/qemu-iotests/tests/resize-below-filter.out
new file mode 100644
index 0000000000..ae1213e6f8
--- /dev/null
+++ b/tests/qemu-iotests/tests/resize-below-filter.out
@@ -0,0 +1,5 @@
+.
+----------------------------------------------------------------------
+Ran 1 tests
+
+OK
--
2.47.2
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v2 5/5] iotests: add test for resizing a 'file' node below a 'raw' node
2025-09-17 11:54 [PATCH v2 0/5] block: refresh filter parents when child was resized Fiona Ebner
` (3 preceding siblings ...)
2025-09-17 11:54 ` [PATCH v2 4/5] iotests: add test for resizing a node below filters Fiona Ebner
@ 2025-09-17 11:54 ` Fiona Ebner
4 siblings, 0 replies; 6+ messages in thread
From: Fiona Ebner @ 2025-09-17 11:54 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-block, fam, stefanha, hreitz, kwolf
Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
---
New in v2.
tests/qemu-iotests/tests/resize-below-raw | 53 +++++++++++++++++++
tests/qemu-iotests/tests/resize-below-raw.out | 5 ++
2 files changed, 58 insertions(+)
create mode 100755 tests/qemu-iotests/tests/resize-below-raw
create mode 100644 tests/qemu-iotests/tests/resize-below-raw.out
diff --git a/tests/qemu-iotests/tests/resize-below-raw b/tests/qemu-iotests/tests/resize-below-raw
new file mode 100755
index 0000000000..3c9241c918
--- /dev/null
+++ b/tests/qemu-iotests/tests/resize-below-raw
@@ -0,0 +1,53 @@
+#!/usr/bin/env python3
+# group: rw quick
+#
+# Test what happens when a 'file' node below a 'raw' node is resized.
+#
+# Copyright (C) Proxmox Server Solutions GmbH
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os
+import iotests
+from iotests import imgfmt, qemu_img_create, QMPTestCase
+
+image_size = 1 * 1024 * 1024
+image = os.path.join(iotests.test_dir, 'test.img')
+
+class TestResizeBelowRaw(QMPTestCase):
+ def setUp(self) -> None:
+ qemu_img_create('-f', imgfmt, image, str(image_size))
+
+ self.vm = iotests.VM()
+ self.vm.add_blockdev(self.vm.qmp_to_opts({
+ 'driver': imgfmt,
+ 'node-name': 'node0',
+ 'file': {
+ 'driver': 'file',
+ 'filename': image,
+ 'node-name': 'file0',
+ }
+ }))
+ self.vm.launch()
+
+ def tearDown(self) -> None:
+ self.vm.shutdown()
+ os.remove(image)
+
+ def assert_size(self, size: int) -> None:
+ nodes = self.vm.qmp('query-named-block-nodes', flat=True)['return']
+ self.assertEqual(len(nodes), 2)
+ for node in nodes:
+ if node['drv'] == 'file':
+ continue
+ self.assertEqual(node['image']['virtual-size'], size)
+
+ def test_resize_below_raw(self) -> None:
+ self.assert_size(image_size)
+ self.vm.qmp('block_resize', node_name='file0', size=2*image_size)
+ self.assert_size(2*image_size)
+ self.vm.qmp('block_resize', node_name='node0', size=3*image_size)
+ self.assert_size(3*image_size)
+
+if __name__ == '__main__':
+ iotests.main(supported_fmts=['raw'], supported_protocols=['file'])
diff --git a/tests/qemu-iotests/tests/resize-below-raw.out b/tests/qemu-iotests/tests/resize-below-raw.out
new file mode 100644
index 0000000000..ae1213e6f8
--- /dev/null
+++ b/tests/qemu-iotests/tests/resize-below-raw.out
@@ -0,0 +1,5 @@
+.
+----------------------------------------------------------------------
+Ran 1 tests
+
+OK
--
2.47.2
^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2025-09-17 11:57 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-17 11:54 [PATCH v2 0/5] block: refresh filter parents when child was resized Fiona Ebner
2025-09-17 11:54 ` [PATCH v2 1/5] include/block/block_int-common: document when resize callback is used Fiona Ebner
2025-09-17 11:54 ` [PATCH v2 2/5] block: make bdrv_co_parent_cb_resize() a proper IO API function Fiona Ebner
2025-09-17 11:54 ` [PATCH v2 3/5] block: implement 'resize' callback for child_of_bds class Fiona Ebner
2025-09-17 11:54 ` [PATCH v2 4/5] iotests: add test for resizing a node below filters Fiona Ebner
2025-09-17 11:54 ` [PATCH v2 5/5] iotests: add test for resizing a 'file' node below a 'raw' node Fiona Ebner
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).