block.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-)
Some operations insert an implicit node above the top node in the block
graph (e.g. block-stream or blockdev-backup). The implicit node is
removed when the operation finishes. If QMP query-named-block-nodes is
called while the operation is removing the implicit node, it may observe
a node with no children, causing a segfault.
This is hypothesized to only affect the block-stream operation as other
operations use the workaround bdc4c4c5e372756a5ba3fb3a61e585b02f0dd7f4
or do not detach their children during cleanup (see
3108a15cf09865456d499b08fe14e3dbec4ccbb3).
This backtrace was observed in #3149 on a relatively recent build. The
bs passed to bdrv_refresh_filename is the cor_filter_bs from the
block-stream operation; bs->implicit was "true".
0 bdrv_refresh_filename (bs=0x5efed72f8350)
at /usr/src/qemu-1:10.1.0+ds-5ubuntu2/b/qemu/block.c:8082
1 0x00005efea73cf9dc in bdrv_block_device_info
(blk=0x0, bs=0x5efed72f8350, flat=true, errp=0x7ffeb829ebd8)
at block/qapi.c:62
2 0x00005efea7391ed3 in bdrv_named_nodes_list
(flat=<optimized out>, errp=0x7ffeb829ebd8)
at /usr/src/qemu-1:10.1.0+ds-5ubuntu2/b/qemu/block.c:6275
3 0x00005efea7471993 in qmp_query_named_block_nodes
(has_flat=<optimized out>, flat=<optimized out>, errp=0x7ffeb829ebd8)
at /usr/src/qemu-1:10.1.0+ds-5ubuntu2/b/qemu/blockdev.c:2834
4 qmp_marshal_query_named_block_nodes
(args=<optimized out>, ret=0x7f2b753beec0, errp=0x7f2b753beec8)
at qapi/qapi-commands-block-core.c:553
5 0x00005efea74f03a5 in do_qmp_dispatch_bh (opaque=0x7f2b753beed0)
at qapi/qmp-dispatch.c:128
6 0x00005efea75108e6 in aio_bh_poll (ctx=0x5efed6f3f430)
at util/async.c:219
...
The get_allocated_file_size change resolves a second segfault after the
first was resolved. Here, bdrv_filter_bs returns NULL as the
bs (cor_filter_bs) has no children:
0 bdrv_co_get_allocated_file_size (bs=<optimized out>)
at /usr/src/qemu-1:10.1.0+ds-5ubuntu2+test8/b/qemu/block.c:6018
1 0x0000631d078522be in bdrv_co_get_allocated_file_size_entry
(opaque=0x7ffd375c5dd0) at block/block-gen.c:288
2 0x0000631d07929ec2 in coroutine_trampoline
(i0=<optimized out>, i1=<optimized out>)
at util/coroutine-ucontext.c:175
...
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3149
Buglink: https://bugs.launchpad.net/bugs/2126951
Suggested-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
Signed-off-by: Wesley Hershberger <wesley.hershberger@canonical.com>
---
As discussed in the previous thread:
https://lists.gnu.org/archive/html/qemu-devel/2025-10/msg05458.html
This resolves the issue with my reproducer.
make check-block passes locally.
Please let me know if any adjustments to the patch are needed.
Thanks for the quick & helpful reviews!
---
block.c | 21 ++++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/block.c b/block.c
index 8848e9a7ed665a1bfbde2aba29e2c414f5bbe39b..8629324703d5d5fcf0bc3908d5b2dd4b26e4031d 100644
--- a/block.c
+++ b/block.c
@@ -6024,8 +6024,18 @@ int64_t coroutine_fn bdrv_co_get_allocated_file_size(BlockDriverState *bs)
*/
return -ENOTSUP;
} else if (drv->is_filter) {
+ BlockDriverState *filtered = bdrv_filter_bs(bs);
+
+ /*
+ * A filter may have been removed from the graph (child detached) but
+ * not yet unrefed.
+ */
+ if (!filtered) {
+ return -ENOMEDIUM;
+ }
+
/* Filter drivers default to the size of their filtered child */
- return bdrv_co_get_allocated_file_size(bdrv_filter_bs(bs));
+ return bdrv_co_get_allocated_file_size(filtered);
} else {
/* Other drivers default to summing their children's sizes */
return bdrv_sum_allocated_file_size(bs);
@@ -8067,6 +8077,15 @@ void bdrv_refresh_filename(BlockDriverState *bs)
}
if (bs->implicit) {
+ /*
+ * An node may have been removed from the graph (child detached) but
+ * not yet unrefed. filename and full_open_options can be left
+ * unchanged since this state is temporary.
+ */
+ if (QLIST_EMPTY(&bs->children)) {
+ return;
+ }
+
/* For implicit nodes, just copy everything from the single child */
child = QLIST_FIRST(&bs->children);
assert(QLIST_NEXT(child, next) == NULL);
---
base-commit: e8779f3d1509cd07620c6166a9a280376e01ff2f
change-id: 20251024-second-fix-3149-f242bd8f57f5
Best regards,
--
Wesley Hershberger <wesley.hershberger@canonical.com>
On 24.10.25 21:07, Wesley Hershberger wrote: > Some operations insert an implicit node above the top node in the block > graph (e.g. block-stream or blockdev-backup). The implicit node is > removed when the operation finishes. If QMP query-named-block-nodes is > called while the operation is removing the implicit node, it may observe > a node with no children, causing a segfault. > > This is hypothesized to only affect the block-stream operation as other > operations use the workaround bdc4c4c5e372756a5ba3fb3a61e585b02f0dd7f4 > or do not detach their children during cleanup (see > 3108a15cf09865456d499b08fe14e3dbec4ccbb3). > > This backtrace was observed in #3149 on a relatively recent build. The > bs passed to bdrv_refresh_filename is the cor_filter_bs from the > block-stream operation; bs->implicit was "true". > > 0 bdrv_refresh_filename (bs=0x5efed72f8350) > at /usr/src/qemu-1:10.1.0+ds-5ubuntu2/b/qemu/block.c:8082 > 1 0x00005efea73cf9dc in bdrv_block_device_info > (blk=0x0, bs=0x5efed72f8350, flat=true, errp=0x7ffeb829ebd8) > at block/qapi.c:62 > 2 0x00005efea7391ed3 in bdrv_named_nodes_list > (flat=<optimized out>, errp=0x7ffeb829ebd8) > at /usr/src/qemu-1:10.1.0+ds-5ubuntu2/b/qemu/block.c:6275 > 3 0x00005efea7471993 in qmp_query_named_block_nodes > (has_flat=<optimized out>, flat=<optimized out>, errp=0x7ffeb829ebd8) > at /usr/src/qemu-1:10.1.0+ds-5ubuntu2/b/qemu/blockdev.c:2834 > 4 qmp_marshal_query_named_block_nodes > (args=<optimized out>, ret=0x7f2b753beec0, errp=0x7f2b753beec8) > at qapi/qapi-commands-block-core.c:553 > 5 0x00005efea74f03a5 in do_qmp_dispatch_bh (opaque=0x7f2b753beed0) > at qapi/qmp-dispatch.c:128 > 6 0x00005efea75108e6 in aio_bh_poll (ctx=0x5efed6f3f430) > at util/async.c:219 > ... > > The get_allocated_file_size change resolves a second segfault after the > first was resolved. Here, bdrv_filter_bs returns NULL as the > bs (cor_filter_bs) has no children: > > 0 bdrv_co_get_allocated_file_size (bs=<optimized out>) > at /usr/src/qemu-1:10.1.0+ds-5ubuntu2+test8/b/qemu/block.c:6018 > 1 0x0000631d078522be in bdrv_co_get_allocated_file_size_entry > (opaque=0x7ffd375c5dd0) at block/block-gen.c:288 > 2 0x0000631d07929ec2 in coroutine_trampoline > (i0=<optimized out>, i1=<optimized out>) > at util/coroutine-ucontext.c:175 > ... > > Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3149 > Buglink: https://bugs.launchpad.net/bugs/2126951 > Suggested-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> > Signed-off-by: Wesley Hershberger <wesley.hershberger@canonical.com> Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> -- Best regards, Vladimir
© 2016 - 2025 Red Hat, Inc.