[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
- [Qemu-devel] [PATCH 16/16] iotests: testcase parallels image with snapshots, (continued)
- [Qemu-devel] [PATCH 16/16] iotests: testcase parallels image with snapshots, Denis V. Lunev, 2014/12/15
- [Qemu-devel] [PATCH 02/16] block/parallels: allow to specify DiskDescriptor.xml instead of image file, Denis V. Lunev, 2014/12/15
- [Qemu-devel] [PATCH 15/16] block/parallels: support read-only parallels snapshots, Denis V. Lunev, 2014/12/15
- [Qemu-devel] [PATCH 13/16] block/parallels: read disk size from XML if DiskDescriptor.xml is passed, Denis V. Lunev, 2014/12/15
- [Qemu-devel] [PATCH 14/16] block/parallels: introduce ParallelsSnapshot data structure, Denis V. Lunev, 2014/12/15
- [Qemu-devel] [PATCH 11/16] block/parallels: add support for backing files, Denis V. Lunev, 2014/12/15
- [Qemu-devel] [PATCH 10/16] block/parallels: add get_block_status, Denis V. Lunev, 2014/12/15
- [Qemu-devel] [PATCH 09/16] block/parallels: read up to cluster end in one go, Denis V. Lunev, 2014/12/15
- [Qemu-devel] [PATCH 12/16] iotests: testcase for backing in parallels format, Denis V. Lunev, 2014/12/15
- [Qemu-devel] [PATCH 08/16] block/parallels: switch to bdrv_read, Denis V. Lunev, 2014/12/15
- [Qemu-devel] [PATCH 01/16] configure: add dependency from libxml2, Denis V. Lunev, 2014/12/15