qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: "Denis V. Lunev" <den@openvz.org>
Cc: Kevin Wolf <kwolf@redhat.com>, "Denis V. Lunev" <den@openvz.org>,
	Jeff Cody <jcody@redhat.com>,
	qemu-devel@nongnu.org, Stefan Hajnoczi <stefanha@redhat.com>
Subject: [Qemu-devel] [PATCH 15/16] block/parallels: support read-only parallels snapshots
Date: Mon, 15 Dec 2014 11:28:00 +0300	[thread overview]
Message-ID: <1418632081-20667-16-git-send-email-den@openvz.org> (raw)
In-Reply-To: <1418632081-20667-1-git-send-email-den@openvz.org>

This patch reads snapshot information from the XML descriptor file.

The lastest snapshot (read-write one) could be located using the
following rules:
GUID could be used as a source to locate leaf in the snapshot tree:
- TopGUID tag is specified in the XML file
- {704718E1-2314-44c8-9087-D78ED36B0F4E} snapshot is present. Used for
  backups by Parallels
- {5FBAABE3-6958-40ff-92A7-860E329AAB41} snapshot

Without one of the snapshots above disk image is invalid.

Snapshots are read from top to bottom placing them into linear array,
which is already properly handled at the moment.

Signed-off-by: Denis V. Lunev <den@openvz.org>
CC: Jeff Cody <jcody@redhat.com>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>
---
 block/parallels.c | 102 +++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 77 insertions(+), 25 deletions(-)

diff --git a/block/parallels.c b/block/parallels.c
index d1b52f3..93a8498 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -42,6 +42,10 @@
 #define HEADER_VERSION 2
 #define HEADER_SIZE 64
 
+#define CURRENT_SNAP_ID "{5FBAABE3-6958-40ff-92A7-860E329AAB41}"
+#define BACKUP_SNAP_ID  "{704718E1-2314-44c8-9087-D78ED36B0F4E}"
+
+
 // always little-endian
 struct parallels_header {
     char magic[16]; // "WithoutFreeSpace"
@@ -239,13 +243,34 @@ static const char *xml_get_text(xmlNode *node, ...)
     return NULL;
 }
 
+static xmlNode *xml_find_snapshot(xmlNode *snaps, const char *guid)
+{
+    if (guid == NULL) {
+        return NULL;
+    }
+
+    for (snaps = snaps->children; snaps != NULL; snaps = snaps->next) {
+        const char *id;
+        if (snaps->type != XML_ELEMENT_NODE) {
+            continue;
+        }
+        id = xml_get_text(snaps, "GUID", NULL);
+
+        if (!xmlStrcasecmp((const xmlChar *)guid, (const xmlChar *)id)) {
+            return snaps;
+        }
+    }
+    return NULL;
+}
+
 static int parallels_open_xml(BlockDriverState *bs, int flags, Error **errp)
 {
-    int size, ret;
+    int ret, size, i;
     xmlDoc *doc = NULL;
-    xmlNode *root, *image;
+    xmlNode *root, *storage, *snaps;
     char *xml = NULL, *endptr;
     const char *data;
+    const char *leaf_snap;
     char image_path[PATH_MAX];
     Error *local_err = NULL;
     BDRVParallelsState *s = bs->opaque;
@@ -300,14 +325,47 @@ static int parallels_open_xml(BlockDriverState *bs, int flags, Error **errp)
         }
     }
 
-    image = xml_seek(root, "StorageData", "Storage", "Image", NULL);
-    data = ""; /* make gcc happy */
-    for (size = 0; image != NULL; image = image->next) {
-        if (image->type != XML_ELEMENT_NODE) {
-            continue;
+    snaps = xml_seek(root, "Snapshots", NULL);
+
+    leaf_snap = xml_get_text(snaps, "TopGUID", NULL);
+    if (leaf_snap != NULL && xml_find_snapshot(snaps, leaf_snap) == NULL) {
+        goto fail;
+    } else if (xml_find_snapshot(snaps, BACKUP_SNAP_ID) != NULL) {
+        leaf_snap = BACKUP_SNAP_ID;
+    } else if (xml_find_snapshot(snaps, CURRENT_SNAP_ID) != NULL) {
+        leaf_snap = CURRENT_SNAP_ID;
+    } else {
+        goto fail;
+    }
+
+    data = leaf_snap;
+    for (s->snaps_count = 0; data != NULL; s->snaps_count++) {
+        xmlNode *node = xml_find_snapshot(snaps, data);
+        if (node == NULL) {
+            break;
+        }
+        data = xml_get_text(node, "ParentGUID", NULL);
+    }
+    if (s->snaps_count == 0) {
+        goto fail;
+    }
+    s->snaps = g_malloc0(sizeof(ParallelsSnapshot) * s->snaps_count);
+
+    storage = xml_seek(root, "StorageData", "Storage", NULL);
+    if (storage == NULL) {
+        goto fail;
+    }
+
+    data = leaf_snap;
+    for (i = 0; i < s->snaps_count; i++) {
+        int64_t total_sectors;
+        xmlNode *image = xml_find_snapshot(storage, data);
+        xmlNode *snap = xml_find_snapshot(snaps, data);
+
+        if (image == NULL || snap == NULL) {
+            goto fail;
         }
 
-        size++;
         data = xml_get_text(image, "Type", NULL);
         if (data != NULL && strcmp(data, "Compressed")) {
             error_setg(errp, "Only compressed Parallels images are supported");
@@ -318,32 +376,26 @@ static int parallels_open_xml(BlockDriverState *bs, int flags, Error **errp)
         if (data == NULL) {
             goto fail;
         }
-    }
-    /* Images with more than 1 snapshots are not supported at the moment */
-    if (size != 1) {
-        error_setg(errp, "Parallels images with snapshots are not supported");
-        goto done;
-    }
 
-    s->snaps_count = size;
-    s->snaps = g_malloc0(sizeof(ParallelsSnapshot) * s->snaps_count);
+        path_combine(image_path, sizeof(image_path), bs->file->filename, data);
 
-    path_combine(image_path, sizeof(image_path), bs->file->filename, data);
+        ret = bdrv_open(&s->snaps[i].file, image_path, NULL, NULL,
+                        flags | BDRV_O_PROTOCOL, NULL, &local_err);
+        if (ret < 0) {
+            error_setg_errno(errp, -ret, "Could not open '%s': %s",
+                             image_path, error_get_pretty(local_err));
+            error_free(local_err);
+            goto done;
+        }
 
-    ret = bdrv_open(&s->snaps[0].file, image_path, NULL, NULL,
-                    flags | BDRV_O_PROTOCOL, NULL, &local_err);
-    if (ret < 0) {
-        error_setg_errno(errp, -ret, "Could not open '%s': %s",
-                         image_path, error_get_pretty(local_err));
-        error_free(local_err);
-    } else {
-        int64_t total_sectors;
         ret = parallels_open_image(s->snaps, &total_sectors, errp);
         if (bs->total_sectors != total_sectors) {
             error_setg(errp, "Invalid image: wrong total sectors");
             ret = -EINVAL;
             goto done;
         }
+
+        data = xml_get_text(snap, "ParentGUID", NULL);
     }
 
 done:
-- 
1.9.1

  parent reply	other threads:[~2014-12-15  9:10 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-12-15  8:27 [Qemu-devel] [PATCH v4 0/16] parallels format support improvements Denis V. Lunev
2014-12-15  8:27 ` [Qemu-devel] [PATCH 01/16] configure: add dependency from libxml2 Denis V. Lunev
2014-12-15  8:27 ` [Qemu-devel] [PATCH 02/16] block/parallels: allow to specify DiskDescriptor.xml instead of image file Denis V. Lunev
2014-12-15 10:45   ` Kevin Wolf
2014-12-15 11:51     ` Denis V. Lunev
2014-12-15  8:27 ` [Qemu-devel] [PATCH 03/16] iotests, parallels: quote TEST_IMG in 076 test to be path-safe Denis V. Lunev
2014-12-15  8:27 ` [Qemu-devel] [PATCH 04/16] iotests: simple parallels XML disk descriptor file test added Denis V. Lunev
2014-12-15 10:49   ` Kevin Wolf
2014-12-15  8:27 ` [Qemu-devel] [PATCH 05/16] block/parallels: support padded Parallels images Denis V. Lunev
2014-12-15 11:05   ` Kevin Wolf
2014-12-15 11:33     ` Denis V. Lunev
2014-12-15  8:27 ` [Qemu-devel] [PATCH 06/16] iotests: padded parallels image test Denis V. Lunev
2014-12-15  8:27 ` [Qemu-devel] [PATCH 07/16] parallels: change copyright information in the image header Denis V. Lunev
2014-12-15 11:06   ` Kevin Wolf
2014-12-15 11:52     ` Denis V. Lunev
2014-12-16 16:29     ` Denis V. Lunev
2014-12-15  8:27 ` [Qemu-devel] [PATCH 08/16] block/parallels: switch to bdrv_read Denis V. Lunev
2014-12-15  8:27 ` [Qemu-devel] [PATCH 09/16] block/parallels: read up to cluster end in one go Denis V. Lunev
2014-12-15  8:27 ` [Qemu-devel] [PATCH 10/16] block/parallels: add get_block_status Denis V. Lunev
2014-12-15 11:52   ` Denis V. Lunev
2014-12-15 12:18     ` Kevin Wolf
2014-12-15  8:27 ` [Qemu-devel] [PATCH 11/16] block/parallels: add support for backing files Denis V. Lunev
2014-12-15 12:30   ` Kevin Wolf
2014-12-15 13:08     ` Roman Kagan
2014-12-15  8:27 ` [Qemu-devel] [PATCH 12/16] iotests: testcase for backing in parallels format Denis V. Lunev
2014-12-15  8:27 ` [Qemu-devel] [PATCH 13/16] block/parallels: read disk size from XML if DiskDescriptor.xml is passed Denis V. Lunev
2014-12-15 12:38   ` Kevin Wolf
2014-12-15  8:27 ` [Qemu-devel] [PATCH 14/16] block/parallels: introduce ParallelsSnapshot data structure Denis V. Lunev
2014-12-15 12:45   ` Kevin Wolf
2014-12-15 13:32     ` Denis V. Lunev
2014-12-17 16:15     ` [Qemu-devel] [RFC PATCH 1/1] block/parallels: new concept for DiskDescriptor.xml Denis V. Lunev
2014-12-15  8:28 ` Denis V. Lunev [this message]
2014-12-15  8:28 ` [Qemu-devel] [PATCH 16/16] iotests: testcase parallels image with snapshots Denis V. Lunev

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=1418632081-20667-16-git-send-email-den@openvz.org \
    --to=den@openvz.org \
    --cc=jcody@redhat.com \
    --cc=kwolf@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@redhat.com \
    /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).