block/qapi.c | 12 ++++++++++++ qapi/block-core.json | 16 ++++++++++++++++ tests/qemu-iotests/184.out | 8 ++++++++ 3 files changed, 36 insertions(+)
In combination with using a throttle filter to enforce IO limits for
a guest device, knowing the 'file' child of a block device can be
useful. If the throttle filter is only intended for guest IO, block
jobs should not also be limited by the throttle filter, so the
block operations need to be done with the 'file' child of the top
throttle node as the target. In combination with mirroring, the name
of that child is not fixed.
Another scenario is when unplugging a guest device after mirroring
below a top throttle node, where the mirror target is added explicitly
via blockdev-add. After mirroring, the target becomes the new 'file'
child of the throttle node. For unplugging, both the top throttle node
and the mirror target need to be deleted, because only implicitly
added child nodes are deleted automatically, and the current 'file'
child of the throttle node was explicitly added (as the mirror
target).
In other scenarios, it could be useful to follow the backing chain.
Note that iotests 191 and 273 use _filter_img_info, so the 'children'
information is filtered out there.
Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
---
Changes in v2:
* Return a map of children, not just the file child's node name.
block/qapi.c | 12 ++++++++++++
qapi/block-core.json | 16 ++++++++++++++++
tests/qemu-iotests/184.out | 8 ++++++++
3 files changed, 36 insertions(+)
diff --git a/block/qapi.c b/block/qapi.c
index 2c50a6bf3b..e0606a3c09 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -51,6 +51,8 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
ImageInfo *backing_info;
BlockDriverState *backing;
BlockDeviceInfo *info;
+ BlockdevChildList **children_list_tail;
+ BdrvChild *child;
if (!bs->drv) {
error_setg(errp, "Block device %s is ejected", bs->node_name);
@@ -77,6 +79,16 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
info->node_name = g_strdup(bs->node_name);
}
+ children_list_tail = &info->children;
+ QLIST_FOREACH(child, &bs->children, next) {
+ BlockdevChild *child_ref = g_new0(BlockdevChild, 1);
+ child_ref->child = g_strdup(child->name);
+ if (child->bs && child->bs->node_name[0]) {
+ child_ref->node_name = g_strdup(child->bs->node_name);
+ }
+ QAPI_LIST_APPEND(children_list_tail, child_ref);
+ }
+
backing = bdrv_cow_bs(bs);
if (backing) {
info->backing_file = g_strdup(backing->filename);
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 1df6644f0d..8816feec2d 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -461,6 +461,19 @@
'direct': 'bool',
'no-flush': 'bool' } }
+##
+# @BlockdevChild:
+#
+# @child: The name of the child, for example 'file' or 'backing'.
+#
+# @node-name: The name of the child's block driver node.
+#
+# Since: 10.1
+##
+{ 'struct': 'BlockdevChild',
+ 'data': { 'child': 'str',
+ '*node-name': 'str' } }
+
##
# @BlockDeviceInfo:
#
@@ -486,6 +499,8 @@
# @backing_file_depth: number of files in the backing file chain
# (since: 1.2)
#
+# @children: Information about child block nodes. (since: 10.1)
+#
# @active: true if the backend is active; typical cases for inactive backends
# are on the migration source instance after migration completes and on the
# destination before it completes. (since: 10.0)
@@ -560,6 +575,7 @@
{ 'struct': 'BlockDeviceInfo',
'data': { 'file': 'str', '*node-name': 'str', 'ro': 'bool', 'drv': 'str',
'*backing_file': 'str', 'backing_file_depth': 'int',
+ 'children': ['BlockdevChild'],
'active': 'bool', 'encrypted': 'bool',
'detect_zeroes': 'BlockdevDetectZeroesOptions',
'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
diff --git a/tests/qemu-iotests/184.out b/tests/qemu-iotests/184.out
index 52692b6b3b..ef99bb2e9a 100644
--- a/tests/qemu-iotests/184.out
+++ b/tests/qemu-iotests/184.out
@@ -41,6 +41,12 @@ Testing:
},
"iops_wr": 0,
"ro": false,
+ "children": [
+ {
+ "node-name": "disk0",
+ "child": "file"
+ }
+ ],
"node-name": "throttle0",
"backing_file_depth": 1,
"drv": "throttle",
@@ -69,6 +75,8 @@ Testing:
},
"iops_wr": 0,
"ro": false,
+ "children": [
+ ],
"node-name": "disk0",
"backing_file_depth": 0,
"drv": "null-co",
--
2.47.2
Am 01.07.2025 um 18:21 hat Fiona Ebner geschrieben:
> In combination with using a throttle filter to enforce IO limits for
> a guest device, knowing the 'file' child of a block device can be
> useful. If the throttle filter is only intended for guest IO, block
> jobs should not also be limited by the throttle filter, so the
> block operations need to be done with the 'file' child of the top
> throttle node as the target. In combination with mirroring, the name
> of that child is not fixed.
>
> Another scenario is when unplugging a guest device after mirroring
> below a top throttle node, where the mirror target is added explicitly
> via blockdev-add. After mirroring, the target becomes the new 'file'
> child of the throttle node. For unplugging, both the top throttle node
> and the mirror target need to be deleted, because only implicitly
> added child nodes are deleted automatically, and the current 'file'
> child of the throttle node was explicitly added (as the mirror
> target).
>
> In other scenarios, it could be useful to follow the backing chain.
>
> Note that iotests 191 and 273 use _filter_img_info, so the 'children'
> information is filtered out there.
>
> Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
> diff --git a/qapi/block-core.json b/qapi/block-core.json
> index 1df6644f0d..8816feec2d 100644
> --- a/qapi/block-core.json
> +++ b/qapi/block-core.json
> @@ -461,6 +461,19 @@
> 'direct': 'bool',
> 'no-flush': 'bool' } }
>
> +##
> +# @BlockdevChild:
> +#
> +# @child: The name of the child, for example 'file' or 'backing'.
> +#
> +# @node-name: The name of the child's block driver node.
> +#
> +# Since: 10.1
> +##
> +{ 'struct': 'BlockdevChild',
> + 'data': { 'child': 'str',
> + '*node-name': 'str' } }
Is node-name really optional? I don't think we have nodes without a node
name any more, do we?
Same with your check for child->bs, I don't think a BdrvChild without a
bs can exist (or only while creating/destroying the BdrvChild, which
holds the graph lock and doesn't allow monitor commands to run in the
middle).
Kevin
Am 02.07.25 um 11:13 schrieb Kevin Wolf:
> Am 01.07.2025 um 18:21 hat Fiona Ebner geschrieben:
>> +##
>> +# @BlockdevChild:
>> +#
>> +# @child: The name of the child, for example 'file' or 'backing'.
>> +#
>> +# @node-name: The name of the child's block driver node.
>> +#
>> +# Since: 10.1
>> +##
>> +{ 'struct': 'BlockdevChild',
>> + 'data': { 'child': 'str',
>> + '*node-name': 'str' } }
>
> Is node-name really optional? I don't think we have nodes without a node
> name any more, do we?
I'm not aware of any, but @node-name in @BlockDeviceInfo is marked as
optional too, so I went with that.
Looking at the git history, missing node-names are auto-generated since
15489c769b ("block: auto-generated node-names") or v2.5. The QAPI schema
says @node-name was added before that in v2.0. Should it be made
non-optional in @BlockDeviceInfo too?
> Same with your check for child->bs, I don't think a BdrvChild without a
> bs can exist (or only while creating/destroying the BdrvChild, which
> holds the graph lock and doesn't allow monitor commands to run in the
> middle).
Okay, yes. There are other places that access child->bs without checking
already. I'll drop that check.
Best Regards,
Fiona
Am 02.07.2025 um 11:39 hat Fiona Ebner geschrieben:
> Am 02.07.25 um 11:13 schrieb Kevin Wolf:
> > Am 01.07.2025 um 18:21 hat Fiona Ebner geschrieben:
> >> +##
> >> +# @BlockdevChild:
> >> +#
> >> +# @child: The name of the child, for example 'file' or 'backing'.
> >> +#
> >> +# @node-name: The name of the child's block driver node.
> >> +#
> >> +# Since: 10.1
> >> +##
> >> +{ 'struct': 'BlockdevChild',
> >> + 'data': { 'child': 'str',
> >> + '*node-name': 'str' } }
> >
> > Is node-name really optional? I don't think we have nodes without a node
> > name any more, do we?
>
> I'm not aware of any, but @node-name in @BlockDeviceInfo is marked as
> optional too, so I went with that.
>
> Looking at the git history, missing node-names are auto-generated since
> 15489c769b ("block: auto-generated node-names") or v2.5. The QAPI schema
> says @node-name was added before that in v2.0. Should it be made
> non-optional in @BlockDeviceInfo too?
Yes, I think this can be done.
Markus, a question about the future direction with such changes:
Currently, we only care about JSON level compatibility. In the future,
if we ever get native bindings for some programming languages (is anyone
still working on one?), I suppose a switch from something like
Option<String> to String could be considered incompatible. Would we
want to guarantee compatibility at that level then, or would
applications using the bindings just have to be updated?
Kevin
© 2016 - 2025 Red Hat, Inc.