On 03/25/2016 03:07 AM, Max Reitz wrote: > This command returns the tree of BlockDriverStates under a given root > node. > > Every tree node is described by its node name and the connection of a > parent node to its children additionally contains the role the child > assumes. > > A node's name can then be used e.g. in conjunction with > query-named-block-nodes to get more information about the node.
I found another problem: {'execute': 'query-block-node-tree', 'arguments': {'root-node': 'disk1' } } {"return": {"children": [{"role": "children.1", "node": {"children": [{"role": "file", "node": {}}], "node-name": "test1"}}, {"role": "children.0", "node": {"children": [{"role": "file", "node": {}}]}}]}} s->children[0] is children.0, and s->children[1] is children.1. But we output them in reverse order. The reason is: BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, BlockDriverState *child_bs, const char *child_name, const BdrvChildRole *child_role) { BdrvChild *child = bdrv_root_attach_child(child_bs, child_name, child_role); QLIST_INSERT_HEAD(&parent_bs->children, child, next); return child; } We insert the new child to the head, not the tail... Thanks Wen Congyang > > Signed-off-by: Max Reitz <mre...@redhat.com> > --- > block/qapi.c | 43 +++++++++++++++++++++++++++++++++++++++++++ > qapi/block-core.json | 46 ++++++++++++++++++++++++++++++++++++++++++++++ > qmp-commands.hx | 38 ++++++++++++++++++++++++++++++++++++++ > 3 files changed, 127 insertions(+) > > diff --git a/block/qapi.c b/block/qapi.c > index 6a4869a..a35d32b 100644 > --- a/block/qapi.c > +++ b/block/qapi.c > @@ -493,6 +493,49 @@ BlockInfoList *qmp_query_block(Error **errp) > return head; > } > > +static BlockNodeTreeNode *qmp_query_block_node_tree_by_bs(BlockDriverState > *bs) > +{ > + BlockNodeTreeNode *bntn; > + BlockNodeTreeChildList **p_next; > + BdrvChild *child; > + > + bntn = g_new0(BlockNodeTreeNode, 1); > + > + bntn->node_name = g_strdup(bdrv_get_node_name(bs)); > + bntn->has_node_name = bntn->node_name; > + > + p_next = &bntn->children; > + QLIST_FOREACH(child, &bs->children, next) { > + BlockNodeTreeChild *bntc; > + > + bntc = g_new(BlockNodeTreeChild, 1); > + *bntc = (BlockNodeTreeChild){ > + .role = g_strdup(child->name), > + .node = qmp_query_block_node_tree_by_bs(child->bs), > + }; > + > + *p_next = g_new0(BlockNodeTreeChildList, 1); > + (*p_next)->value = bntc; > + p_next = &(*p_next)->next; > + } > + > + *p_next = NULL; > + return bntn; > +} > + > +BlockNodeTreeNode *qmp_query_block_node_tree(const char *root_node, > + Error **errp) > +{ > + BlockDriverState *bs; > + > + bs = bdrv_lookup_bs(root_node, root_node, errp); > + if (!bs) { > + return NULL; > + } > + > + return qmp_query_block_node_tree_by_bs(bs); > +} > + > static bool next_query_bds(BlockBackend **blk, BlockDriverState **bs, > bool query_nodes) > { > diff --git a/qapi/block-core.json b/qapi/block-core.json > index b1cf77d..754ccd6 100644 > --- a/qapi/block-core.json > +++ b/qapi/block-core.json > @@ -470,6 +470,52 @@ > > > ## > +# @BlockNodeTreeNode: > +# > +# Describes a node in the block node graph. > +# > +# @node-name: If present, the node's name. > +# > +# @children: List of the node's children. > +# > +# Since: 2.7 > +## > +{ 'struct': 'BlockNodeTreeNode', > + 'data': { '*node-name': 'str', > + 'children': ['BlockNodeTreeChild'] } } > + > +## > +# @BlockNodeTreeChild: > +# > +# Describes a child node in the block node graph. > +# > +# @role: Role the child assumes for its parent, e.g. "file" or "backing". > +# > +# @node: The child node's BlockNodeTreeNode structure. > +# > +# Since: 2.7 > +## > +{ 'struct': 'BlockNodeTreeChild', > + 'data': { 'role': 'str', > + 'node': 'BlockNodeTreeNode' } } > + > +## > +# @query-block-node-tree: > +# > +# Queries the tree of nodes under a given node in the block graph. > +# > +# @root-node: Node name or device name of the tree's root node. > +# > +# Returns: The root node's BlockNodeTreeNode structure. > +# > +# Since: 2.7 > +## > +{ 'command': 'query-block-node-tree', > + 'data': { 'root-node': 'str' }, > + 'returns': 'BlockNodeTreeNode' } > + > + > +## > # @BlockDeviceTimedStats: > # > # Statistics of a block device during a given interval of time. > diff --git a/qmp-commands.hx b/qmp-commands.hx > index 9e05365..5c404aa 100644 > --- a/qmp-commands.hx > +++ b/qmp-commands.hx > @@ -2637,6 +2637,44 @@ EQMP > }, > > SQMP > +query-block-node-tree > +--------------------- > + > +Queries the tree of nodes under a given node in the block graph. > + > +Arguments: > + > +- "root-node": Node name or device name of the tree's root node (json-string) > + > +The block node tree is represented with BlockNodeTreeNode and > BlockNodeTreeChild > +json-objects. > + > +Each BlockNodeTreeNode json-object contains the following: > + > +- "node-name": If present, the node's name (json-string, optional) > +- "children": json-array of the node's children, each entry is a json-object > of > + type BlockNodeTreeChild > + > +Each BlockNodeTreeChild json-object contains the following: > + > +- "role": Role the child node assumes for its parent, e.g. "file" or > "backing" > + (json-string) > +- "node": BlockNodeTreeNode describing the child node (json-object) > + > +The cyclic reference of BlockNodeTreeNode and BlockNodeTreeChild to each > other > +thus spawns a tree. > + > +This command returns the root node's BlockNodeTreeNode structure. > + > +EQMP > + > + { > + .name = "query-block-node-tree", > + .args_type = "root-node:B", > + .mhandler.cmd_new = qmp_marshal_query_block_node_tree, > + }, > + > +SQMP > query-blockstats > ---------------- > >