diff options
author | Denis V. Lunev <den@openvz.org> | 2015-04-28 10:46:44 +0300 |
---|---|---|
committer | Stefan Hajnoczi <stefanha@redhat.com> | 2015-05-22 09:37:31 +0100 |
commit | 74cf6c5026fef6e327f09786445f626df02cbdf0 (patch) | |
tree | 6e03c4194a6d7795872a5642801eb9b88966a348 /block/parallels.c | |
parent | 50ffd8fd3cfceede87cec1f7f9a04cd7b9147271 (diff) | |
download | qemu-74cf6c5026fef6e327f09786445f626df02cbdf0.tar.gz qemu-74cf6c5026fef6e327f09786445f626df02cbdf0.tar.bz2 qemu-74cf6c5026fef6e327f09786445f626df02cbdf0.zip |
block/parallels: support parallels image creation
Do not even care to create WithoutFreeSpace image, it is obsolete.
Always create WithouFreSpacExt one.
The code also does not spend a lot of efforts to fill cylinders and
heads fields, they are not used actually in a real life neither in
QEMU nor in Parallels products.
Signed-off-by: Denis V. Lunev <den@openvz.org>
Reviewed-by: Roman Kagan <rkagan@parallels.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Roman Kagan <rkagan@parallels.com>
Message-id: 1430207220-24458-12-git-send-email-den@openvz.org
CC: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Diffstat (limited to 'block/parallels.c')
-rw-r--r-- | block/parallels.c | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/block/parallels.c b/block/parallels.c index 8d738033c3..15f6cb32ad 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -33,6 +33,9 @@ #define HEADER_MAGIC2 "WithouFreSpacExt" #define HEADER_VERSION 2 +#define DEFAULT_CLUSTER_SIZE 1048576 /* 1 MiB */ + + // always little-endian typedef struct ParallelsHeader { char magic[16]; // "WithoutFreeSpace" @@ -317,12 +320,103 @@ static coroutine_fn int parallels_co_readv(BlockDriverState *bs, return ret; } +static int parallels_create(const char *filename, QemuOpts *opts, Error **errp) +{ + int64_t total_size, cl_size; + uint8_t tmp[BDRV_SECTOR_SIZE]; + Error *local_err = NULL; + BlockDriverState *file; + uint32_t cat_entries, cat_sectors; + ParallelsHeader header; + int ret; + + total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0), + BDRV_SECTOR_SIZE); + cl_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_CLUSTER_SIZE, + DEFAULT_CLUSTER_SIZE), BDRV_SECTOR_SIZE); + + ret = bdrv_create_file(filename, opts, &local_err); + if (ret < 0) { + error_propagate(errp, local_err); + return ret; + } + + file = NULL; + ret = bdrv_open(&file, filename, NULL, NULL, + BDRV_O_RDWR | BDRV_O_PROTOCOL, NULL, &local_err); + if (ret < 0) { + error_propagate(errp, local_err); + return ret; + } + ret = bdrv_truncate(file, 0); + if (ret < 0) { + goto exit; + } + + cat_entries = DIV_ROUND_UP(total_size, cl_size); + cat_sectors = DIV_ROUND_UP(cat_entries * sizeof(uint32_t) + + sizeof(ParallelsHeader), cl_size); + cat_sectors = (cat_sectors * cl_size) >> BDRV_SECTOR_BITS; + + memset(&header, 0, sizeof(header)); + memcpy(header.magic, HEADER_MAGIC2, sizeof(header.magic)); + header.version = cpu_to_le32(HEADER_VERSION); + /* don't care much about geometry, it is not used on image level */ + header.heads = cpu_to_le32(16); + header.cylinders = cpu_to_le32(total_size / BDRV_SECTOR_SIZE / 16 / 32); + header.tracks = cpu_to_le32(cl_size >> BDRV_SECTOR_BITS); + header.catalog_entries = cpu_to_le32(cat_entries); + header.nb_sectors = cpu_to_le64(DIV_ROUND_UP(total_size, BDRV_SECTOR_SIZE)); + header.data_off = cpu_to_le32(cat_sectors); + + /* write all the data */ + memset(tmp, 0, sizeof(tmp)); + memcpy(tmp, &header, sizeof(header)); + + ret = bdrv_pwrite(file, 0, tmp, BDRV_SECTOR_SIZE); + if (ret < 0) { + goto exit; + } + ret = bdrv_write_zeroes(file, 1, cat_sectors - 1, 0); + if (ret < 0) { + goto exit; + } + ret = 0; + +done: + bdrv_unref(file); + return ret; + +exit: + error_setg_errno(errp, -ret, "Failed to create Parallels image"); + goto done; +} + static void parallels_close(BlockDriverState *bs) { BDRVParallelsState *s = bs->opaque; g_free(s->catalog_bitmap); } +static QemuOptsList parallels_create_opts = { + .name = "parallels-create-opts", + .head = QTAILQ_HEAD_INITIALIZER(parallels_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 image cluster size", + .def_value_str = stringify(DEFAULT_CLUSTER_SIZE), + }, + { /* end of list */ } + } +}; + static BlockDriver bdrv_parallels = { .format_name = "parallels", .instance_size = sizeof(BDRVParallelsState), @@ -333,6 +427,9 @@ static BlockDriver bdrv_parallels = { .bdrv_has_zero_init = bdrv_has_zero_init_1, .bdrv_co_readv = parallels_co_readv, .bdrv_co_writev = parallels_co_writev, + + .bdrv_create = parallels_create, + .create_opts = ¶llels_create_opts, }; static void bdrv_parallels_init(void) |