Skip to content

Commit

Permalink
qapi: add x-debug-query-block-graph
Browse files Browse the repository at this point in the history
Add a new command, returning block nodes (and their users) graph.

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Message-id: 20181221170909.25584-2-vsementsov@virtuozzo.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
  • Loading branch information
Vladimir Sementsov-Ogievskiy authored and XanClic committed Jan 30, 2019
1 parent b4fbe1f commit 5d3b4e9
Show file tree
Hide file tree
Showing 6 changed files with 269 additions and 0 deletions.
148 changes: 148 additions & 0 deletions block.c
Expand Up @@ -4119,6 +4119,154 @@ BlockDeviceInfoList *bdrv_named_nodes_list(Error **errp)
return list;
}

#define QAPI_LIST_ADD(list, element) do { \
typeof(list) _tmp = g_new(typeof(*(list)), 1); \
_tmp->value = (element); \
_tmp->next = (list); \
(list) = _tmp; \
} while (0)

typedef struct XDbgBlockGraphConstructor {
XDbgBlockGraph *graph;
GHashTable *graph_nodes;
} XDbgBlockGraphConstructor;

static XDbgBlockGraphConstructor *xdbg_graph_new(void)
{
XDbgBlockGraphConstructor *gr = g_new(XDbgBlockGraphConstructor, 1);

gr->graph = g_new0(XDbgBlockGraph, 1);
gr->graph_nodes = g_hash_table_new(NULL, NULL);

return gr;
}

static XDbgBlockGraph *xdbg_graph_finalize(XDbgBlockGraphConstructor *gr)
{
XDbgBlockGraph *graph = gr->graph;

g_hash_table_destroy(gr->graph_nodes);
g_free(gr);

return graph;
}

static uintptr_t xdbg_graph_node_num(XDbgBlockGraphConstructor *gr, void *node)
{
uintptr_t ret = (uintptr_t)g_hash_table_lookup(gr->graph_nodes, node);

if (ret != 0) {
return ret;
}

/*
* Start counting from 1, not 0, because 0 interferes with not-found (NULL)
* answer of g_hash_table_lookup.
*/
ret = g_hash_table_size(gr->graph_nodes) + 1;
g_hash_table_insert(gr->graph_nodes, node, (void *)ret);

return ret;
}

static void xdbg_graph_add_node(XDbgBlockGraphConstructor *gr, void *node,
XDbgBlockGraphNodeType type, const char *name)
{
XDbgBlockGraphNode *n;

n = g_new0(XDbgBlockGraphNode, 1);

n->id = xdbg_graph_node_num(gr, node);
n->type = type;
n->name = g_strdup(name);

QAPI_LIST_ADD(gr->graph->nodes, n);
}

static void xdbg_graph_add_edge(XDbgBlockGraphConstructor *gr, void *parent,
const BdrvChild *child)
{
typedef struct {
unsigned int flag;
BlockPermission num;
} PermissionMap;

static const PermissionMap permissions[] = {
{ BLK_PERM_CONSISTENT_READ, BLOCK_PERMISSION_CONSISTENT_READ },
{ BLK_PERM_WRITE, BLOCK_PERMISSION_WRITE },
{ BLK_PERM_WRITE_UNCHANGED, BLOCK_PERMISSION_WRITE_UNCHANGED },
{ BLK_PERM_RESIZE, BLOCK_PERMISSION_RESIZE },
{ BLK_PERM_GRAPH_MOD, BLOCK_PERMISSION_GRAPH_MOD },
{ 0, 0 }
};
const PermissionMap *p;
XDbgBlockGraphEdge *edge;

QEMU_BUILD_BUG_ON(1UL << (ARRAY_SIZE(permissions) - 1) != BLK_PERM_ALL + 1);

edge = g_new0(XDbgBlockGraphEdge, 1);

edge->parent = xdbg_graph_node_num(gr, parent);
edge->child = xdbg_graph_node_num(gr, child->bs);
edge->name = g_strdup(child->name);

for (p = permissions; p->flag; p++) {
if (p->flag & child->perm) {
QAPI_LIST_ADD(edge->perm, p->num);
}
if (p->flag & child->shared_perm) {
QAPI_LIST_ADD(edge->shared_perm, p->num);
}
}

QAPI_LIST_ADD(gr->graph->edges, edge);
}


XDbgBlockGraph *bdrv_get_xdbg_block_graph(Error **errp)
{
BlockBackend *blk;
BlockJob *job;
BlockDriverState *bs;
BdrvChild *child;
XDbgBlockGraphConstructor *gr = xdbg_graph_new();

for (blk = blk_all_next(NULL); blk; blk = blk_all_next(blk)) {
char *allocated_name = NULL;
const char *name = blk_name(blk);

if (!*name) {
name = allocated_name = blk_get_attached_dev_id(blk);
}
xdbg_graph_add_node(gr, blk, X_DBG_BLOCK_GRAPH_NODE_TYPE_BLOCK_BACKEND,
name);
g_free(allocated_name);
if (blk_root(blk)) {
xdbg_graph_add_edge(gr, blk, blk_root(blk));
}
}

for (job = block_job_next(NULL); job; job = block_job_next(job)) {
GSList *el;

xdbg_graph_add_node(gr, job, X_DBG_BLOCK_GRAPH_NODE_TYPE_BLOCK_JOB,
job->job.id);
for (el = job->nodes; el; el = el->next) {
xdbg_graph_add_edge(gr, job, (BdrvChild *)el->data);
}
}

QTAILQ_FOREACH(bs, &graph_bdrv_states, node_list) {
xdbg_graph_add_node(gr, bs, X_DBG_BLOCK_GRAPH_NODE_TYPE_BLOCK_DRIVER,
bs->node_name);
QLIST_FOREACH(child, &bs->children, next) {
xdbg_graph_add_edge(gr, bs, child);
}
}

return xdbg_graph_finalize(gr);
}

BlockDriverState *bdrv_lookup_bs(const char *device,
const char *node_name,
Error **errp)
Expand Down
5 changes: 5 additions & 0 deletions block/block-backend.c
Expand Up @@ -2249,3 +2249,8 @@ int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in,
blk_out->root, off_out,
bytes, read_flags, write_flags);
}

const BdrvChild *blk_root(BlockBackend *blk)
{
return blk->root;
}
5 changes: 5 additions & 0 deletions blockdev.c
Expand Up @@ -3582,6 +3582,11 @@ BlockDeviceInfoList *qmp_query_named_block_nodes(Error **errp)
return bdrv_named_nodes_list(errp);
}

XDbgBlockGraph *qmp_x_debug_query_block_graph(Error **errp)
{
return bdrv_get_xdbg_block_graph(errp);
}

BlockJob *do_blockdev_backup(BlockdevBackup *backup, JobTxn *txn,
Error **errp)
{
Expand Down
1 change: 1 addition & 0 deletions include/block/block.h
Expand Up @@ -448,6 +448,7 @@ void bdrv_eject(BlockDriverState *bs, bool eject_flag);
const char *bdrv_get_format_name(BlockDriverState *bs);
BlockDriverState *bdrv_find_node(const char *node_name);
BlockDeviceInfoList *bdrv_named_nodes_list(Error **errp);
XDbgBlockGraph *bdrv_get_xdbg_block_graph(Error **errp);
BlockDriverState *bdrv_lookup_bs(const char *device,
const char *node_name,
Error **errp);
Expand Down
2 changes: 2 additions & 0 deletions include/sysemu/block-backend.h
Expand Up @@ -237,4 +237,6 @@ int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in,
int bytes, BdrvRequestFlags read_flags,
BdrvRequestFlags write_flags);

const BdrvChild *blk_root(BlockBackend *blk);

#endif
108 changes: 108 additions & 0 deletions qapi/block-core.json
Expand Up @@ -1665,6 +1665,114 @@
##
{ 'command': 'query-named-block-nodes', 'returns': [ 'BlockDeviceInfo' ] }

##
# @XDbgBlockGraphNodeType:
#
# @block-backend: corresponds to BlockBackend
#
# @block-job: corresonds to BlockJob
#
# @block-driver: corresponds to BlockDriverState
#
# Since: 4.0
##
{ 'enum': 'XDbgBlockGraphNodeType',
'data': [ 'block-backend', 'block-job', 'block-driver' ] }

##
# @XDbgBlockGraphNode:
#
# @id: Block graph node identifier. This @id is generated only for
# x-debug-query-block-graph and does not relate to any other identifiers in
# Qemu.
#
# @type: Type of graph node. Can be one of block-backend, block-job or
# block-driver-state.
#
# @name: Human readable name of the node. Corresponds to node-name for
# block-driver-state nodes; is not guaranteed to be unique in the whole
# graph (with block-jobs and block-backends).
#
# Since: 4.0
##
{ 'struct': 'XDbgBlockGraphNode',
'data': { 'id': 'uint64', 'type': 'XDbgBlockGraphNodeType', 'name': 'str' } }

##
# @BlockPermission:
#
# Enum of base block permissions.
#
# @consistent-read: A user that has the "permission" of consistent reads is
# guaranteed that their view of the contents of the block
# device is complete and self-consistent, representing the
# contents of a disk at a specific point.
# For most block devices (including their backing files) this
# is true, but the property cannot be maintained in a few
# situations like for intermediate nodes of a commit block
# job.
#
# @write: This permission is required to change the visible disk contents.
#
# @write-unchanged: This permission (which is weaker than BLK_PERM_WRITE) is
# both enough and required for writes to the block node when
# the caller promises that the visible disk content doesn't
# change.
# As the BLK_PERM_WRITE permission is strictly stronger,
# either is sufficient to perform an unchanging write.
#
# @resize: This permission is required to change the size of a block node.
#
# @graph-mod: This permission is required to change the node that this
# BdrvChild points to.
#
# Since: 4.0
##
{ 'enum': 'BlockPermission',
'data': [ 'consistent-read', 'write', 'write-unchanged', 'resize',
'graph-mod' ] }
##
# @XDbgBlockGraphEdge:
#
# Block Graph edge description for x-debug-query-block-graph.
#
# @parent: parent id
#
# @child: child id
#
# @name: name of the relation (examples are 'file' and 'backing')
#
# @perm: granted permissions for the parent operating on the child
#
# @shared-perm: permissions that can still be granted to other users of the
# child while it is still attached to this parent
#
# Since: 4.0
##
{ 'struct': 'XDbgBlockGraphEdge',
'data': { 'parent': 'uint64', 'child': 'uint64',
'name': 'str', 'perm': [ 'BlockPermission' ],
'shared-perm': [ 'BlockPermission' ] } }

##
# @XDbgBlockGraph:
#
# Block Graph - list of nodes and list of edges.
#
# Since: 4.0
##
{ 'struct': 'XDbgBlockGraph',
'data': { 'nodes': ['XDbgBlockGraphNode'], 'edges': ['XDbgBlockGraphEdge'] } }

##
# @x-debug-query-block-graph:
#
# Get the block graph.
#
# Since: 4.0
##
{ 'command': 'x-debug-query-block-graph', 'returns': 'XDbgBlockGraph' }

##
# @drive-mirror:
#
Expand Down

0 comments on commit 5d3b4e9

Please sign in to comment.