]> git.proxmox.com Git - mirror_qemu.git/commitdiff
qemu-img: Let info print block graph
authorHanna Reitz <hreitz@redhat.com>
Mon, 20 Jun 2022 16:27:03 +0000 (18:27 +0200)
committerKevin Wolf <kwolf@redhat.com>
Wed, 1 Feb 2023 15:52:33 +0000 (16:52 +0100)
For every node in the backing chain, collect its BlockGraphInfo struct
using bdrv_query_block_graph_info().  Print all nodes' information,
indenting child nodes and labelling them with a path constructed from
the child names leading to the node from the root (e.g. /file/file).

Note that we open each image with BDRV_O_NO_BACKING, so its backing
child is omitted from this graph, and thus presented in the previous
manner: By simply concatenating all images' information, separated with
blank lines.

This affects two iotests:
- 065: Here we try to get the format node's format specific information.
  The pre-patch code does so by taking all lines from "Format specific
  information:" until an empty line.  This format specific information
  is no longer followed by an empty line, though, but by child node
  information, so limit the range by "Child node '/file':".
- 302: Calls qemu_img() for qemu-img info directly, which does not
  filter the output, so the child node information ends up in the
  output.

Signed-off-by: Hanna Reitz <hreitz@redhat.com>
Message-Id: <20220620162704.80987-12-hreitz@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
qapi/block-core.json
qemu-img.c
tests/qemu-iotests/065
tests/qemu-iotests/302.out

index d703e0fb1600a02767de882058e1f55969a88b21..7f331eb8eaca7b70756da8a48d8ab784ca8e6c9a 100644 (file)
 ##
 # @DummyBlockCoreForceArrays:
 #
-# Not used by QMP; hack to let us use BlockNodeInfoList internally
+# Not used by QMP; hack to let us use BlockGraphInfoList internally
 #
 # Since: 8.0
 ##
 { 'struct': 'DummyBlockCoreForceArrays',
-  'data': { 'unused-block-node-info': ['BlockNodeInfo'] } }
+  'data': { 'unused-block-graph-info': ['BlockGraphInfo'] } }
index d2763ac2de5f4f049bc77acf84054e3031c6e1ce..595179a34632b97f2f5cf6e75f9e3ad4ab5ef3c4 100644 (file)
@@ -2817,13 +2817,13 @@ static void dump_snapshots(BlockDriverState *bs)
     g_free(sn_tab);
 }
 
-static void dump_json_block_node_info_list(BlockNodeInfoList *list)
+static void dump_json_block_graph_info_list(BlockGraphInfoList *list)
 {
     GString *str;
     QObject *obj;
     Visitor *v = qobject_output_visitor_new(&obj);
 
-    visit_type_BlockNodeInfoList(v, NULL, &list, &error_abort);
+    visit_type_BlockGraphInfoList(v, NULL, &list, &error_abort);
     visit_complete(v, &obj);
     str = qobject_to_json_pretty(obj, true);
     assert(str != NULL);
@@ -2833,13 +2833,13 @@ static void dump_json_block_node_info_list(BlockNodeInfoList *list)
     g_string_free(str, true);
 }
 
-static void dump_json_block_node_info(BlockNodeInfo *info)
+static void dump_json_block_graph_info(BlockGraphInfo *info)
 {
     GString *str;
     QObject *obj;
     Visitor *v = qobject_output_visitor_new(&obj);
 
-    visit_type_BlockNodeInfo(v, NULL, &info, &error_abort);
+    visit_type_BlockGraphInfo(v, NULL, &info, &error_abort);
     visit_complete(v, &obj);
     str = qobject_to_json_pretty(obj, true);
     assert(str != NULL);
@@ -2849,9 +2849,29 @@ static void dump_json_block_node_info(BlockNodeInfo *info)
     g_string_free(str, true);
 }
 
-static void dump_human_image_info_list(BlockNodeInfoList *list)
+static void dump_human_image_info(BlockGraphInfo *info, int indentation,
+                                  const char *path)
 {
-    BlockNodeInfoList *elem;
+    BlockChildInfoList *children_list;
+
+    bdrv_node_info_dump(qapi_BlockGraphInfo_base(info), indentation);
+
+    for (children_list = info->children; children_list;
+         children_list = children_list->next)
+    {
+        BlockChildInfo *child = children_list->value;
+        g_autofree char *child_path = NULL;
+
+        printf("%*sChild node '%s%s':\n",
+               indentation * 4, "", path, child->name);
+        child_path = g_strdup_printf("%s%s/", path, child->name);
+        dump_human_image_info(child->info, indentation + 1, child_path);
+    }
+}
+
+static void dump_human_image_info_list(BlockGraphInfoList *list)
+{
+    BlockGraphInfoList *elem;
     bool delim = false;
 
     for (elem = list; elem; elem = elem->next) {
@@ -2860,7 +2880,7 @@ static void dump_human_image_info_list(BlockNodeInfoList *list)
         }
         delim = true;
 
-        bdrv_node_info_dump(elem->value, 0);
+        dump_human_image_info(elem->value, 0, "/");
     }
 }
 
@@ -2870,7 +2890,7 @@ static gboolean str_equal_func(gconstpointer a, gconstpointer b)
 }
 
 /**
- * Open an image file chain and return an BlockNodeInfoList
+ * Open an image file chain and return an BlockGraphInfoList
  *
  * @filename: topmost image filename
  * @fmt: topmost image format (may be NULL to autodetect)
@@ -2881,13 +2901,13 @@ static gboolean str_equal_func(gconstpointer a, gconstpointer b)
  * opening an image file.  If there was an error a message will have been
  * printed to stderr.
  */
-static BlockNodeInfoList *collect_image_info_list(bool image_opts,
-                                                  const char *filename,
-                                                  const char *fmt,
-                                                  bool chain, bool force_share)
+static BlockGraphInfoList *collect_image_info_list(bool image_opts,
+                                                   const char *filename,
+                                                   const char *fmt,
+                                                   bool chain, bool force_share)
 {
-    BlockNodeInfoList *head = NULL;
-    BlockNodeInfoList **tail = &head;
+    BlockGraphInfoList *head = NULL;
+    BlockGraphInfoList **tail = &head;
     GHashTable *filenames;
     Error *err = NULL;
 
@@ -2896,7 +2916,7 @@ static BlockNodeInfoList *collect_image_info_list(bool image_opts,
     while (filename) {
         BlockBackend *blk;
         BlockDriverState *bs;
-        BlockNodeInfo *info;
+        BlockGraphInfo *info;
 
         if (g_hash_table_lookup_extended(filenames, filename, NULL, NULL)) {
             error_report("Backing file '%s' creates an infinite loop.",
@@ -2913,7 +2933,14 @@ static BlockNodeInfoList *collect_image_info_list(bool image_opts,
         }
         bs = blk_bs(blk);
 
-        bdrv_query_block_node_info(bs, &info, &err);
+        /*
+         * Note that the returned BlockGraphInfo object will not have
+         * information about this image's backing node, because we have opened
+         * it with BDRV_O_NO_BACKING.  Printing this object will therefore not
+         * duplicate the backing chain information that we obtain by walking
+         * the chain manually here.
+         */
+        bdrv_query_block_graph_info(bs, &info, &err);
         if (err) {
             error_report_err(err);
             blk_unref(blk);
@@ -2946,7 +2973,7 @@ static BlockNodeInfoList *collect_image_info_list(bool image_opts,
     return head;
 
 err:
-    qapi_free_BlockNodeInfoList(head);
+    qapi_free_BlockGraphInfoList(head);
     g_hash_table_destroy(filenames);
     return NULL;
 }
@@ -2957,7 +2984,7 @@ static int img_info(int argc, char **argv)
     OutputFormat output_format = OFORMAT_HUMAN;
     bool chain = false;
     const char *filename, *fmt, *output;
-    BlockNodeInfoList *list;
+    BlockGraphInfoList *list;
     bool image_opts = false;
     bool force_share = false;
 
@@ -3036,14 +3063,14 @@ static int img_info(int argc, char **argv)
         break;
     case OFORMAT_JSON:
         if (chain) {
-            dump_json_block_node_info_list(list);
+            dump_json_block_graph_info_list(list);
         } else {
-            dump_json_block_node_info(list->value);
+            dump_json_block_graph_info(list->value);
         }
         break;
     }
 
-    qapi_free_BlockNodeInfoList(list);
+    qapi_free_BlockGraphInfoList(list);
     return 0;
 }
 
index b724c89c7c50a8699137ea3caf0575d9240ca0b6..b76701c71e8d1cb5b8708ba7065242251f7824e5 100755 (executable)
@@ -56,7 +56,7 @@ class TestQemuImgInfo(TestImageInfoSpecific):
     def test_human(self):
         data = qemu_img('info', '--output=human', test_img).stdout.split('\n')
         data = data[(data.index('Format specific information:') + 1)
-                    :data.index('')]
+                    :data.index("Child node '/file':")]
         for field in data:
             self.assertTrue(re.match('^ {4}[^ ]', field) is not None)
         data = [line.strip() for line in data]
index 3e7c281b9116e4b54a4d6834d9ef4a760a69ca47..edfa1c4f05490b353b30c5d5acc7ec3354864e77 100644 (file)
@@ -4,6 +4,11 @@ image: nbd+unix:///exp?socket=SOCK_DIR/PID-nbd-sock
 file format: raw
 virtual size: 448 KiB (458752 bytes)
 disk size: unavailable
+Child node '/file':
+    image: nbd+unix:///exp?socket=SOCK_DIR/PID-nbd-sock
+    file format: nbd
+    virtual size: 448 KiB (458752 bytes)
+    disk size: unavailable
 
 === Converted image info ===
 image: TEST_IMG