qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [RFC PATCH 1/1] block/parallels: new concept for DiskDescri


From: Denis V. Lunev
Subject: [Qemu-devel] [RFC PATCH 1/1] block/parallels: new concept for DiskDescriptor.xml
Date: Wed, 17 Dec 2014 19:15:55 +0300

Actually we have 2 major options without intruduction of the new concept:
- follow VMDK approach (original approach in v4 patchset)
- chain backing stores in XML parsing code in additional block driver

This is very rough but working conceptual code with a new approach.
The patch should be applied on top of patch 1 of the original patchset.

The idea is to parse XML file in new "XML" block driver and open
real image as a backing store inside XML parsing code. The first image
will be read-write, other underlying ones will be readnly. Padding
will be passed through options dictionary.

I have not addressed any other things from the review.

Can you pls comment this?

Signed-off-by: Denis V. Lunev <address@hidden>
CC: Jeff Cody <address@hidden>
CC: Kevin Wolf <address@hidden>
CC: Stefan Hajnoczi <address@hidden>
CC: Roman Kagan <address@hidden>
---
 block/parallels.c | 232 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 232 insertions(+)

diff --git a/block/parallels.c b/block/parallels.c
index 4f9cd8d..bc0d683 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -27,6 +27,12 @@
 #include "block/block_int.h"
 #include "qemu/module.h"
 
+#if defined(CONFIG_LIBXML2)
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#endif
+#include <stdarg.h>
+
 /**************************************************************/
 
 #define HEADER_MAGIC "WithoutFreeSpace"
@@ -211,3 +217,229 @@ static void bdrv_parallels_init(void)
 }
 
 block_init(bdrv_parallels_init);
+
+
+#if defined(CONFIG_LIBXML2)
+
+typedef struct BDRVPrlXmlState {
+    xmlDoc *xml;
+    BlockDriverState *bi;
+} BDRVPrlXmlState;
+
+
+static xmlNodePtr xml_find(xmlNode *node, const char *elem)
+{
+    xmlNode *child;
+
+    for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
+        if (!xmlStrcmp(child->name, (const xmlChar *)elem) &&
+                child->type == XML_ELEMENT_NODE) {
+            return child;
+        }
+    }
+    return NULL;
+}
+
+static xmlNodePtr xml_seek_va(xmlNode *root, va_list args)
+{
+    const char *elem;
+
+    while ((elem = va_arg(args, const char *)) != NULL) {
+        root = xml_find(root, elem);
+        if (root == NULL) {
+            return NULL;
+        }
+    }
+    return root;
+}
+
+static xmlNodePtr xml_seek(xmlNode *root, ...)
+{
+    va_list args;
+    va_start(args, root);
+    root = xml_seek_va(root, args);
+    va_end(args);
+    return root;
+}
+
+static const char *xml_get_text(xmlNode *node, ...)
+{
+    xmlNode *child;
+    va_list args;
+
+    va_start(args, node);
+    node = xml_seek_va(node, args);
+    va_end(args);
+
+    if (node == NULL) {
+        return NULL;
+    }
+
+    for (child = node->xmlChildrenNode; child; child = child->next) {
+        if (child->type == XML_TEXT_NODE) {
+            return (const char *)child->content;
+        }
+    }
+    return NULL;
+}
+
+static int prl_probe_xml(const uint8_t *data, int buf_size, const char *fn)
+{
+    int score = 0;
+    char *buf = g_malloc(buf_size + 1);
+
+    memcpy(buf, data, buf_size);
+    buf[buf_size] = 0;
+    if (strstr(buf, "<?xml version=\"1.0\"?>") &&
+        strstr(buf, "<Parallels_disk_image>")) {
+        score = 100;
+    }
+    g_free(buf);
+    return score;
+}
+
+static int prl_open_xml(BlockDriverState *bs, QDict *opts, int fl, Error 
**errp)
+{
+    int64_t size;
+    int ret;
+    xmlDoc *doc = NULL;
+    xmlNode *root, *image;
+    char *xml = NULL;
+    const char *data;
+    char image_path[PATH_MAX];
+    Error *local_err = NULL;
+    BDRVPrlXmlState *s = bs->opaque;
+    BlockDriverState *backing_hd = NULL;
+
+    size = bdrv_getlength(bs->file);
+    if (size < 0) {
+        ret = (int)size;
+        goto fail;
+    }
+    /* XML file size should be reasonable */
+    if (size > 65536) {
+        ret = -EFBIG;
+        goto fail;
+    }
+
+    xml = g_malloc(size + 1);
+
+    ret = bdrv_pread(bs->file, 0, xml, size);
+    if (ret != size) {
+        g_free(xml);
+        goto fail;
+    }
+    xml[size] = 0;
+
+    ret = -EINVAL;
+    doc = xmlReadMemory(xml, size, NULL, NULL,
+                        XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
+    g_free(xml);
+    if (doc == NULL) {
+        goto fail;
+    }
+    root = xmlDocGetRootElement(doc);
+    if (root == NULL) {
+        goto fail;
+    }
+
+    data = xml_get_text(root, "Disk_Parameters", "Disk_size", NULL);
+    if (data == NULL) {
+        goto fail;
+    } else {
+        char *endptr;
+        bs->total_sectors = strtoull(data, &endptr, 0);
+        if (*endptr != '\0') {
+            goto fail;
+        }
+    }
+
+    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;
+        }
+
+        size++;
+        data = xml_get_text(image, "Type", NULL);
+        if (data != NULL && strcmp(data, "Compressed")) {
+            error_setg(errp, "Only compressed Parallels images are supported");
+            goto done;
+        }
+
+        data = xml_get_text(image, "File", NULL);
+        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;
+    }
+
+    path_combine(image_path, sizeof(image_path), bs->file->filename, data);
+
+    bs->open_flags &= ~BDRV_O_NO_BACKING;
+
+    fl &= ~(BDRV_O_RDWR | BDRV_O_COPY_ON_READ | BDRV_O_SNAPSHOT |
+            BDRV_O_TEMPORARY);
+    backing_hd = bdrv_new();
+    ret = bdrv_open(&backing_hd, image_path, NULL, NULL,
+                    fl, NULL, &local_err);
+    if (ret < 0) {
+        bdrv_unref(backing_hd);
+        backing_hd = NULL;
+        bs->open_flags |= BDRV_O_NO_BACKING;
+        error_setg(errp, "Could not open backing file: %s",
+                   error_get_pretty(local_err));
+        error_free(local_err);
+        goto done;
+    }
+    bdrv_set_backing_hd(bs, backing_hd);
+
+    s->xml = doc;
+    doc = NULL;
+
+done:
+    if (doc != NULL) {
+        xmlFreeDoc(doc);
+    }
+    return ret;
+
+fail:
+    error_setg(errp, "Failed to parse Parallels disk descriptor XML");
+    goto done;
+}
+
+static coroutine_fn int
+prl_co_read(BlockDriverState *bs, int64_t sect, uint8_t *buf, int n)
+{
+    return bdrv_read(bs->backing_hd, sect, buf, n);
+}
+
+static void prl_close_xml(BlockDriverState *bs)
+{
+    BDRVPrlXmlState *s = bs->opaque;
+    xmlFreeDoc(s->xml);
+}
+
+static BlockDriver bdrv_prl_xml = {
+    .format_name    = "prl",
+    .instance_size  = sizeof(BDRVPrlXmlState),
+    .bdrv_probe     = prl_probe_xml,
+    .bdrv_open      = prl_open_xml,
+    .bdrv_read      = prl_co_read,
+    .bdrv_close     = prl_close_xml,
+    .supports_backing  = true,
+};
+
+static void bdrv_prl_init_xml(void)
+{
+    bdrv_register(&bdrv_prl_xml);
+}
+
+block_init(bdrv_prl_init_xml);
+
+#endif
-- 
1.9.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]