mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-11 03:24:58 -06:00
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>
This commit is contained in:
parent
50ffd8fd3c
commit
74cf6c5026
1 changed files with 97 additions and 0 deletions
|
@ -33,6 +33,9 @@
|
||||||
#define HEADER_MAGIC2 "WithouFreSpacExt"
|
#define HEADER_MAGIC2 "WithouFreSpacExt"
|
||||||
#define HEADER_VERSION 2
|
#define HEADER_VERSION 2
|
||||||
|
|
||||||
|
#define DEFAULT_CLUSTER_SIZE 1048576 /* 1 MiB */
|
||||||
|
|
||||||
|
|
||||||
// always little-endian
|
// always little-endian
|
||||||
typedef struct ParallelsHeader {
|
typedef struct ParallelsHeader {
|
||||||
char magic[16]; // "WithoutFreeSpace"
|
char magic[16]; // "WithoutFreeSpace"
|
||||||
|
@ -317,12 +320,103 @@ static coroutine_fn int parallels_co_readv(BlockDriverState *bs,
|
||||||
return ret;
|
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)
|
static void parallels_close(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
BDRVParallelsState *s = bs->opaque;
|
BDRVParallelsState *s = bs->opaque;
|
||||||
g_free(s->catalog_bitmap);
|
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 = {
|
static BlockDriver bdrv_parallels = {
|
||||||
.format_name = "parallels",
|
.format_name = "parallels",
|
||||||
.instance_size = sizeof(BDRVParallelsState),
|
.instance_size = sizeof(BDRVParallelsState),
|
||||||
|
@ -333,6 +427,9 @@ static BlockDriver bdrv_parallels = {
|
||||||
.bdrv_has_zero_init = bdrv_has_zero_init_1,
|
.bdrv_has_zero_init = bdrv_has_zero_init_1,
|
||||||
.bdrv_co_readv = parallels_co_readv,
|
.bdrv_co_readv = parallels_co_readv,
|
||||||
.bdrv_co_writev = parallels_co_writev,
|
.bdrv_co_writev = parallels_co_writev,
|
||||||
|
|
||||||
|
.bdrv_create = parallels_create,
|
||||||
|
.create_opts = ¶llels_create_opts,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void bdrv_parallels_init(void)
|
static void bdrv_parallels_init(void)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue