Lines Matching +full:- +full:- +full:disable +full:- +full:live +full:- +full:block +full:- +full:migration
2 * Block driver for the Virtual Disk Image (VDI) format
6 * SPDX-License-Identifier: GPL-2.0-or-later
30 * Deallocation of zero-filled blocks and shrinking images are missing, too
31 * (might be added to common block layer).
33 * Allocation of blocks could be optimized (less writes to block map and
37 * (current code uses one operation per block (1 MiB).
40 * block table, no problem with current QEMU).
49 * The driver keeps a block cache (little endian entries) in memory.
50 * For the standard block size (1 MiB), a 1 TiB disk will use 4 MiB RAM,
57 #include "qapi/qobject-input-visitor.h"
58 #include "qapi/qapi-visit-block-core.h"
59 #include "block/block_int.h"
60 #include "block/qdict.h"
61 #include "system/block-backend.h"
65 #include "migration/blocker.h"
79 /* Support non-standard block (cluster) size. This is untested.
84 /* Support static (fixed, pre-allocated) images. */
103 fprintf(stderr, "vdi\t%-24s" fmt, __func__, ##__VA_ARGS__); \
125 /* A never-allocated block; semantically arbitrary content. */
128 /* A discarded (no longer allocated) block; semantically zero-filled. */
144 ((unsigned)((INT_MAX + 1u - BDRV_SECTOR_SIZE) / sizeof(uint32_t)))
180 /* The block map entries are little endian (even in memory). */
182 /* Size of block (bytes). */
184 /* First sector of block map. */
196 header->signature = le32_to_cpu(header->signature); in vdi_header_to_cpu()
197 header->version = le32_to_cpu(header->version); in vdi_header_to_cpu()
198 header->header_size = le32_to_cpu(header->header_size); in vdi_header_to_cpu()
199 header->image_type = le32_to_cpu(header->image_type); in vdi_header_to_cpu()
200 header->image_flags = le32_to_cpu(header->image_flags); in vdi_header_to_cpu()
201 header->offset_bmap = le32_to_cpu(header->offset_bmap); in vdi_header_to_cpu()
202 header->offset_data = le32_to_cpu(header->offset_data); in vdi_header_to_cpu()
203 header->cylinders = le32_to_cpu(header->cylinders); in vdi_header_to_cpu()
204 header->heads = le32_to_cpu(header->heads); in vdi_header_to_cpu()
205 header->sectors = le32_to_cpu(header->sectors); in vdi_header_to_cpu()
206 header->sector_size = le32_to_cpu(header->sector_size); in vdi_header_to_cpu()
207 header->disk_size = le64_to_cpu(header->disk_size); in vdi_header_to_cpu()
208 header->block_size = le32_to_cpu(header->block_size); in vdi_header_to_cpu()
209 header->block_extra = le32_to_cpu(header->block_extra); in vdi_header_to_cpu()
210 header->blocks_in_image = le32_to_cpu(header->blocks_in_image); in vdi_header_to_cpu()
211 header->blocks_allocated = le32_to_cpu(header->blocks_allocated); in vdi_header_to_cpu()
212 header->uuid_image = qemu_uuid_bswap(header->uuid_image); in vdi_header_to_cpu()
213 header->uuid_last_snap = qemu_uuid_bswap(header->uuid_last_snap); in vdi_header_to_cpu()
214 header->uuid_link = qemu_uuid_bswap(header->uuid_link); in vdi_header_to_cpu()
215 header->uuid_parent = qemu_uuid_bswap(header->uuid_parent); in vdi_header_to_cpu()
220 header->signature = cpu_to_le32(header->signature); in vdi_header_to_le()
221 header->version = cpu_to_le32(header->version); in vdi_header_to_le()
222 header->header_size = cpu_to_le32(header->header_size); in vdi_header_to_le()
223 header->image_type = cpu_to_le32(header->image_type); in vdi_header_to_le()
224 header->image_flags = cpu_to_le32(header->image_flags); in vdi_header_to_le()
225 header->offset_bmap = cpu_to_le32(header->offset_bmap); in vdi_header_to_le()
226 header->offset_data = cpu_to_le32(header->offset_data); in vdi_header_to_le()
227 header->cylinders = cpu_to_le32(header->cylinders); in vdi_header_to_le()
228 header->heads = cpu_to_le32(header->heads); in vdi_header_to_le()
229 header->sectors = cpu_to_le32(header->sectors); in vdi_header_to_le()
230 header->sector_size = cpu_to_le32(header->sector_size); in vdi_header_to_le()
231 header->disk_size = cpu_to_le64(header->disk_size); in vdi_header_to_le()
232 header->block_size = cpu_to_le32(header->block_size); in vdi_header_to_le()
233 header->block_extra = cpu_to_le32(header->block_extra); in vdi_header_to_le()
234 header->blocks_in_image = cpu_to_le32(header->blocks_in_image); in vdi_header_to_le()
235 header->blocks_allocated = cpu_to_le32(header->blocks_allocated); in vdi_header_to_le()
236 header->uuid_image = qemu_uuid_bswap(header->uuid_image); in vdi_header_to_le()
237 header->uuid_last_snap = qemu_uuid_bswap(header->uuid_last_snap); in vdi_header_to_le()
238 header->uuid_link = qemu_uuid_bswap(header->uuid_link); in vdi_header_to_le()
239 header->uuid_parent = qemu_uuid_bswap(header->uuid_parent); in vdi_header_to_le()
246 logout("text %s", header->text); in vdi_header_print()
247 logout("signature 0x%08x\n", header->signature); in vdi_header_print()
248 logout("header size 0x%04x\n", header->header_size); in vdi_header_print()
249 logout("image type 0x%04x\n", header->image_type); in vdi_header_print()
250 logout("image flags 0x%04x\n", header->image_flags); in vdi_header_print()
251 logout("description %s\n", header->description); in vdi_header_print()
252 logout("offset bmap 0x%04x\n", header->offset_bmap); in vdi_header_print()
253 logout("offset data 0x%04x\n", header->offset_data); in vdi_header_print()
254 logout("cylinders 0x%04x\n", header->cylinders); in vdi_header_print()
255 logout("heads 0x%04x\n", header->heads); in vdi_header_print()
256 logout("sectors 0x%04x\n", header->sectors); in vdi_header_print()
257 logout("sector size 0x%04x\n", header->sector_size); in vdi_header_print()
259 header->disk_size, header->disk_size / MiB); in vdi_header_print()
260 logout("block size 0x%04x\n", header->block_size); in vdi_header_print()
261 logout("block extra 0x%04x\n", header->block_extra); in vdi_header_print()
262 logout("blocks tot. 0x%04x\n", header->blocks_in_image); in vdi_header_print()
263 logout("blocks all. 0x%04x\n", header->blocks_allocated); in vdi_header_print()
264 uuid = header->uuid_image; in vdi_header_print()
267 uuid = header->uuid_last_snap; in vdi_header_print()
270 uuid = header->uuid_link; in vdi_header_print()
273 uuid = header->uuid_parent; in vdi_header_print()
282 BDRVVdiState *s = (BDRVVdiState *)bs->opaque; in vdi_co_check()
284 uint32_t block; in vdi_co_check() local
289 return -ENOTSUP; in vdi_co_check()
292 bmap = g_try_new(uint32_t, s->header.blocks_in_image); in vdi_co_check()
293 if (s->header.blocks_in_image && bmap == NULL) { in vdi_co_check()
294 res->check_errors++; in vdi_co_check()
295 return -ENOMEM; in vdi_co_check()
298 memset(bmap, 0xff, s->header.blocks_in_image * sizeof(uint32_t)); in vdi_co_check()
300 /* Check block map and value of blocks_allocated. */ in vdi_co_check()
301 for (block = 0; block < s->header.blocks_in_image; block++) { in vdi_co_check()
302 uint32_t bmap_entry = le32_to_cpu(s->bmap[block]); in vdi_co_check()
304 if (bmap_entry < s->header.blocks_in_image) { in vdi_co_check()
309 fprintf(stderr, "ERROR: block index %" PRIu32 in vdi_co_check()
311 res->corruptions++; in vdi_co_check()
314 fprintf(stderr, "ERROR: block index %" PRIu32 in vdi_co_check()
315 " too large, is %" PRIu32 "\n", block, bmap_entry); in vdi_co_check()
316 res->corruptions++; in vdi_co_check()
320 if (blocks_allocated != s->header.blocks_allocated) { in vdi_co_check()
323 blocks_allocated, s->header.blocks_allocated); in vdi_co_check()
324 res->corruptions++; in vdi_co_check()
337 BDRVVdiState *s = (BDRVVdiState *)bs->opaque; in vdi_co_get_info()
339 bdi->cluster_size = s->block_size; in vdi_co_get_info()
340 bdi->vm_state_offset = 0; in vdi_co_get_info()
348 /* The return value for missing code must be 0, see block.c. */ in vdi_make_empty()
361 } else if (le32_to_cpu(header->signature) == VDI_SIGNATURE) { in vdi_probe()
368 logout("%s", header->text); in vdi_probe()
377 BDRVVdiState *s = bs->opaque; in vdi_open()
392 ret = bdrv_pread(bs->file, 0, sizeof(header), &header, 0); in vdi_open()
406 ret = -ENOTSUP; in vdi_open()
424 ret = -EINVAL; in vdi_open()
429 ret = -ENOTSUP; in vdi_open()
432 /* We only support block maps which start on a sector boundary. */ in vdi_open()
433 error_setg(errp, "unsupported VDI image (unaligned block map offset " in vdi_open()
435 ret = -ENOTSUP; in vdi_open()
441 ret = -ENOTSUP; in vdi_open()
446 ret = -ENOTSUP; in vdi_open()
449 error_setg(errp, "unsupported VDI image (block size %" PRIu32 in vdi_open()
452 ret = -ENOTSUP; in vdi_open()
460 ret = -ENOTSUP; in vdi_open()
463 error_setg(errp, "unsupported VDI image (non-NULL link UUID)"); in vdi_open()
464 ret = -ENOTSUP; in vdi_open()
467 error_setg(errp, "unsupported VDI image (non-NULL parent UUID)"); in vdi_open()
468 ret = -ENOTSUP; in vdi_open()
474 ret = -ENOTSUP; in vdi_open()
478 bs->total_sectors = header.disk_size / SECTOR_SIZE; in vdi_open()
480 s->block_size = header.block_size; in vdi_open()
481 s->bmap_sector = header.offset_bmap / SECTOR_SIZE; in vdi_open()
482 s->header = header; in vdi_open()
486 s->bmap = qemu_try_blockalign(bs->file->bs, bmap_size * SECTOR_SIZE); in vdi_open()
487 if (s->bmap == NULL) { in vdi_open()
488 ret = -ENOMEM; in vdi_open()
492 ret = bdrv_pread(bs->file, header.offset_bmap, bmap_size * SECTOR_SIZE, in vdi_open()
493 s->bmap, 0); in vdi_open()
498 /* Disable migration when vdi images are used */ in vdi_open()
499 error_setg(&s->migration_blocker, "The vdi format used by node '%s' " in vdi_open()
500 "does not support live migration", in vdi_open()
503 ret = migrate_add_blocker_normal(&s->migration_blocker, errp); in vdi_open()
508 qemu_co_rwlock_init(&s->bmap_lock); in vdi_open()
513 qemu_vfree(s->bmap); in vdi_open()
530 BDRVVdiState *s = (BDRVVdiState *)bs->opaque; in vdi_co_block_status()
531 size_t bmap_index = offset / s->block_size; in vdi_co_block_status()
532 size_t index_in_block = offset % s->block_size; in vdi_co_block_status()
533 uint32_t bmap_entry = le32_to_cpu(s->bmap[bmap_index]); in vdi_co_block_status()
537 *pnum = MIN(s->block_size - index_in_block, bytes); in vdi_co_block_status()
543 *map = s->header.offset_data + (uint64_t)bmap_entry * s->block_size + in vdi_co_block_status()
545 *file = bs->file->bs; in vdi_co_block_status()
547 (s->header.image_type == VDI_TYPE_STATIC ? BDRV_BLOCK_RECURSE : 0); in vdi_co_block_status()
554 BDRVVdiState *s = bs->opaque; in vdi_co_preadv()
565 qemu_iovec_init(&local_qiov, qiov->niov); in vdi_co_preadv()
568 block_index = offset / s->block_size; in vdi_co_preadv()
569 offset_in_block = offset % s->block_size; in vdi_co_preadv()
570 n_bytes = MIN(bytes, s->block_size - offset_in_block); in vdi_co_preadv()
576 qemu_co_rwlock_rdlock(&s->bmap_lock); in vdi_co_preadv()
577 bmap_entry = le32_to_cpu(s->bmap[block_index]); in vdi_co_preadv()
578 qemu_co_rwlock_unlock(&s->bmap_lock); in vdi_co_preadv()
580 /* Block not allocated, return zeros, no need to wait. */ in vdi_co_preadv()
584 uint64_t data_offset = s->header.offset_data + in vdi_co_preadv()
585 (uint64_t)bmap_entry * s->block_size + in vdi_co_preadv()
591 ret = bdrv_co_preadv(bs->file, data_offset, n_bytes, in vdi_co_preadv()
596 bytes -= n_bytes; in vdi_co_preadv()
610 BDRVVdiState *s = bs->opaque; in vdi_co_pwritev()
619 uint8_t *block = NULL; in vdi_co_pwritev() local
625 qemu_iovec_init(&local_qiov, qiov->niov); in vdi_co_pwritev()
628 block_index = offset / s->block_size; in vdi_co_pwritev()
629 offset_in_block = offset % s->block_size; in vdi_co_pwritev()
630 n_bytes = MIN(bytes, s->block_size - offset_in_block); in vdi_co_pwritev()
636 qemu_co_rwlock_rdlock(&s->bmap_lock); in vdi_co_pwritev()
637 bmap_entry = le32_to_cpu(s->bmap[block_index]); in vdi_co_pwritev()
639 /* Allocate new block and write to it. */ in vdi_co_pwritev()
640 qemu_co_rwlock_upgrade(&s->bmap_lock); in vdi_co_pwritev()
641 bmap_entry = le32_to_cpu(s->bmap[block_index]); in vdi_co_pwritev()
644 qemu_co_rwlock_downgrade(&s->bmap_lock); in vdi_co_pwritev()
648 bmap_entry = s->header.blocks_allocated; in vdi_co_pwritev()
649 s->bmap[block_index] = cpu_to_le32(bmap_entry); in vdi_co_pwritev()
650 s->header.blocks_allocated++; in vdi_co_pwritev()
651 data_offset = s->header.offset_data + in vdi_co_pwritev()
652 (uint64_t)bmap_entry * s->block_size; in vdi_co_pwritev()
653 if (block == NULL) { in vdi_co_pwritev()
654 block = g_malloc(s->block_size); in vdi_co_pwritev()
658 /* Copy data to be written to new block and zero unused parts. */ in vdi_co_pwritev()
659 memset(block, 0, offset_in_block); in vdi_co_pwritev()
660 qemu_iovec_to_buf(qiov, bytes_done, block + offset_in_block, in vdi_co_pwritev()
662 memset(block + offset_in_block + n_bytes, 0, in vdi_co_pwritev()
663 s->block_size - n_bytes - offset_in_block); in vdi_co_pwritev()
665 /* Write the new block under CoRwLock write-side protection, in vdi_co_pwritev()
666 * so this full-cluster write does not overlap a partial write in vdi_co_pwritev()
669 ret = bdrv_co_pwrite(bs->file, data_offset, s->block_size, block, in vdi_co_pwritev()
671 qemu_co_rwlock_unlock(&s->bmap_lock); in vdi_co_pwritev()
674 data_offset = s->header.offset_data + in vdi_co_pwritev()
675 (uint64_t)bmap_entry * s->block_size + in vdi_co_pwritev()
677 qemu_co_rwlock_unlock(&s->bmap_lock); in vdi_co_pwritev()
682 ret = bdrv_co_pwritev(bs->file, data_offset, n_bytes, in vdi_co_pwritev()
686 bytes -= n_bytes; in vdi_co_pwritev()
697 g_free(block); in vdi_co_pwritev()
701 if (block) { in vdi_co_pwritev()
708 g_free(block); in vdi_co_pwritev()
713 *header = s->header; in vdi_co_pwritev()
715 ret = bdrv_co_pwrite(bs->file, 0, sizeof(*header), header, 0); in vdi_co_pwritev()
722 logout("now writing modified block map entry %u...%u\n", in vdi_co_pwritev()
724 /* Write modified sectors from block map. */ in vdi_co_pwritev()
727 n_sectors = bmap_last - bmap_first + 1; in vdi_co_pwritev()
728 bmap_offset = s->bmap_sector + bmap_first; in vdi_co_pwritev()
729 base = ((uint8_t *)&s->bmap[0]) + bmap_first * SECTOR_SIZE; in vdi_co_pwritev()
730 logout("will write %u block map sectors starting from entry %u\n", in vdi_co_pwritev()
732 ret = bdrv_co_pwrite(bs->file, bmap_offset * SECTOR_SIZE, in vdi_co_pwritev()
758 assert(create_options->driver == BLOCKDEV_DRIVER_VDI); in vdi_co_do_create()
759 vdi_opts = &create_options->u.vdi; in vdi_co_do_create()
764 bytes = vdi_opts->size; in vdi_co_do_create()
766 if (!vdi_opts->has_preallocation) { in vdi_co_do_create()
767 vdi_opts->preallocation = PREALLOC_MODE_OFF; in vdi_co_do_create()
769 switch (vdi_opts->preallocation) { in vdi_co_do_create()
778 return -EINVAL; in vdi_co_do_create()
783 ret = -ENOTSUP; in vdi_co_do_create()
791 ret = -ENOTSUP; in vdi_co_do_create()
793 "A non-default cluster size is not supported in this build"); in vdi_co_do_create()
799 ret = -ENOTSUP; in vdi_co_do_create()
807 bs_file = bdrv_co_open_blockdev_ref(vdi_opts->file, errp); in vdi_co_do_create()
809 ret = -EIO; in vdi_co_do_create()
816 ret = -EPERM; in vdi_co_do_create()
863 ret = -ENOMEM; in vdi_co_do_create()
920 * cluster-size is not part of the QAPI schema; therefore we have in vdi_co_create_opts()
930 ret = -EINVAL; in vdi_co_create_opts()
949 ret = -EIO; in vdi_co_create_opts()
954 qdict_put_str(qdict, "file", bs_file->node_name); in vdi_co_create_opts()
962 ret = -EINVAL; in vdi_co_create_opts()
968 ret = -EINVAL; in vdi_co_create_opts()
973 assert(create_options->driver == BLOCKDEV_DRIVER_VDI); in vdi_co_create_opts()
974 create_options->u.vdi.size = ROUND_UP(create_options->u.vdi.size, in vdi_co_create_opts()
988 BDRVVdiState *s = bs->opaque; in vdi_close()
990 qemu_vfree(s->bmap); in vdi_close()
992 migrate_del_blocker(&s->migration_blocker); in vdi_close()
997 BDRVVdiState *s = bs->opaque; in vdi_has_zero_init()
999 if (s->header.image_type == VDI_TYPE_STATIC) { in vdi_has_zero_init()
1000 return bdrv_has_zero_init(bs->file->bs); in vdi_has_zero_init()
1007 .name = "vdi-create-opts",
1019 .help = "VDI cluster (block) size",
1027 .help = "VDI static (pre-allocated) image",