* [PATCH RFC 0/5] block: implement Parallels Disk format driver
@ 2020-11-13 12:58 Vladimir Sementsov-Ogievskiy
2020-11-13 12:58 ` [PATCH 1/5] block/prl-xml: add Parallels xml BlockDriver Vladimir Sementsov-Ogievskiy
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-11-13 12:58 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-block, den, vsementsov, dautovri
Hi all!
I just send these old patches as they can be useful. I'm not the author
of the code and not going to discuss them. "RFC" is here just to mark
the series as "not-for-applying-to-master". So, please don't answer
here. If you want to continue this work, post v2 first.
Virtuozzo doesn't have plans on improving Parallels disk format
support in Qemu. Still, if someone want to work on it, these patches may
help.
Note that patches don't apply to master, they need a rebase. I've
applied them onto b0292b851b85ba81c0cfedf5b576c32189cfaa11, to run git
send-email. So, you may start from applying to same commit and rebasing
onto current master if you want.
Note also that Edgar and Klim are not in Virtuozzo team for now and
their @virtuozzo.com emails are invalid.
Edgar Kaziakhmedov (1):
iotests: add test for prl-xml format
Klim Kireev (4):
block/prl-xml: add Parallels xml BlockDriver
block/prl-xml: add bdrv_co_readv/writev and flush
block/prl-xml: add bdrv_probe
block/prl-xml: add bdrv_check
block/prl-xml.c | 560 ++++++++++++++++++
block/Makefile.objs | 5 +-
tests/qemu-iotests/164 | 98 +++
tests/qemu-iotests/164.out | 54 ++
tests/qemu-iotests/check | 7 +
tests/qemu-iotests/group | 1 +
.../prl-xml/DiskDescriptor.xml.bz2 | Bin 0 -> 457 bytes
.../sample_images/prl-xml/Snapshots.xml.bz2 | Bin 0 -> 307 bytes
...aabe3-6958-40ff-92a7-860e329aab41}.hds.bz2 | Bin 0 -> 93 bytes
...476cf-d62e-45d1-b355-86feca91376e}.hds.bz2 | Bin 0 -> 93 bytes
10 files changed, 723 insertions(+), 2 deletions(-)
create mode 100644 block/prl-xml.c
create mode 100755 tests/qemu-iotests/164
create mode 100644 tests/qemu-iotests/164.out
create mode 100644 tests/qemu-iotests/sample_images/prl-xml/DiskDescriptor.xml.bz2
create mode 100644 tests/qemu-iotests/sample_images/prl-xml/Snapshots.xml.bz2
create mode 100644 tests/qemu-iotests/sample_images/prl-xml/parallels.{5fbaabe3-6958-40ff-92a7-860e329aab41}.hds.bz2
create mode 100644 tests/qemu-iotests/sample_images/prl-xml/parallels.{986476cf-d62e-45d1-b355-86feca91376e}.hds.bz2
--
2.21.3
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 1/5] block/prl-xml: add Parallels xml BlockDriver
2020-11-13 12:58 [PATCH RFC 0/5] block: implement Parallels Disk format driver Vladimir Sementsov-Ogievskiy
@ 2020-11-13 12:58 ` Vladimir Sementsov-Ogievskiy
2020-11-13 12:58 ` [PATCH 2/5] block/prl-xml: add bdrv_co_readv/writev and flush Vladimir Sementsov-Ogievskiy
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-11-13 12:58 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-block, den, vsementsov, dautovri
From: Klim Kireev <klim.kireev@virtuozzo.com>
This patch introduces new BlockDriver: prl-xml.
It adds opening and closing capabilities.
All operations are performed using libxml2.
Signed-off-by: Klim Kireev <klim.kireev@virtuozzo.com>
---
block/prl-xml.c | 492 ++++++++++++++++++++++++++++++++++++++++++++
block/Makefile.objs | 5 +-
2 files changed, 495 insertions(+), 2 deletions(-)
create mode 100644 block/prl-xml.c
diff --git a/block/prl-xml.c b/block/prl-xml.c
new file mode 100644
index 0000000000..fa9c4fd5fa
--- /dev/null
+++ b/block/prl-xml.c
@@ -0,0 +1,492 @@
+/*
+* Block driver for Parallels disk image format
+* Copyright (c) 2015-2017, Virtuozzo, Inc.
+* Authors:
+* 2016-2017 Klim S. Kireev <klim.kireev@virtuozzo.com>
+* 2015 Denis V. Lunev <den@openvz.org>
+*
+* This code was originally based on comparing different disk images created
+* by Parallels. Currently it is based on opened OpenVZ sources
+* available at
+* https://github.com/OpenVZ/ploop
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+*/
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "block/block_int.h"
+#include "qemu/uuid.h"
+#include "qemu/cutils.h"
+#include "qemu/option.h"
+#include "qapi/qmp/qdict.h"
+
+#include <libxml/parser.h>
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <string.h> /* For basename */
+
+#define DEF_TOP_SNAPSHOT "5fbaabe3-6958-40ff-92a7-860e329aab41"
+#define GUID_LEN strlen(DEF_TOP_SNAPSHOT)
+#define PRL_XML_FILENAME "DiskDescriptor.xml"
+
+typedef struct BDRVPrlXmlState {
+ xmlDoc *xml;
+ BdrvChild *image;
+} BDRVPrlXmlState;
+
+enum TopSnapMode {
+ ERROR_MODE = -1,
+ NODE_MODE,
+ GUID_MODE
+};
+
+static QemuOptsList prl_xml_create_opts = {
+ .name = "prl-xml-create-opts",
+ .head = QTAILQ_HEAD_INITIALIZER(prl_xml_create_opts.head),
+ .desc = {
+ {
+ .name = BLOCK_OPT_SIZE,
+ .type = QEMU_OPT_SIZE,
+ .help = "Virtual disk size",
+ },
+ {
+ .name = BLOCK_OPT_CLUSTER_SIZE,
+ .type = QEMU_OPT_SIZE,
+ .help = "Parallels XML back image cluster size",
+ .def_value_str = stringify(DEFAULT_CLUSTER_SIZE),
+ },
+ { /* end of list */ }
+ }
+};
+
+static xmlNodePtr xml_find_element_child(xmlNodePtr node, const char *elem)
+{
+ xmlNodePtr child;
+
+ for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
+ if (child->type == XML_ELEMENT_NODE &&
+ !xmlStrcmp(child->name, (const xmlChar *)elem))
+ {
+ return child;
+ }
+ }
+ return NULL;
+}
+
+static xmlNodePtr xml_seek_va(xmlNodePtr root, va_list args)
+{
+ const char *elem;
+
+ while ((elem = va_arg(args, const char *)) != NULL) {
+ root = xml_find_element_child(root, elem);
+ if (root == NULL) {
+ return NULL;
+ }
+ }
+ return root;
+}
+
+static xmlNodePtr xml_seek(xmlNodePtr 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(xmlNodePtr node, ...)
+{
+ xmlNodePtr child;
+ va_list args;
+
+ if (node == NULL) {
+ return NULL;
+ }
+
+ 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 inline int get_addr_mode(xmlDocPtr doc)
+{
+ xmlNodePtr root = xmlDocGetRootElement(doc);
+ if (root == NULL) {
+ return ERROR_MODE;
+ }
+
+ xmlNodePtr cur = xml_seek(root, "Snapshots", "TopGUID", NULL);
+ if (cur == NULL) {
+ return GUID_MODE;
+ } else {
+ return NODE_MODE;
+ }
+};
+
+static int xml_check(xmlNodePtr root, Error **errp)
+{
+ xmlNodePtr image;
+ const char *data;
+
+ data = (const char *)xmlGetProp(root, (const xmlChar *)"Version");
+ if (data == NULL) {
+ error_setg(errp, "There is no version attribute in xml root");
+ return -EINVAL;
+ }
+
+ if (strcmp(data, "1.0") != 0) {
+ error_setg(errp, "Format versions differing from 1.0 are unsupported");
+ return -ENOTSUP;
+ }
+
+ image = xml_seek(root, "StorageData", "Storage", "Image", NULL);
+ if (image == NULL) {
+ error_setg(errp, "There is no image nodes in xml");
+ return -EINVAL;
+ }
+ while (image != NULL) {
+ data = ""; /* make gcc happy */
+ if (image->type != XML_ELEMENT_NODE) {
+ image = image->next;
+ continue;
+ }
+
+ data = xml_get_text(image, "Type", NULL);
+ if (data == NULL) {
+ error_setg(errp, "There is no type node in xml");
+ return -EINVAL;
+ }
+
+ if (strcmp(data, "Plain") == 0) {
+ error_setg(errp, "Plain Parallels images are unsupported");
+ return -ENOTSUP;
+ }
+
+ if (strcmp(data, "Compressed") != 0) {
+ error_setg(errp, "Invalid value of type node: %s", data);
+ return -EINVAL;
+ }
+
+ data = xml_get_text(image, "File", NULL);
+ if (data == NULL) {
+ error_setg(errp, "Invalid image xml node");
+ return -EINVAL;
+ }
+ image = image->next;
+ }
+
+ image = xml_seek(root, "Snapshots", "Shot", NULL);
+ if (image == NULL) {
+ error_setg(errp, "There is no snapshots in xml");
+ return -EINVAL;
+ }
+ while (image != NULL) {
+ data = ""; /* make gcc happy */
+ if (image->type != XML_ELEMENT_NODE) {
+ image = image->next;
+ continue;
+ }
+
+ data = xml_get_text(image, "ParentGUID", NULL);
+ if (data == NULL) {
+ error_setg(errp, "There is no ParentGUID node in Snapshot");
+ return -EINVAL;
+ }
+
+ data = xml_get_text(image, "GUID", NULL);
+ if (data == NULL) {
+ error_setg(errp, "There is no GUID node in Snapshot");
+ return -EINVAL;
+ }
+
+ image = image->next;
+ }
+
+ return 0;
+}
+
+static xmlNodePtr uuid_seek(xmlNodePtr node, const char *uuid)
+{
+ while (node != NULL) {
+ const char *cur_uuid;
+ if (node->type != XML_ELEMENT_NODE) {
+ node = node->next;
+ continue;
+ }
+ cur_uuid = xml_get_text(node, "GUID", NULL);
+ if (cur_uuid == NULL) {
+ return NULL;
+ }
+ if (strcmp(uuid, cur_uuid) == 0) {
+ return node;
+ }
+ node = node->next;
+ }
+
+ return NULL;
+}
+
+static xmlNodePtr uuid_image_seek(xmlNodePtr root, const char *uuid)
+{
+ if (uuid == NULL) {
+ return NULL;
+ }
+
+ xmlNodePtr image = xml_seek(root, "StorageData", "Storage", "Image", NULL);
+
+ return uuid_seek(image, uuid);
+}
+
+static xmlNodePtr uuid_snap_seek(xmlNodePtr root, const char *uuid)
+{
+ if (uuid == NULL) {
+ return NULL;
+ }
+
+ xmlNodePtr snap = xml_seek(root, "Snapshots", "Shot", NULL);
+
+ return uuid_seek(snap, uuid);
+}
+
+static inline xmlNodePtr get_parent_snap(xmlNodePtr root, xmlNodePtr snap)
+{
+ const char *uuid = xml_get_text(snap, "ParentGUID", NULL);
+ if (uuid && strcmp(uuid, "{"UUID_NONE"}") == 0) {
+ return NULL;
+ }
+
+ return uuid_snap_seek(root, uuid);
+}
+
+static inline xmlNodePtr snap2image(xmlNodePtr root, xmlNodePtr snap)
+{
+ const char *uuid = xml_get_text(snap, "GUID", NULL);
+ return uuid_image_seek(root, uuid);
+}
+
+static inline xmlNodePtr image2snap(xmlNodePtr root, xmlNodePtr image)
+{
+ const char *uuid = xml_get_text(image, "GUID", NULL);
+ return uuid_snap_seek(root, uuid);
+}
+
+static int snap_open_xml(BlockDriverState *bs, xmlNodePtr snap,
+ QDict *opts, Error **errp)
+{
+ BDRVPrlXmlState *s = bs->opaque;
+ BlockDriverState *last_bs = s->image->bs;
+ int ret = 0;
+ const char *filename = NULL;
+ size_t len = 0;
+ xmlNodePtr root = xmlDocGetRootElement(s->xml);
+ xmlNodePtr image = snap2image(root, snap);
+
+ if (image == NULL) {
+ error_setg(errp, "Incorrent xml");
+ return -EINVAL;
+ }
+ filename = xml_get_text(image, "File", NULL);
+ if (filename == NULL) {
+ error_setg(errp, "Incorrent xml");
+ return -EINVAL;
+ }
+
+ while (last_bs->backing != NULL) {
+ last_bs = last_bs->backing->bs;
+ }
+
+ len = strlen(filename);
+ if (len > sizeof(last_bs->backing_file)) {
+ error_setg(errp, "Incorrent filename %s", filename);
+ return -EINVAL;
+ }
+ pstrcpy(last_bs->backing_file, sizeof(last_bs->backing_file),
+ filename);
+
+ assert(strlen("parallels") < sizeof(last_bs->backing_format));
+ pstrcpy(last_bs->backing_format, sizeof(last_bs->backing_format),
+ "parallels");
+ ret = bdrv_open_backing_file(last_bs, NULL, "backing", errp);
+ return ret;
+}
+
+static int first_open_xml(BlockDriverState *bs, xmlNodePtr snap,
+ QDict *opts, Error **errp)
+{
+ char image_path[PATH_MAX] = {};
+ BDRVPrlXmlState *s = bs->opaque;
+ xmlNodePtr root = xmlDocGetRootElement(s->xml);
+ xmlNodePtr image = snap2image(root, snap);
+ if (image == NULL) {
+ error_setg(errp, "Incorrent xml");
+ return -EINVAL;
+ }
+ const char *filename = xml_get_text(image, "File", NULL);
+ if (s->image != NULL) {
+ return -EINVAL;
+ }
+ path_combine(image_path, sizeof(image_path),
+ bs->filename, filename);
+ qdict_del(opts, "file");
+ s->image = bdrv_open_child(image_path, opts, "image", bs,
+ &child_format, false, errp);
+ if (s->image == NULL) {
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int64_t prl_xml_get_length(xmlNodePtr root)
+{
+ const char *data;
+ int64_t ret;
+
+ data = xml_get_text(root, "Disk_Parameters", "Disk_size", NULL);
+ if (data == NULL) {
+ return -EINVAL;
+ } else {
+ const char *endptr;
+ qemu_strtoi64(data, &endptr, 0, &ret);
+ if (*endptr != '\0') {
+ return -EINVAL;
+ }
+ }
+
+ return ret;
+}
+
+static int prl_open_xml(BlockDriverState *bs, QDict *opts, int flags,
+ Error **errp)
+{
+ int ret = -EINVAL, snap_mode;
+ xmlDoc *doc = NULL;
+ xmlNodePtr root;
+ xmlNodePtr snap;
+ BDRVPrlXmlState *s = bs->opaque;
+
+ if (strcmp(basename(bs->filename), PRL_XML_FILENAME) != 0) {
+ error_setg(errp, "Invalid xml name");
+ goto fail;
+ }
+
+ doc = xmlReadFile(bs->filename, NULL, XML_PARSE_NOERROR |
+ XML_PARSE_NOWARNING);
+
+ if (doc == NULL) {
+ error_setg(errp, "Can't open xml");
+ goto fail;
+ }
+
+ s->xml = doc;
+ root = xmlDocGetRootElement(doc);
+ if (root == NULL) {
+ ret = -EINVAL;
+ error_setg(errp, "Invalid xml");
+ goto fail;
+ }
+
+ ret = xml_check(root, errp);
+ if (ret < 0) {
+ goto fail;
+ }
+
+ bs->total_sectors = prl_xml_get_length(root);
+ if (bs->total_sectors < 0) {
+ ret = -EINVAL;
+ error_setg(errp, "Invalid xml");
+ goto fail;
+ }
+
+ snap_mode = get_addr_mode(doc);
+ if (snap_mode == ERROR_MODE) {
+ ret = -EINVAL;
+ error_setg(errp, "Can't determine an address mode");
+ goto fail;
+ }
+ if (snap_mode == NODE_MODE) {
+ ret = -ENOTSUP;
+ error_setg(errp, "The node addressing mode is unsupported now");
+ goto fail;
+ }
+
+ snap = uuid_snap_seek(root, "{"DEF_TOP_SNAPSHOT"}");
+ if (snap == NULL) {
+ ret = -EINVAL;
+ error_setg(errp, "Can't find top image");
+ goto fail;
+ }
+ ret = first_open_xml(bs, snap, opts, errp);
+ if (ret < 0) {
+ error_append_hint(errp, "Can't open top image\n");
+ goto fail;
+ }
+
+ snap = get_parent_snap(root, snap);
+ while (snap != NULL) {
+ ret = snap_open_xml(bs, snap, opts, errp);
+ if (ret < 0) {
+ error_append_hint(errp, "Can't open image\n");
+ goto fail;
+ }
+ snap = get_parent_snap(root, snap);
+ }
+
+ return 0;
+fail:
+ xmlFreeDoc(doc);
+ return ret;
+}
+
+static void prl_close_xml(BlockDriverState *bs)
+{
+ BDRVPrlXmlState *s = bs->opaque;
+ bdrv_unref_child(bs, s->image);
+ xmlFreeDoc(s->xml);
+}
+
+static BlockDriver bdrv_prl_xml = {
+ .format_name = "prl-xml",
+ .instance_size = sizeof(BDRVPrlXmlState),
+ .bdrv_open = prl_open_xml,
+ .bdrv_close = prl_close_xml,
+ .create_opts = &prl_xml_create_opts,
+ .bdrv_child_perm = bdrv_filter_default_perms,
+ .is_filter = true
+};
+
+static void bdrv_prl_init_xml(void)
+{
+ bdrv_register(&bdrv_prl_xml);
+}
+
+block_init(bdrv_prl_init_xml);
diff --git a/block/Makefile.objs b/block/Makefile.objs
index d644bac60a..df146c77fa 100644
--- a/block/Makefile.objs
+++ b/block/Makefile.objs
@@ -6,6 +6,7 @@ block-obj-y += vhdx.o vhdx-endian.o vhdx-log.o
block-obj-y += quorum.o
block-obj-y += parallels.o blkdebug.o blkverify.o blkreplay.o
block-obj-y += block-backend.o snapshot.o qapi.o
+block-obj-$(CONFIG_LIBXML2) += prl-xml.o
block-obj-$(CONFIG_WIN32) += file-win32.o win32-aio.o
block-obj-$(CONFIG_POSIX) += file-posix.o
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
@@ -48,5 +49,5 @@ block-obj-$(if $(CONFIG_BZIP2),m,n) += dmg-bz2.o
dmg-bz2.o-libs := $(BZIP2_LIBS)
qcow.o-libs := -lz
linux-aio.o-libs := -laio
-parallels.o-cflags := $(LIBXML2_CFLAGS)
-parallels.o-libs := $(LIBXML2_LIBS)
+prl-xml.o-cflags := $(LIBXML2_CFLAGS)
+prl-xml.o-libs := $(LIBXML2_LIBS)
--
2.21.3
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 2/5] block/prl-xml: add bdrv_co_readv/writev and flush
2020-11-13 12:58 [PATCH RFC 0/5] block: implement Parallels Disk format driver Vladimir Sementsov-Ogievskiy
2020-11-13 12:58 ` [PATCH 1/5] block/prl-xml: add Parallels xml BlockDriver Vladimir Sementsov-Ogievskiy
@ 2020-11-13 12:58 ` Vladimir Sementsov-Ogievskiy
2020-11-13 12:58 ` [PATCH 3/5] block/prl-xml: add bdrv_probe Vladimir Sementsov-Ogievskiy
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-11-13 12:58 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-block, den, vsementsov, dautovri
From: Klim Kireev <klim.kireev@virtuozzo.com>
This commit adds bdrv_co_readv, bdrv_co_writev, and bdrv_co_flush_to_os
implementation. It merely passes these functions down
to top BlockDriverState in the snapshot chain.
Signed-off-by: Klim Kireev <klim.kireev@virtuozzo.com>
Signed-off-by: Edgar Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy<vsementsov@virtuozzo.com>
---
block/prl-xml.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/block/prl-xml.c b/block/prl-xml.c
index fa9c4fd5fa..5ab32bb6ab 100644
--- a/block/prl-xml.c
+++ b/block/prl-xml.c
@@ -467,6 +467,22 @@ fail:
return ret;
}
+static coroutine_fn int
+prl_co_readv(BlockDriverState *bs, int64_t sector_num,
+ int nb_sectors, QEMUIOVector *qiov)
+{
+ BDRVPrlXmlState *s = bs->opaque;
+ return bdrv_co_readv(s->image, sector_num, nb_sectors, qiov);
+}
+
+static coroutine_fn int
+prl_co_writev(BlockDriverState *bs, int64_t sector_num,
+ int nb_sectors, QEMUIOVector *qiov)
+{
+ BDRVPrlXmlState *s = bs->opaque;
+ return bdrv_co_writev(s->image, sector_num, nb_sectors, qiov);
+}
+
static void prl_close_xml(BlockDriverState *bs)
{
BDRVPrlXmlState *s = bs->opaque;
@@ -474,11 +490,20 @@ static void prl_close_xml(BlockDriverState *bs)
xmlFreeDoc(s->xml);
}
+static coroutine_fn int prl_co_flush_to_os(BlockDriverState *bs)
+{
+ BDRVPrlXmlState *s = bs->opaque;
+ return bdrv_co_flush(s->image->bs);
+}
+
static BlockDriver bdrv_prl_xml = {
.format_name = "prl-xml",
.instance_size = sizeof(BDRVPrlXmlState),
.bdrv_open = prl_open_xml,
+ .bdrv_co_readv = prl_co_readv,
+ .bdrv_co_writev = prl_co_writev,
.bdrv_close = prl_close_xml,
+ .bdrv_co_flush_to_os = prl_co_flush_to_os,
.create_opts = &prl_xml_create_opts,
.bdrv_child_perm = bdrv_filter_default_perms,
.is_filter = true
--
2.21.3
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 3/5] block/prl-xml: add bdrv_probe
2020-11-13 12:58 [PATCH RFC 0/5] block: implement Parallels Disk format driver Vladimir Sementsov-Ogievskiy
2020-11-13 12:58 ` [PATCH 1/5] block/prl-xml: add Parallels xml BlockDriver Vladimir Sementsov-Ogievskiy
2020-11-13 12:58 ` [PATCH 2/5] block/prl-xml: add bdrv_co_readv/writev and flush Vladimir Sementsov-Ogievskiy
@ 2020-11-13 12:58 ` Vladimir Sementsov-Ogievskiy
2020-11-13 12:58 ` [PATCH 4/5] block/prl-xml: add bdrv_check Vladimir Sementsov-Ogievskiy
2020-11-13 12:58 ` [PATCH 5/5] iotests: add test for prl-xml format Vladimir Sementsov-Ogievskiy
4 siblings, 0 replies; 6+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-11-13 12:58 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-block, den, vsementsov, dautovri
From: Klim Kireev <klim.kireev@virtuozzo.com>
This commit adds bdrv_probe implementation.
It checks the filename (it must be DiskDescriptor.xml).
Then it checks correctness of the xml file using libxml2.
Signed-off-by: Klim Kireev <klim.kireev@virtuozzo.com>
---
block/prl-xml.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/block/prl-xml.c b/block/prl-xml.c
index 5ab32bb6ab..023651342c 100644
--- a/block/prl-xml.c
+++ b/block/prl-xml.c
@@ -467,6 +467,30 @@ fail:
return ret;
}
+static int prl_probe_xml(const uint8_t *data, int buf_size,
+ const char *filename)
+{
+ xmlDoc *doc = NULL;
+ xmlNodePtr root;
+
+ if (strcmp(basename(filename), PRL_XML_FILENAME) != 0) {
+ return 0;
+ }
+
+ doc = xmlReadFile(filename, NULL, XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
+ if (doc == NULL) {
+ return 0;
+ }
+
+ root = xmlDocGetRootElement(doc);
+ if (root == NULL) {
+ return 0;
+ }
+
+ xmlFreeDoc(doc);
+ return 100;
+}
+
static coroutine_fn int
prl_co_readv(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, QEMUIOVector *qiov)
@@ -499,6 +523,7 @@ static coroutine_fn int prl_co_flush_to_os(BlockDriverState *bs)
static BlockDriver bdrv_prl_xml = {
.format_name = "prl-xml",
.instance_size = sizeof(BDRVPrlXmlState),
+ .bdrv_probe = prl_probe_xml,
.bdrv_open = prl_open_xml,
.bdrv_co_readv = prl_co_readv,
.bdrv_co_writev = prl_co_writev,
--
2.21.3
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 4/5] block/prl-xml: add bdrv_check
2020-11-13 12:58 [PATCH RFC 0/5] block: implement Parallels Disk format driver Vladimir Sementsov-Ogievskiy
` (2 preceding siblings ...)
2020-11-13 12:58 ` [PATCH 3/5] block/prl-xml: add bdrv_probe Vladimir Sementsov-Ogievskiy
@ 2020-11-13 12:58 ` Vladimir Sementsov-Ogievskiy
2020-11-13 12:58 ` [PATCH 5/5] iotests: add test for prl-xml format Vladimir Sementsov-Ogievskiy
4 siblings, 0 replies; 6+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-11-13 12:58 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-block, den, vsementsov, dautovri
From: Klim Kireev <klim.kireev@virtuozzo.com>
Add bdrv_check, which just checks child image and all backings.
Signed-off-by: Klim Kireev <klim.kireev@virtuozzo.com>
---
block/prl-xml.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/block/prl-xml.c b/block/prl-xml.c
index 023651342c..736cd98469 100644
--- a/block/prl-xml.c
+++ b/block/prl-xml.c
@@ -520,6 +520,23 @@ static coroutine_fn int prl_co_flush_to_os(BlockDriverState *bs)
return bdrv_co_flush(s->image->bs);
}
+static coroutine_fn int prl_co_check_xml(BlockDriverState *bs,
+ BdrvCheckResult *result,
+ BdrvCheckMode fix) {
+ BDRVPrlXmlState *s = bs->opaque;
+ BdrvChild *cur = s->image;
+ int ret = 0;
+
+ while (cur != NULL && ret >= 0) {
+ if (cur->bs->drv->bdrv_co_check != NULL) {
+ ret = bdrv_check(cur->bs, result, fix);
+ }
+ cur = cur->bs->backing;
+ }
+
+ return ret;
+}
+
static BlockDriver bdrv_prl_xml = {
.format_name = "prl-xml",
.instance_size = sizeof(BDRVPrlXmlState),
@@ -529,6 +546,7 @@ static BlockDriver bdrv_prl_xml = {
.bdrv_co_writev = prl_co_writev,
.bdrv_close = prl_close_xml,
.bdrv_co_flush_to_os = prl_co_flush_to_os,
+ .bdrv_co_check = prl_co_check_xml,
.create_opts = &prl_xml_create_opts,
.bdrv_child_perm = bdrv_filter_default_perms,
.is_filter = true
--
2.21.3
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 5/5] iotests: add test for prl-xml format
2020-11-13 12:58 [PATCH RFC 0/5] block: implement Parallels Disk format driver Vladimir Sementsov-Ogievskiy
` (3 preceding siblings ...)
2020-11-13 12:58 ` [PATCH 4/5] block/prl-xml: add bdrv_check Vladimir Sementsov-Ogievskiy
@ 2020-11-13 12:58 ` Vladimir Sementsov-Ogievskiy
4 siblings, 0 replies; 6+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-11-13 12:58 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-block, den, vsementsov, dautovri
From: Edgar Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.com>
Signed-off-by: Edgar Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
---
tests/qemu-iotests/164 | 98 ++++++++++++++++++
tests/qemu-iotests/164.out | 54 ++++++++++
tests/qemu-iotests/check | 7 ++
tests/qemu-iotests/group | 1 +
.../prl-xml/DiskDescriptor.xml.bz2 | Bin 0 -> 457 bytes
.../sample_images/prl-xml/Snapshots.xml.bz2 | Bin 0 -> 307 bytes
...aabe3-6958-40ff-92a7-860e329aab41}.hds.bz2 | Bin 0 -> 93 bytes
...476cf-d62e-45d1-b355-86feca91376e}.hds.bz2 | Bin 0 -> 93 bytes
8 files changed, 160 insertions(+)
create mode 100755 tests/qemu-iotests/164
create mode 100644 tests/qemu-iotests/164.out
create mode 100644 tests/qemu-iotests/sample_images/prl-xml/DiskDescriptor.xml.bz2
create mode 100644 tests/qemu-iotests/sample_images/prl-xml/Snapshots.xml.bz2
create mode 100644 tests/qemu-iotests/sample_images/prl-xml/parallels.{5fbaabe3-6958-40ff-92a7-860e329aab41}.hds.bz2
create mode 100644 tests/qemu-iotests/sample_images/prl-xml/parallels.{986476cf-d62e-45d1-b355-86feca91376e}.hds.bz2
diff --git a/tests/qemu-iotests/164 b/tests/qemu-iotests/164
new file mode 100755
index 0000000000..a55ab5d7d8
--- /dev/null
+++ b/tests/qemu-iotests/164
@@ -0,0 +1,98 @@
+#!/bin/bash
+#
+# prl-xml format validation test
+#
+# Copyright (C) 2017 Edgar Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=edgar.kaziakhmedov@virtuozzo.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+status=1 # failure is the default!
+
+_cleanup()
+{
+ _rm_test_img "$TEST_DIR/$PRL_XML_DIR/$CUR_IMAGE"
+ _rm_test_img "$TEST_DIR/$PRL_XML_DIR/$BACK_IMAGE"
+ _rm_test_img "$TEST_DIR/$PRL_XML_DIR/$SNAP_LIST"
+ _cleanup_test_img
+ rmdir "$TEST_DIR/$PRL_XML_DIR"
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt prl-xml
+_supported_proto file
+_supported_os Linux
+
+inuse_offset=$((0x2c))
+
+PRL_XML_DIR="prl-xml"
+mkdir "$TEST_DIR/$PRL_XML_DIR"
+CUR_IMAGE="parallels.{5fbaabe3-6958-40ff-92a7-860e329aab41}.hds"
+BACK_IMAGE="parallels.{986476cf-d62e-45d1-b355-86feca91376e}.hds"
+SNAP_LIST="Snapshots.xml"
+XML_IMG="DiskDescriptor.xml"
+size=128M
+CLUSTER_SIZE=64k
+IMGFMT=prl-xml
+_use_sample_img "$PRL_XML_DIR/$CUR_IMAGE.bz2"
+_use_sample_img "$PRL_XML_DIR/$BACK_IMAGE.bz2"
+_use_sample_img "$PRL_XML_DIR/$SNAP_LIST.bz2"
+_use_sample_img "$PRL_XML_DIR/$XML_IMG.bz2"
+
+echo == read empty image ==
+{ $QEMU_IO -c "read -P 0 32k 64k" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
+echo == write more than 1 block in a row ==
+{ $QEMU_IO -c "write -P 0x11 32k 128k" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
+echo == read less than block ==
+{ $QEMU_IO -c "read -P 0x69 32k 32k" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
+echo == read exactly 1 block ==
+{ $QEMU_IO -c "read -P 0x69 64k 64k" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
+echo == read more than 1 block ==
+{ $QEMU_IO -c "read -P 0x69 32k 128k" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
+echo == check that there is no trash after written ==
+{ $QEMU_IO -c "read -P 0 160k 32k" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
+echo == check that there is no trash before written ==
+{ $QEMU_IO -c "read -P 0 0 32k" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
+echo == write the whole disk ==
+{ $QEMU_IO -c "write -P 0x45 0 2M" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
+echo == read the whole disk ==
+{ $QEMU_IO -c "read -P 0x45 0 2M" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
+echo == check that there is error while write out of range ==
+{ $QEMU_IO -c "write -P 0 2M 32k" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
+echo == check that there is error while disk size is less than data written ==
+{ $QEMU_IO -c "write -P 0x45 0 3M" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
+
+echo "== Corrupt image =="
+poke_file "$TEST_DIR/$PRL_XML_DIR/$CUR_IMAGE" "$inuse_offset" "\x59\x6e\x6f\x74"
+{ $QEMU_IO -c "read -P 0x11 64k 64k" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
+# as it is a block filter, we change driver format
+_check_test_img
+_check_test_img -r all
+{ $QEMU_IO -c "read -P 0x11 64k 64k" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/164.out b/tests/qemu-iotests/164.out
new file mode 100644
index 0000000000..777c0c2c1c
--- /dev/null
+++ b/tests/qemu-iotests/164.out
@@ -0,0 +1,54 @@
+QA output created by 164
+== read empty image ==
+read 65536/65536 bytes at offset 32768
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+== write more than 1 block in a row ==
+wrote 131072/131072 bytes at offset 32768
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+== read less than block ==
+Pattern verification failed at offset 32768, 32768 bytes
+read 32768/32768 bytes at offset 32768
+32 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+== read exactly 1 block ==
+Pattern verification failed at offset 65536, 65536 bytes
+read 65536/65536 bytes at offset 65536
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+== read more than 1 block ==
+Pattern verification failed at offset 32768, 131072 bytes
+read 131072/131072 bytes at offset 32768
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+== check that there is no trash after written ==
+read 32768/32768 bytes at offset 163840
+32 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+== check that there is no trash before written ==
+read 32768/32768 bytes at offset 0
+32 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+== write the whole disk ==
+wrote 2097152/2097152 bytes at offset 0
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+== read the whole disk ==
+read 2097152/2097152 bytes at offset 0
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+== check that there is error while write out of range ==
+write failed: Input/output error
+== check that there is error while disk size is less than data written ==
+write failed: Input/output error
+== Corrupt image ==
+can't open device TEST_DIR/prl-xml/DiskDescriptor.xml: parallels: Image was not closed correctly; cannot be opened read/write
+Can't open top image
+ERROR image was not closed correctly
+
+1 errors were found on the image.
+Data may be corrupted, or further writes to the image may corrupt it.
+Repairing image was not closed correctly
+The following inconsistencies were found and repaired:
+
+ 0 leaked clusters
+ 1 corruptions
+
+Double checking the fixed image now...
+No errors were found on the image.
+Pattern verification failed at offset 65536, 65536 bytes
+read 65536/65536 bytes at offset 65536
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+*** done
diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
index e6b6ff7a04..0a87c8d840 100755
--- a/tests/qemu-iotests/check
+++ b/tests/qemu-iotests/check
@@ -229,6 +229,7 @@ image format options
-bochs test bochs
-cloop test cloop
-parallels test parallels
+ -prl-xml test prl-xml
-qcow test qcow
-qcow2 test qcow2
-qed test qed
@@ -288,6 +289,12 @@ testlist options
xpand=false
;;
+ -prl-xml)
+ IMGFMT=prl-xml
+ IMGFMT_GENERIC=false
+ xpand=false
+ ;;
+
-qcow)
IMGFMT=qcow
xpand=false
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index a2dfe79d86..d22853fed6 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -168,6 +168,7 @@
160 rw auto quick
162 auto quick
163 rw auto quick
+164 rw auto quick
165 rw auto quick
170 rw auto quick
171 rw auto quick
diff --git a/tests/qemu-iotests/sample_images/prl-xml/DiskDescriptor.xml.bz2 b/tests/qemu-iotests/sample_images/prl-xml/DiskDescriptor.xml.bz2
new file mode 100644
index 0000000000000000000000000000000000000000..08dad3b4a9c980e931bc0b1d128bf931754a0730
GIT binary patch
literal 457
zcmV;)0XF_ZT4*^jL0KkKSrF;;(*OYXUw}kZPy_$xpWsgbzwh08Kmq%XS_EJK00000
z00050<x}*N)Bpg{pa1{>0FhFe>Y92HlRY3t1k)x7iM22Qsv;FVpa3SCYG^bXG{_8|
zrfN!{Cd7v_5J(9M0s}_dWC~Q2$^q`CQ9GkqB)PntA`y-oQij;)JNjE(B9Y*5aV@eZ
zNm#hli#yE)7^1NyrcFiV@r278BPk{EYaYR2-xv$bF@i7>S(f6lk}@&{M@|-=EDInh
z1TQdzVh>8Vid!*P!6c*$Ae_l29fvPb-K|eJV1RjPLW4O6g5X2eSUs4Sk}gILzRBoP
zpHePXvokW4>Jvg~PXZ{SSoaK&ZH+Ou+Zm`9dCH>;i})omFSQhX*`7S5GZHtsEf=>w
z1@YYz7*4~Ij?&_cOOoQ={;YNEHAluO=lD$;(-cuvUM(k+scFz|XL9qg!Mwv9P4QDi
zZfryL&S!Erw6rX7Q7R#ko6NZ8#&UYgdr7g++-G_%Jw_LzuB3a>_GL3NF_MS1iYl0^
z6I+QmlSNwC6>a&aGBB|%l=PU|mZaQ)`TG;NQwaRAwJ&DIPvBk26yZWZL#NYBA5X_~
literal 0
HcmV?d00001
diff --git a/tests/qemu-iotests/sample_images/prl-xml/Snapshots.xml.bz2 b/tests/qemu-iotests/sample_images/prl-xml/Snapshots.xml.bz2
new file mode 100644
index 0000000000000000000000000000000000000000..b5d80ae94d4500b1b19f3439dc5e953383797c6f
GIT binary patch
literal 307
zcmV-30nGkFT4*^jL0KkKSxpAo!2keSUw}kVa0CDMtRYMaKj+`dFaafl45Vb#^oG(j
z!Ww#j1Juv}&}yEUO*J$z4FF*QqfCtlsip-~(t(pxG&KMKXlV5qfO$lMX&?jw2v8-q
z1`8?>TaY|qfYis;LeUupdT2xBtur^&?vpdx7R17+oiv%}2wGIw-)zxJLr_^;oRJC4
z2#6Ap!Nu!vRP96>_M1>58rRKl2SU7pU?xx5wYliRwKUL%LTSn&49HEuR+X$}sk5@T
z=xr(7)RvMJ8`AEc%m$-oFQzoR=yQk}&wu2md@z{{n6N7=p=AGC+I1H@3>iwz8Wyyr
zWa1$U^GSrJhB+xNlJ>S-MI_qG1yW`~MP9ZklRCtzNpT7YFCZ1HaF+M+cO+AV2?Wq>
FtPtE<hb{mB
literal 0
HcmV?d00001
diff --git a/tests/qemu-iotests/sample_images/prl-xml/parallels.{5fbaabe3-6958-40ff-92a7-860e329aab41}.hds.bz2 b/tests/qemu-iotests/sample_images/prl-xml/parallels.{5fbaabe3-6958-40ff-92a7-860e329aab41}.hds.bz2
new file mode 100644
index 0000000000000000000000000000000000000000..174c8ba055fc1a24b91f179670fd15b53e00efdd
GIT binary patch
literal 93
zcmV-j0HXgwT4*^jL0KkKS=)oU7yuwJ=Yr6{KmY>(2!JYJ)<6It00<xeR3$(r5vF9&
zDv_iB08MQ#q9On-S)$Yk0W=~I07sO2y<D>Emf9jW8MFZ406H$@ig2MJw+D1EabX`c
literal 0
HcmV?d00001
diff --git a/tests/qemu-iotests/sample_images/prl-xml/parallels.{986476cf-d62e-45d1-b355-86feca91376e}.hds.bz2 b/tests/qemu-iotests/sample_images/prl-xml/parallels.{986476cf-d62e-45d1-b355-86feca91376e}.hds.bz2
new file mode 100644
index 0000000000000000000000000000000000000000..174c8ba055fc1a24b91f179670fd15b53e00efdd
GIT binary patch
literal 93
zcmV-j0HXgwT4*^jL0KkKS=)oU7yuwJ=Yr6{KmY>(2!JYJ)<6It00<xeR3$(r5vF9&
zDv_iB08MQ#q9On-S)$Yk0W=~I07sO2y<D>Emf9jW8MFZ406H$@ig2MJw+D1EabX`c
literal 0
HcmV?d00001
--
2.21.3
^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2020-11-13 13:17 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-11-13 12:58 [PATCH RFC 0/5] block: implement Parallels Disk format driver Vladimir Sementsov-Ogievskiy
2020-11-13 12:58 ` [PATCH 1/5] block/prl-xml: add Parallels xml BlockDriver Vladimir Sementsov-Ogievskiy
2020-11-13 12:58 ` [PATCH 2/5] block/prl-xml: add bdrv_co_readv/writev and flush Vladimir Sementsov-Ogievskiy
2020-11-13 12:58 ` [PATCH 3/5] block/prl-xml: add bdrv_probe Vladimir Sementsov-Ogievskiy
2020-11-13 12:58 ` [PATCH 4/5] block/prl-xml: add bdrv_check Vladimir Sementsov-Ogievskiy
2020-11-13 12:58 ` [PATCH 5/5] iotests: add test for prl-xml format Vladimir Sementsov-Ogievskiy
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).