X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=block%2Fvdi.c;h=b9845a4cbded0a27d70101461e8da05a188a971a;hb=c4107e8208d0222f9b328691b519aaee4101db87;hp=d939b034c4e34a95debb869243774af9dd4c97c7;hpb=da23248f272bcb8d4fa75c994110d4366ccceb97;p=mirror_qemu.git diff --git a/block/vdi.c b/block/vdi.c index d939b034c4..b9845a4cbd 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -50,11 +50,12 @@ */ #include "qemu/osdep.h" +#include "qemu/units.h" #include "qapi/error.h" -#include "qapi/qmp/qdict.h" #include "qapi/qobject-input-visitor.h" #include "qapi/qapi-visit-block-core.h" #include "block/block_int.h" +#include "block/qdict.h" #include "sysemu/block-backend.h" #include "qemu/module.h" #include "qemu/option.h" @@ -83,11 +84,9 @@ /* Command line option for static images. */ #define BLOCK_OPT_STATIC "static" -#define KiB 1024 -#define MiB (KiB * KiB) - #define SECTOR_SIZE 512 -#define DEFAULT_CLUSTER_SIZE (1 * MiB) +#define DEFAULT_CLUSTER_SIZE 1048576 +/* Note: can't use 1 * MiB, because it's passed to stringify() */ #if defined(CONFIG_VDI_DEBUG) #define VDI_DEBUG 1 @@ -172,6 +171,8 @@ typedef struct { uint64_t unused2[7]; } QEMU_PACKED VdiHeader; +QEMU_BUILD_BUG_ON(sizeof(VdiHeader) != 512); + typedef struct { /* The block map entries are little endian (even in memory). */ uint32_t *bmap; @@ -189,56 +190,56 @@ typedef struct { static void vdi_header_to_cpu(VdiHeader *header) { - le32_to_cpus(&header->signature); - le32_to_cpus(&header->version); - le32_to_cpus(&header->header_size); - le32_to_cpus(&header->image_type); - le32_to_cpus(&header->image_flags); - le32_to_cpus(&header->offset_bmap); - le32_to_cpus(&header->offset_data); - le32_to_cpus(&header->cylinders); - le32_to_cpus(&header->heads); - le32_to_cpus(&header->sectors); - le32_to_cpus(&header->sector_size); - le64_to_cpus(&header->disk_size); - le32_to_cpus(&header->block_size); - le32_to_cpus(&header->block_extra); - le32_to_cpus(&header->blocks_in_image); - le32_to_cpus(&header->blocks_allocated); - qemu_uuid_bswap(&header->uuid_image); - qemu_uuid_bswap(&header->uuid_last_snap); - qemu_uuid_bswap(&header->uuid_link); - qemu_uuid_bswap(&header->uuid_parent); + header->signature = le32_to_cpu(header->signature); + header->version = le32_to_cpu(header->version); + header->header_size = le32_to_cpu(header->header_size); + header->image_type = le32_to_cpu(header->image_type); + header->image_flags = le32_to_cpu(header->image_flags); + header->offset_bmap = le32_to_cpu(header->offset_bmap); + header->offset_data = le32_to_cpu(header->offset_data); + header->cylinders = le32_to_cpu(header->cylinders); + header->heads = le32_to_cpu(header->heads); + header->sectors = le32_to_cpu(header->sectors); + header->sector_size = le32_to_cpu(header->sector_size); + header->disk_size = le64_to_cpu(header->disk_size); + header->block_size = le32_to_cpu(header->block_size); + header->block_extra = le32_to_cpu(header->block_extra); + header->blocks_in_image = le32_to_cpu(header->blocks_in_image); + header->blocks_allocated = le32_to_cpu(header->blocks_allocated); + header->uuid_image = qemu_uuid_bswap(header->uuid_image); + header->uuid_last_snap = qemu_uuid_bswap(header->uuid_last_snap); + header->uuid_link = qemu_uuid_bswap(header->uuid_link); + header->uuid_parent = qemu_uuid_bswap(header->uuid_parent); } static void vdi_header_to_le(VdiHeader *header) { - cpu_to_le32s(&header->signature); - cpu_to_le32s(&header->version); - cpu_to_le32s(&header->header_size); - cpu_to_le32s(&header->image_type); - cpu_to_le32s(&header->image_flags); - cpu_to_le32s(&header->offset_bmap); - cpu_to_le32s(&header->offset_data); - cpu_to_le32s(&header->cylinders); - cpu_to_le32s(&header->heads); - cpu_to_le32s(&header->sectors); - cpu_to_le32s(&header->sector_size); - cpu_to_le64s(&header->disk_size); - cpu_to_le32s(&header->block_size); - cpu_to_le32s(&header->block_extra); - cpu_to_le32s(&header->blocks_in_image); - cpu_to_le32s(&header->blocks_allocated); - qemu_uuid_bswap(&header->uuid_image); - qemu_uuid_bswap(&header->uuid_last_snap); - qemu_uuid_bswap(&header->uuid_link); - qemu_uuid_bswap(&header->uuid_parent); + header->signature = cpu_to_le32(header->signature); + header->version = cpu_to_le32(header->version); + header->header_size = cpu_to_le32(header->header_size); + header->image_type = cpu_to_le32(header->image_type); + header->image_flags = cpu_to_le32(header->image_flags); + header->offset_bmap = cpu_to_le32(header->offset_bmap); + header->offset_data = cpu_to_le32(header->offset_data); + header->cylinders = cpu_to_le32(header->cylinders); + header->heads = cpu_to_le32(header->heads); + header->sectors = cpu_to_le32(header->sectors); + header->sector_size = cpu_to_le32(header->sector_size); + header->disk_size = cpu_to_le64(header->disk_size); + header->block_size = cpu_to_le32(header->block_size); + header->block_extra = cpu_to_le32(header->block_extra); + header->blocks_in_image = cpu_to_le32(header->blocks_in_image); + header->blocks_allocated = cpu_to_le32(header->blocks_allocated); + header->uuid_image = qemu_uuid_bswap(header->uuid_image); + header->uuid_last_snap = qemu_uuid_bswap(header->uuid_last_snap); + header->uuid_link = qemu_uuid_bswap(header->uuid_link); + header->uuid_parent = qemu_uuid_bswap(header->uuid_parent); } -#if defined(CONFIG_VDI_DEBUG) static void vdi_header_print(VdiHeader *header) { - char uuid[37]; + char uuidstr[37]; + QemuUUID uuid; logout("text %s", header->text); logout("signature 0x%08x\n", header->signature); logout("header size 0x%04x\n", header->header_size); @@ -257,16 +258,19 @@ static void vdi_header_print(VdiHeader *header) logout("block extra 0x%04x\n", header->block_extra); logout("blocks tot. 0x%04x\n", header->blocks_in_image); logout("blocks all. 0x%04x\n", header->blocks_allocated); - uuid_unparse(header->uuid_image, uuid); - logout("uuid image %s\n", uuid); - uuid_unparse(header->uuid_last_snap, uuid); - logout("uuid snap %s\n", uuid); - uuid_unparse(header->uuid_link, uuid); - logout("uuid link %s\n", uuid); - uuid_unparse(header->uuid_parent, uuid); - logout("uuid parent %s\n", uuid); + uuid = header->uuid_image; + qemu_uuid_unparse(&uuid, uuidstr); + logout("uuid image %s\n", uuidstr); + uuid = header->uuid_last_snap; + qemu_uuid_unparse(&uuid, uuidstr); + logout("uuid snap %s\n", uuidstr); + uuid = header->uuid_link; + qemu_uuid_unparse(&uuid, uuidstr); + logout("uuid link %s\n", uuidstr); + uuid = header->uuid_parent; + qemu_uuid_unparse(&uuid, uuidstr); + logout("uuid parent %s\n", uuidstr); } -#endif static int coroutine_fn vdi_co_check(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix) @@ -372,6 +376,7 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags, size_t bmap_size; int ret; Error *local_err = NULL; + QemuUUID uuid_link, uuid_parent; bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, false, errp); @@ -381,15 +386,15 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags, logout("\n"); - ret = bdrv_read(bs->file, 0, (uint8_t *)&header, 1); + ret = bdrv_pread(bs->file, 0, &header, sizeof(header)); if (ret < 0) { goto fail; } vdi_header_to_cpu(&header); -#if defined(CONFIG_VDI_DEBUG) - vdi_header_print(&header); -#endif + if (VDI_DEBUG) { + vdi_header_print(&header); + } if (header.disk_size > VDI_DISK_SIZE_MAX) { error_setg(errp, "Unsupported VDI image size (size is 0x%" PRIx64 @@ -399,6 +404,9 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags, goto fail; } + uuid_link = header.uuid_link; + uuid_parent = header.uuid_parent; + if (header.disk_size % SECTOR_SIZE != 0) { /* 'VBoxManage convertfromraw' can create images with odd disk sizes. We accept them but round the disk size to the next multiple of @@ -436,7 +444,8 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags, goto fail; } else if (header.block_size != DEFAULT_CLUSTER_SIZE) { error_setg(errp, "unsupported VDI image (block size %" PRIu32 - " is not %u)", header.block_size, DEFAULT_CLUSTER_SIZE); + " is not %" PRIu32 ")", + header.block_size, DEFAULT_CLUSTER_SIZE); ret = -ENOTSUP; goto fail; } else if (header.disk_size > @@ -447,11 +456,11 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags, (uint64_t)header.blocks_in_image * header.block_size); ret = -ENOTSUP; goto fail; - } else if (!qemu_uuid_is_null(&header.uuid_link)) { + } else if (!qemu_uuid_is_null(&uuid_link)) { error_setg(errp, "unsupported VDI image (non-NULL link UUID)"); ret = -ENOTSUP; goto fail; - } else if (!qemu_uuid_is_null(&header.uuid_parent)) { + } else if (!qemu_uuid_is_null(&uuid_parent)) { error_setg(errp, "unsupported VDI image (non-NULL parent UUID)"); ret = -ENOTSUP; goto fail; @@ -477,8 +486,8 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags, goto fail; } - ret = bdrv_read(bs->file, s->bmap_sector, (uint8_t *)s->bmap, - bmap_size); + ret = bdrv_pread(bs->file, header.offset_bmap, s->bmap, + bmap_size * SECTOR_SIZE); if (ret < 0) { goto fail_free_bmap; } @@ -697,7 +706,7 @@ nonallocating_write: assert(VDI_IS_ALLOCATED(bmap_first)); *header = s->header; vdi_header_to_le(header); - ret = bdrv_write(bs->file, 0, block, 1); + ret = bdrv_pwrite(bs->file, 0, block, sizeof(VdiHeader)); g_free(block); block = NULL; @@ -715,10 +724,11 @@ nonallocating_write: base = ((uint8_t *)&s->bmap[0]) + bmap_first * SECTOR_SIZE; logout("will write %u block map sectors starting from entry %u\n", n_sectors, bmap_first); - ret = bdrv_write(bs->file, offset, base, n_sectors); + ret = bdrv_pwrite(bs->file, offset * SECTOR_SIZE, base, + n_sectors * SECTOR_SIZE); } - return ret; + return ret < 0 ? ret : 0; } static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options, @@ -728,7 +738,7 @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options, int ret = 0; uint64_t bytes = 0; uint32_t blocks; - uint32_t image_type = VDI_TYPE_DYNAMIC; + uint32_t image_type; VdiHeader header; size_t i; size_t bmap_size; @@ -736,6 +746,7 @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options, BlockDriverState *bs_file = NULL; BlockBackend *blk = NULL; uint32_t *bmap = NULL; + QemuUUID uuid; assert(create_options->driver == BLOCKDEV_DRIVER_VDI); vdi_opts = &create_options->u.vdi; @@ -744,9 +755,22 @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options, /* Validate options and set default values */ bytes = vdi_opts->size; - if (vdi_opts->q_static) { + + if (!vdi_opts->has_preallocation) { + vdi_opts->preallocation = PREALLOC_MODE_OFF; + } + switch (vdi_opts->preallocation) { + case PREALLOC_MODE_OFF: + image_type = VDI_TYPE_DYNAMIC; + break; + case PREALLOC_MODE_METADATA: image_type = VDI_TYPE_STATIC; + break; + default: + error_setg(errp, "Preallocation mode not supported for vdi"); + return -EINVAL; } + #ifndef CONFIG_VDI_STATIC_IMAGE if (image_type == VDI_TYPE_STATIC) { ret = -ENOTSUP; @@ -779,7 +803,8 @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options, goto exit; } - blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL); + blk = blk_new(bdrv_get_aio_context(bs_file), + BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL); ret = blk_insert_bs(blk, bs_file, errp); if (ret < 0) { goto exit; @@ -809,12 +834,14 @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options, if (image_type == VDI_TYPE_STATIC) { header.blocks_allocated = blocks; } - qemu_uuid_generate(&header.uuid_image); - qemu_uuid_generate(&header.uuid_last_snap); + qemu_uuid_generate(&uuid); + header.uuid_image = uuid; + qemu_uuid_generate(&uuid); + header.uuid_last_snap = uuid; /* There is no need to set header.uuid_link or header.uuid_parent here. */ -#if defined(CONFIG_VDI_DEBUG) - vdi_header_print(&header); -#endif + if (VDI_DEBUG) { + vdi_header_print(&header); + } vdi_header_to_le(&header); ret = blk_pwrite(blk, offset, &header, sizeof(header), 0); if (ret < 0) { @@ -854,6 +881,7 @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options, } } + ret = 0; exit: blk_unref(blk); bdrv_unref(bs_file); @@ -874,6 +902,7 @@ static int coroutine_fn vdi_co_create_opts(const char *filename, QemuOpts *opts, BlockdevCreateOptions *create_options = NULL; BlockDriverState *bs_file = NULL; uint64_t block_size = DEFAULT_CLUSTER_SIZE; + bool is_static = false; Visitor *v; Error *local_err = NULL; int ret; @@ -895,6 +924,9 @@ static int coroutine_fn vdi_co_create_opts(const char *filename, QemuOpts *opts, goto done; } #endif + if (qemu_opt_get_bool_del(opts, BLOCK_OPT_STATIC, false)) { + is_static = true; + } qdict = qemu_opts_to_qdict_filtered(opts, NULL, &vdi_create_opts, true); @@ -913,9 +945,16 @@ static int coroutine_fn vdi_co_create_opts(const char *filename, QemuOpts *opts, qdict_put_str(qdict, "driver", "vdi"); qdict_put_str(qdict, "file", bs_file->node_name); + if (is_static) { + qdict_put_str(qdict, "preallocation", "metadata"); + } /* Get the QAPI object */ - v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); + v = qobject_input_visitor_new_flat_confused(qdict, errp); + if (!v) { + ret = -EINVAL; + goto done; + } visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err); visit_free(v); @@ -933,7 +972,7 @@ static int coroutine_fn vdi_co_create_opts(const char *filename, QemuOpts *opts, /* Create the vdi image (format layer) */ ret = vdi_co_do_create(create_options, block_size, errp); done: - QDECREF(qdict); + qobject_unref(qdict); qapi_free_BlockdevCreateOptions(create_options); bdrv_unref(bs_file); return ret;