qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Kevin Wolf <kwolf@redhat.com>
To: anthony@codemonkey.ws
Cc: kwolf@redhat.com, qemu-devel@nongnu.org
Subject: [Qemu-devel] [PATCH 08/32] qemu-img: Add --backing-chain option to info command
Date: Wed, 24 Oct 2012 11:50:32 +0200	[thread overview]
Message-ID: <1351072256-6112-9-git-send-email-kwolf@redhat.com> (raw)
In-Reply-To: <1351072256-6112-1-git-send-email-kwolf@redhat.com>

From: Stefan Hajnoczi <stefanha@redhat.com>

The qemu-img info --backing-chain option enumerates the backing file
chain.  For example, for base.qcow2 <- snap1.qcow2 <- snap2.qcow2 the
output becomes:

  $ qemu-img info --backing-chain snap2.qcow2
  image: snap2.qcow2
  file format: qcow2
  virtual size: 100M (104857600 bytes)
  disk size: 196K
  cluster_size: 65536
  backing file: snap1.qcow2
  backing file format: qcow2

  image: snap1.qcow2
  file format: qcow2
  virtual size: 100M (104857600 bytes)
  disk size: 196K
  cluster_size: 65536
  backing file: base.qcow2
  backing file format: qcow2

  image: base.qcow2
  file format: qcow2
  virtual size: 100M (104857600 bytes)
  disk size: 136K
  cluster_size: 65536

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 qemu-img.c |  167 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 153 insertions(+), 14 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index c092ccf..b17bddd 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -1112,6 +1112,23 @@ static void dump_snapshots(BlockDriverState *bs)
     g_free(sn_tab);
 }
 
+static void dump_json_image_info_list(ImageInfoList *list)
+{
+    Error *errp = NULL;
+    QString *str;
+    QmpOutputVisitor *ov = qmp_output_visitor_new();
+    QObject *obj;
+    visit_type_ImageInfoList(qmp_output_get_visitor(ov),
+                             &list, NULL, &errp);
+    obj = qmp_output_get_qobject(ov);
+    str = qobject_to_json_pretty(obj);
+    assert(str != NULL);
+    printf("%s\n", qstring_get_str(str));
+    qobject_decref(obj);
+    qmp_output_visitor_cleanup(ov);
+    QDECREF(str);
+}
+
 static void collect_snapshots(BlockDriverState *bs , ImageInfo *info)
 {
     int i, sn_count;
@@ -1251,9 +1268,129 @@ static void dump_human_image_info(ImageInfo *info)
             printf("backing file format: %s\n", info->backing_filename_format);
         }
     }
+
+    if (info->has_snapshots) {
+        SnapshotInfoList *elem;
+        char buf[256];
+
+        printf("Snapshot list:\n");
+        printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
+
+        /* Ideally bdrv_snapshot_dump() would operate on SnapshotInfoList but
+         * we convert to the block layer's native QEMUSnapshotInfo for now.
+         */
+        for (elem = info->snapshots; elem; elem = elem->next) {
+            QEMUSnapshotInfo sn = {
+                .vm_state_size = elem->value->vm_state_size,
+                .date_sec = elem->value->date_sec,
+                .date_nsec = elem->value->date_nsec,
+                .vm_clock_nsec = elem->value->vm_clock_sec * 1000000000ULL +
+                                 elem->value->vm_clock_nsec,
+            };
+
+            pstrcpy(sn.id_str, sizeof(sn.id_str), elem->value->id);
+            pstrcpy(sn.name, sizeof(sn.name), elem->value->name);
+            printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), &sn));
+        }
+    }
+}
+
+static void dump_human_image_info_list(ImageInfoList *list)
+{
+    ImageInfoList *elem;
+    bool delim = false;
+
+    for (elem = list; elem; elem = elem->next) {
+        if (delim) {
+            printf("\n");
+        }
+        delim = true;
+
+        dump_human_image_info(elem->value);
+    }
+}
+
+static gboolean str_equal_func(gconstpointer a, gconstpointer b)
+{
+    return strcmp(a, b) == 0;
+}
+
+/**
+ * Open an image file chain and return an ImageInfoList
+ *
+ * @filename: topmost image filename
+ * @fmt: topmost image format (may be NULL to autodetect)
+ * @chain: true  - enumerate entire backing file chain
+ *         false - only topmost image file
+ *
+ * Returns a list of ImageInfo objects or NULL if there was an error opening an
+ * image file.  If there was an error a message will have been printed to
+ * stderr.
+ */
+static ImageInfoList *collect_image_info_list(const char *filename,
+                                              const char *fmt,
+                                              bool chain)
+{
+    ImageInfoList *head = NULL;
+    ImageInfoList **last = &head;
+    GHashTable *filenames;
+
+    filenames = g_hash_table_new_full(g_str_hash, str_equal_func, NULL, NULL);
+
+    while (filename) {
+        BlockDriverState *bs;
+        ImageInfo *info;
+        ImageInfoList *elem;
+
+        if (g_hash_table_lookup_extended(filenames, filename, NULL, NULL)) {
+            error_report("Backing file '%s' creates an infinite loop.",
+                         filename);
+            goto err;
+        }
+        g_hash_table_insert(filenames, (gpointer)filename, NULL);
+
+        bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_NO_BACKING,
+                           false);
+        if (!bs) {
+            goto err;
+        }
+
+        info = g_new0(ImageInfo, 1);
+        collect_image_info(bs, info, filename, fmt);
+        collect_snapshots(bs, info);
+
+        elem = g_new0(ImageInfoList, 1);
+        elem->value = info;
+        *last = elem;
+        last = &elem->next;
+
+        bdrv_delete(bs);
+
+        filename = fmt = NULL;
+        if (chain) {
+            if (info->has_full_backing_filename) {
+                filename = info->full_backing_filename;
+            } else if (info->has_backing_filename) {
+                filename = info->backing_filename;
+            }
+            if (info->has_backing_filename_format) {
+                fmt = info->backing_filename_format;
+            }
+        }
+    }
+    g_hash_table_destroy(filenames);
+    return head;
+
+err:
+    qapi_free_ImageInfoList(head);
+    g_hash_table_destroy(filenames);
+    return NULL;
 }
 
-enum {OPTION_OUTPUT = 256};
+enum {
+    OPTION_OUTPUT = 256,
+    OPTION_BACKING_CHAIN = 257,
+};
 
 typedef enum OutputFormat {
     OFORMAT_JSON,
@@ -1264,9 +1401,9 @@ static int img_info(int argc, char **argv)
 {
     int c;
     OutputFormat output_format = OFORMAT_HUMAN;
+    bool chain = false;
     const char *filename, *fmt, *output;
-    BlockDriverState *bs;
-    ImageInfo *info;
+    ImageInfoList *list;
 
     fmt = NULL;
     output = NULL;
@@ -1276,6 +1413,7 @@ static int img_info(int argc, char **argv)
             {"help", no_argument, 0, 'h'},
             {"format", required_argument, 0, 'f'},
             {"output", required_argument, 0, OPTION_OUTPUT},
+            {"backing-chain", no_argument, 0, OPTION_BACKING_CHAIN},
             {0, 0, 0, 0}
         };
         c = getopt_long(argc, argv, "f:h",
@@ -1294,6 +1432,9 @@ static int img_info(int argc, char **argv)
         case OPTION_OUTPUT:
             output = optarg;
             break;
+        case OPTION_BACKING_CHAIN:
+            chain = true;
+            break;
         }
     }
     if (optind >= argc) {
@@ -1310,27 +1451,25 @@ static int img_info(int argc, char **argv)
         return 1;
     }
 
-    bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_NO_BACKING, false);
-    if (!bs) {
+    list = collect_image_info_list(filename, fmt, chain);
+    if (!list) {
         return 1;
     }
 
-    info = g_new0(ImageInfo, 1);
-    collect_image_info(bs, info, filename, fmt);
-
     switch (output_format) {
     case OFORMAT_HUMAN:
-        dump_human_image_info(info);
-        dump_snapshots(bs);
+        dump_human_image_info_list(list);
         break;
     case OFORMAT_JSON:
-        collect_snapshots(bs, info);
-        dump_json_image_info(info);
+        if (chain) {
+            dump_json_image_info_list(list);
+        } else {
+            dump_json_image_info(list->value);
+        }
         break;
     }
 
-    qapi_free_ImageInfo(info);
-    bdrv_delete(bs);
+    qapi_free_ImageInfoList(list);
     return 0;
 }
 
-- 
1.7.6.5

  parent reply	other threads:[~2012-10-24  9:51 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-10-24  9:50 [Qemu-devel] [PULL 00/32] Block patches Kevin Wolf
2012-10-24  9:50 ` [Qemu-devel] [PATCH 01/32] qemu-img: Fix division by zero for zero size images Kevin Wolf
2012-10-24  9:50 ` [Qemu-devel] [PATCH 02/32] qemu-iotests: Test qemu-img operation on zero size image Kevin Wolf
2012-10-24  9:50 ` [Qemu-devel] [PATCH 03/32] qmp: fix __accept() in qmp.py Kevin Wolf
2012-10-24  9:50 ` [Qemu-devel] [PATCH 04/32] qemu-img rebase: use empty string to rebase without backing file Kevin Wolf
2012-10-24  9:50 ` [Qemu-devel] [PATCH 05/32] block: make bdrv_find_backing_image compare canonical filenames Kevin Wolf
2012-10-24  9:50 ` [Qemu-devel] [PATCH 06/32] block: in commit, determine base image from the top image Kevin Wolf
2012-10-24  9:50 ` [Qemu-devel] [PATCH 07/32] qemu-iotests: add relative backing file tests for block-commit (040) Kevin Wolf
2012-10-24  9:50 ` Kevin Wolf [this message]
2012-10-24  9:50 ` [Qemu-devel] [PATCH 09/32] qemu-iotests: Add 043 backing file chain infinite loop test Kevin Wolf
2012-10-24  9:50 ` [Qemu-devel] [PATCH 10/32] qemu-img: document 'info --backing-chain' Kevin Wolf
2012-10-24  9:50 ` [Qemu-devel] [PATCH 11/32] block: bdrv_create(): don't leak cco.filename on error Kevin Wolf
2012-10-24  9:50 ` [Qemu-devel] [PATCH 12/32] monitor: Allow add-fd to any specified fd set Kevin Wolf
2012-10-24  9:50 ` [Qemu-devel] [PATCH 13/32] monitor: Enable adding an inherited fd to an " Kevin Wolf
2012-10-24  9:50 ` [Qemu-devel] [PATCH 14/32] monitor: Prevent removing fd from set during init Kevin Wolf
2012-10-24  9:50 ` [Qemu-devel] [PATCH 15/32] qemu-config: Add new -add-fd command line option Kevin Wolf
2012-10-24  9:50 ` [Qemu-devel] [PATCH 16/32] block: add bdrv_query_info Kevin Wolf
2012-10-24  9:50 ` [Qemu-devel] [PATCH 17/32] block: add bdrv_query_stats Kevin Wolf
2012-10-24  9:50 ` [Qemu-devel] [PATCH 18/32] block: add bdrv_open_backing_file Kevin Wolf
2012-10-24  9:50 ` [Qemu-devel] [PATCH 19/32] block: introduce new dirty bitmap functionality Kevin Wolf
2012-10-24  9:50 ` [Qemu-devel] [PATCH 20/32] block: export dirty bitmap information in query-block Kevin Wolf
2012-10-24  9:50 ` [Qemu-devel] [PATCH 21/32] block: rename block_job_complete to block_job_completed Kevin Wolf
2012-10-24  9:50 ` [Qemu-devel] [PATCH 22/32] block: add block-job-complete Kevin Wolf
2012-10-24  9:50 ` [Qemu-devel] [PATCH 23/32] block: introduce BLOCK_JOB_READY event Kevin Wolf
2012-10-24  9:50 ` [Qemu-devel] [PATCH 24/32] mirror: introduce mirror job Kevin Wolf
2012-10-24  9:50 ` [Qemu-devel] [PATCH 25/32] qmp: add drive-mirror command Kevin Wolf
2012-10-24  9:50 ` [Qemu-devel] [PATCH 26/32] mirror: implement completion Kevin Wolf
2012-10-24  9:50 ` [Qemu-devel] [PATCH 27/32] qemu-iotests: add mirroring test case Kevin Wolf
2012-10-24  9:50 ` [Qemu-devel] [PATCH 28/32] iostatus: forward block_job_iostatus_reset to block job Kevin Wolf
2012-10-24  9:50 ` [Qemu-devel] [PATCH 29/32] mirror: add support for on-source-error/on-target-error Kevin Wolf
2012-10-24  9:50 ` [Qemu-devel] [PATCH 30/32] qmp: add pull_event function Kevin Wolf
2012-10-24  9:50 ` [Qemu-devel] [PATCH 31/32] qemu-iotests: add testcases for mirroring on-source-error/on-target-error Kevin Wolf
2012-10-24  9:50 ` [Qemu-devel] [PATCH 32/32] osdep: Less restrictive F_SEFL in qemu_dup_flags() Kevin Wolf
2012-10-29 19:24 ` [Qemu-devel] [PULL 00/32] Block patches Anthony Liguori

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1351072256-6112-9-git-send-email-kwolf@redhat.com \
    --to=kwolf@redhat.com \
    --cc=anthony@codemonkey.ws \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).