[PATCH 2/2] qemu-img info: Optionally show block limits

Kevin Wolf posted 2 patches 4 days, 23 hours ago
Maintainers: Kevin Wolf <kwolf@redhat.com>, Hanna Reitz <hreitz@redhat.com>, Eric Blake <eblake@redhat.com>, Markus Armbruster <armbru@redhat.com>
[PATCH 2/2] qemu-img info: Optionally show block limits
Posted by Kevin Wolf 4 days, 23 hours ago
Add a new --limits option to 'qemu-img info' that displays the block
limits for the image and all of its children, making the information
more accessible for human users than in QMP. This option is not enabled
by default because it can be a lot of output that isn't usually relevant
if you're not specifically trying to diagnose some I/O problem.

This makes the same information automatically also available in HMP
'info block -v'.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 docs/tools/qemu-img.rst |  6 +++++-
 include/block/qapi.h    |  2 +-
 block/qapi.c            | 34 ++++++++++++++++++++++++++++++++--
 qemu-img.c              | 15 ++++++++++++---
 qemu-img-cmds.hx        |  4 ++--
 5 files changed, 52 insertions(+), 9 deletions(-)

diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst
index 5e7b85079d..fdc9ea9cf2 100644
--- a/docs/tools/qemu-img.rst
+++ b/docs/tools/qemu-img.rst
@@ -503,7 +503,7 @@ Command description:
 
   The size syntax is similar to :manpage:`dd(1)`'s size syntax.
 
-.. option:: info [--object OBJECTDEF] [--image-opts] [-f FMT] [--output=OFMT] [--backing-chain] [-U] FILENAME
+.. option:: info [--object OBJECTDEF] [--image-opts] [-f FMT] [--output=OFMT] [--backing-chain] [--limits] [-U] FILENAME
 
   Give information about the disk image *FILENAME*. Use it in
   particular to know the size reserved on disk which can be different
@@ -571,6 +571,10 @@ Command description:
     ``ImageInfoSpecific*`` QAPI object (e.g. ``ImageInfoSpecificQCow2``
     for qcow2 images).
 
+  *Block limits*
+    The block limits for I/O that QEMU detected for the image.
+    This information is only shown if the ``--limits`` option was specified.
+
 .. option:: map [--object OBJECTDEF] [--image-opts] [-f FMT] [--start-offset=OFFSET] [--max-length=LEN] [--output=OFMT] [-U] FILENAME
 
   Dump the metadata of image *FILENAME* and its backing file chain.
diff --git a/include/block/qapi.h b/include/block/qapi.h
index 54c48de26a..be554e53dc 100644
--- a/include/block/qapi.h
+++ b/include/block/qapi.h
@@ -42,7 +42,7 @@ bdrv_query_image_info(BlockDriverState *bs, ImageInfo **p_info, bool flat,
                       bool skip_implicit_filters, Error **errp);
 void GRAPH_RDLOCK
 bdrv_query_block_graph_info(BlockDriverState *bs, BlockGraphInfo **p_info,
-                            Error **errp);
+                            bool limits, Error **errp);
 
 void bdrv_snapshot_dump(QEMUSnapshotInfo *sn);
 void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec,
diff --git a/block/qapi.c b/block/qapi.c
index 54521d0a68..9f5771e019 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -417,6 +417,7 @@ fail:
  */
 void bdrv_query_block_graph_info(BlockDriverState *bs,
                                  BlockGraphInfo **p_info,
+                                 bool limits,
                                  Error **errp)
 {
     ERRP_GUARD();
@@ -425,7 +426,7 @@ void bdrv_query_block_graph_info(BlockDriverState *bs,
     BdrvChild *c;
 
     info = g_new0(BlockGraphInfo, 1);
-    bdrv_do_query_node_info(bs, qapi_BlockGraphInfo_base(info), false, errp);
+    bdrv_do_query_node_info(bs, qapi_BlockGraphInfo_base(info), limits, errp);
     if (*errp) {
         goto fail;
     }
@@ -439,7 +440,7 @@ void bdrv_query_block_graph_info(BlockDriverState *bs,
         QAPI_LIST_APPEND(children_list_tail, c_info);
 
         c_info->name = g_strdup(c->name);
-        bdrv_query_block_graph_info(c->bs, &c_info->info, errp);
+        bdrv_query_block_graph_info(c->bs, &c_info->info, limits, errp);
         if (*errp) {
             goto fail;
         }
@@ -936,6 +937,29 @@ void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec,
     visit_free(v);
 }
 
+/**
+ * Dumps the given BlockLimitsInfo object in a human-readable form,
+ * prepending an optional prefix if the dump is not empty.
+ */
+static void bdrv_image_info_limits_dump(BlockLimitsInfo *limits,
+                                        const char *prefix,
+                                        int indentation)
+{
+    QObject *obj;
+    Visitor *v = qobject_output_visitor_new(&obj);
+
+    visit_type_BlockLimitsInfo(v, NULL, &limits, &error_abort);
+    visit_complete(v, &obj);
+    if (!qobject_is_empty_dump(obj)) {
+        if (prefix) {
+            qemu_printf("%*s%s", indentation * 4, "", prefix);
+        }
+        dump_qobject(indentation + 1, obj);
+    }
+    qobject_unref(obj);
+    visit_free(v);
+}
+
 /**
  * Print the given @info object in human-readable form.  Every field is indented
  * using the given @indentation (four spaces per indentation level).
@@ -1011,6 +1035,12 @@ void bdrv_node_info_dump(BlockNodeInfo *info, int indentation, bool protocol)
         }
     }
 
+    if (info->limits) {
+        bdrv_image_info_limits_dump(info->limits,
+                                    "Block limits:\n",
+                                    indentation);
+    }
+
     if (info->has_snapshots) {
         SnapshotInfoList *elem;
 
diff --git a/qemu-img.c b/qemu-img.c
index 7a162fdc08..5cdbeda969 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -86,6 +86,7 @@ enum {
     OPTION_BITMAPS = 275,
     OPTION_FORCE = 276,
     OPTION_SKIP_BROKEN = 277,
+    OPTION_LIMITS = 278,
 };
 
 typedef enum OutputFormat {
@@ -3002,7 +3003,8 @@ static gboolean str_equal_func(gconstpointer a, gconstpointer b)
 static BlockGraphInfoList *collect_image_info_list(bool image_opts,
                                                    const char *filename,
                                                    const char *fmt,
-                                                   bool chain, bool force_share)
+                                                   bool chain, bool limits,
+                                                   bool force_share)
 {
     BlockGraphInfoList *head = NULL;
     BlockGraphInfoList **tail = &head;
@@ -3039,7 +3041,7 @@ static BlockGraphInfoList *collect_image_info_list(bool image_opts,
          * the chain manually here.
          */
         bdrv_graph_rdlock_main_loop();
-        bdrv_query_block_graph_info(bs, &info, &err);
+        bdrv_query_block_graph_info(bs, &info, limits, &err);
         bdrv_graph_rdunlock_main_loop();
 
         if (err) {
@@ -3088,6 +3090,7 @@ static int img_info(const img_cmd_t *ccmd, int argc, char **argv)
     BlockGraphInfoList *list;
     bool image_opts = false;
     bool force_share = false;
+    bool limits = false;
 
     fmt = NULL;
     for(;;) {
@@ -3097,6 +3100,7 @@ static int img_info(const img_cmd_t *ccmd, int argc, char **argv)
             {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
             {"backing-chain", no_argument, 0, OPTION_BACKING_CHAIN},
             {"force-share", no_argument, 0, 'U'},
+            {"limits", no_argument, 0, OPTION_LIMITS},
             {"output", required_argument, 0, OPTION_OUTPUT},
             {"object", required_argument, 0, OPTION_OBJECT},
             {0, 0, 0, 0}
@@ -3119,6 +3123,8 @@ static int img_info(const img_cmd_t *ccmd, int argc, char **argv)
 "     display information about the backing chain for copy-on-write overlays\n"
 "  -U, --force-share\n"
 "     open image in shared mode for concurrent access\n"
+"  --limits\n"
+"     show detected block limits (may depend on options, e.g. cache mode)\n"
 "  --output human|json\n"
 "     specify output format (default: human)\n"
 "  --object OBJDEF\n"
@@ -3140,6 +3146,9 @@ static int img_info(const img_cmd_t *ccmd, int argc, char **argv)
         case 'U':
             force_share = true;
             break;
+        case OPTION_LIMITS:
+            limits = true;
+            break;
         case OPTION_OUTPUT:
             output_format = parse_output_format(argv[0], optarg);
             break;
@@ -3156,7 +3165,7 @@ static int img_info(const img_cmd_t *ccmd, int argc, char **argv)
     filename = argv[optind++];
 
     list = collect_image_info_list(image_opts, filename, fmt, chain,
-                                   force_share);
+                                   limits, force_share);
     if (!list) {
         return 1;
     }
diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx
index 2c5a8a28f9..74b66f9d42 100644
--- a/qemu-img-cmds.hx
+++ b/qemu-img-cmds.hx
@@ -66,9 +66,9 @@ SRST
 ERST
 
 DEF("info", img_info,
-    "info [--object objectdef] [--image-opts] [-f fmt] [--output=ofmt] [--backing-chain] [-U] filename")
+    "info [--object objectdef] [--image-opts] [-f fmt] [--output=ofmt] [--backing-chain] [--limits] [-U] filename")
 SRST
-.. option:: info [--object OBJECTDEF] [--image-opts] [-f FMT] [--output=OFMT] [--backing-chain] [-U] FILENAME
+.. option:: info [--object OBJECTDEF] [--image-opts] [-f FMT] [--output=OFMT] [--backing-chain] [--limits] [-U] FILENAME
 ERST
 
 DEF("map", img_map,
-- 
2.51.0
Re: [PATCH 2/2] qemu-img info: Optionally show block limits
Posted by Eric Blake 4 days, 22 hours ago
On Tue, Sep 23, 2025 at 06:37:35PM +0200, Kevin Wolf wrote:
> Add a new --limits option to 'qemu-img info' that displays the block
> limits for the image and all of its children, making the information
> more accessible for human users than in QMP. This option is not enabled
> by default because it can be a lot of output that isn't usually relevant
> if you're not specifically trying to diagnose some I/O problem.
> 
> This makes the same information automatically also available in HMP
> 'info block -v'.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  docs/tools/qemu-img.rst |  6 +++++-
>  include/block/qapi.h    |  2 +-
>  block/qapi.c            | 34 ++++++++++++++++++++++++++++++++--
>  qemu-img.c              | 15 ++++++++++++---
>  qemu-img-cmds.hx        |  4 ++--
>  5 files changed, 52 insertions(+), 9 deletions(-)
> 

> +++ b/qemu-img.c

> @@ -3119,6 +3123,8 @@ static int img_info(const img_cmd_t *ccmd, int argc, char **argv)
>  "     display information about the backing chain for copy-on-write overlays\n"
>  "  -U, --force-share\n"
>  "     open image in shared mode for concurrent access\n"
> +"  --limits\n"
> +"     show detected block limits (may depend on options, e.g. cache mode)\n"

I'm trying to figure out how the parenthetical helps the --help
message.  The fact that it is detected limits already implies that
anything else (like cache mode) that can change what gets detected
would have an impact.  So I think it would be fine to just use " show
detected block limits\n".

But overall, I like the idea of being able to display what used to be
internal information.

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.
Virtualization:  qemu.org | libguestfs.org
Re: [PATCH 2/2] qemu-img info: Optionally show block limits
Posted by Kevin Wolf 4 days, 8 hours ago
Am 23.09.2025 um 20:09 hat Eric Blake geschrieben:
> On Tue, Sep 23, 2025 at 06:37:35PM +0200, Kevin Wolf wrote:
> > Add a new --limits option to 'qemu-img info' that displays the block
> > limits for the image and all of its children, making the information
> > more accessible for human users than in QMP. This option is not enabled
> > by default because it can be a lot of output that isn't usually relevant
> > if you're not specifically trying to diagnose some I/O problem.
> > 
> > This makes the same information automatically also available in HMP
> > 'info block -v'.
> > 
> > Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> > ---
> >  docs/tools/qemu-img.rst |  6 +++++-
> >  include/block/qapi.h    |  2 +-
> >  block/qapi.c            | 34 ++++++++++++++++++++++++++++++++--
> >  qemu-img.c              | 15 ++++++++++++---
> >  qemu-img-cmds.hx        |  4 ++--
> >  5 files changed, 52 insertions(+), 9 deletions(-)
> > 
> 
> > +++ b/qemu-img.c
> 
> > @@ -3119,6 +3123,8 @@ static int img_info(const img_cmd_t *ccmd, int argc, char **argv)
> >  "     display information about the backing chain for copy-on-write overlays\n"
> >  "  -U, --force-share\n"
> >  "     open image in shared mode for concurrent access\n"
> > +"  --limits\n"
> > +"     show detected block limits (may depend on options, e.g. cache mode)\n"
> 
> I'm trying to figure out how the parenthetical helps the --help
> message.  The fact that it is detected limits already implies that
> anything else (like cache mode) that can change what gets detected
> would have an impact.  So I think it would be fine to just use " show
> detected block limits\n".

Yes, other options can influence the limits, too. I just thought that
the most common pitfall for users will be that they actually want to
know the limits for cache=none because that's what their VM uses, but
'qemu-img info' returns them for cache=writeback. So it felt helpful to
add the note. But if you think that we'd better leave it out, I can
remove it.

Actually, this reminds me that I wanted to add a -t <cache_mode> option
to 'qemu-img info', too, so that you can actually get the interesting
information without using --image-opts. That will be something for a
separate patch, though.

Kevin