Lines Matching +full:- +full:- +full:disable +full:- +full:live +full:- +full:block +full:- +full:migration
2 * Block driver for Connectix / Microsoft Virtual PC images
28 #include "block/block_int.h"
29 #include "block/qdict.h"
30 #include "system/block-backend.h"
33 #include "migration/blocker.h"
38 #include "qapi/qobject-input-visitor.h"
39 #include "qapi/qapi-visit-block-core.h"
63 /* always big-endian */
108 /* Offset of the Block Allocation Table (BAT) */
122 /* Backing file name (in UTF-16) */
164 .name = "vpc-runtime-opts",
203 BDRVVPCState *s = bs->opaque; in vpc_parse_options()
211 s->force_use_sz = true; in vpc_parse_options()
213 s->force_use_chs = true; in vpc_parse_options()
220 * Microsoft Virtual PC and Microsoft Hyper-V produce and read
222 * while Hyper-V and disk2vhd use the size specified in the footer.
229 * the size is the footer->current_size to avoid truncation. Otherwise,
230 * we follow the table based on footer->creator_app:
236 * 'win ' : current_size Hyper-V
248 return !strncmp(footer->creator_app, "vpc ", 4) || in vpc_ignore_current_size()
249 !strncmp(footer->creator_app, "qemu", 4); in vpc_ignore_current_size()
255 BDRVVPCState *s = bs->opaque; in vpc_open()
278 ret = -EINVAL; in vpc_open()
285 ret = -EINVAL; in vpc_open()
289 ret = bdrv_pread(bs->file, 0, sizeof(s->footer), &s->footer, 0); in vpc_open()
295 footer = &s->footer; in vpc_open()
296 if (strncmp(footer->creator, "conectix", 8)) { in vpc_open()
297 int64_t offset = bdrv_getlength(bs->file->bs); in vpc_open()
303 ret = -EINVAL; in vpc_open()
309 ret = bdrv_pread(bs->file, offset - sizeof(*footer), sizeof(*footer), in vpc_open()
314 if (strncmp(footer->creator, "conectix", 8) || in vpc_open()
315 be32_to_cpu(footer->type) != VHD_FIXED) { in vpc_open()
317 ret = -EINVAL; in vpc_open()
323 checksum = be32_to_cpu(footer->checksum); in vpc_open()
324 footer->checksum = 0; in vpc_open()
327 ret = -EINVAL; in vpc_open()
332 footer->checksum = cpu_to_be32(checksum); in vpc_open()
337 bs->total_sectors = (int64_t) in vpc_open()
338 be16_to_cpu(footer->cyls) * footer->heads * footer->secs_per_cyl; in vpc_open()
341 use_chs = vpc_ignore_current_size(footer) || s->force_use_chs; in vpc_open()
343 if (!use_chs || bs->total_sectors == VHD_MAX_GEOMETRY || s->force_use_sz) { in vpc_open()
344 bs->total_sectors = be64_to_cpu(footer->current_size) / in vpc_open()
349 if (bs->total_sectors > VHD_MAX_SECTORS) { in vpc_open()
350 ret = -EFBIG; in vpc_open()
355 ret = bdrv_pread(bs->file, be64_to_cpu(footer->data_offset), in vpc_open()
364 ret = -EINVAL; in vpc_open()
368 s->block_size = be32_to_cpu(dyndisk_header.block_size); in vpc_open()
369 if (!is_power_of_2(s->block_size) || s->block_size < BDRV_SECTOR_SIZE) { in vpc_open()
370 error_setg(errp, "Invalid block size %" PRIu32, s->block_size); in vpc_open()
371 ret = -EINVAL; in vpc_open()
374 s->bitmap_size = ((s->block_size / (8 * 512)) + 511) & ~511; in vpc_open()
376 s->max_table_entries = be32_to_cpu(dyndisk_header.max_table_entries); in vpc_open()
378 if ((bs->total_sectors * 512) / s->block_size > 0xffffffffU) { in vpc_open()
380 ret = -EINVAL; in vpc_open()
384 computed_size = (uint64_t) s->max_table_entries * s->block_size; in vpc_open()
385 if (computed_size < bs->total_sectors * 512) { in vpc_open()
387 ret = -EINVAL; in vpc_open()
391 if (s->max_table_entries > SIZE_MAX / 4 || in vpc_open()
392 s->max_table_entries > (int) INT_MAX / 4) { in vpc_open()
394 s->max_table_entries); in vpc_open()
395 ret = -EINVAL; in vpc_open()
399 pagetable_size = (uint64_t) s->max_table_entries * 4; in vpc_open()
401 s->pagetable = qemu_try_blockalign(bs->file->bs, pagetable_size); in vpc_open()
402 if (s->pagetable == NULL) { in vpc_open()
404 ret = -ENOMEM; in vpc_open()
408 s->bat_offset = be64_to_cpu(dyndisk_header.table_offset); in vpc_open()
410 ret = bdrv_pread(bs->file, s->bat_offset, pagetable_size, in vpc_open()
411 s->pagetable, 0); in vpc_open()
417 s->free_data_block_offset = in vpc_open()
418 ROUND_UP(s->bat_offset + pagetable_size, 512); in vpc_open()
420 for (i = 0; i < s->max_table_entries; i++) { in vpc_open()
421 be32_to_cpus(&s->pagetable[i]); in vpc_open()
422 if (s->pagetable[i] != 0xFFFFFFFF) { in vpc_open()
423 int64_t next = (512 * (int64_t) s->pagetable[i]) + in vpc_open()
424 s->bitmap_size + s->block_size; in vpc_open()
426 if (next > s->free_data_block_offset) { in vpc_open()
427 s->free_data_block_offset = next; in vpc_open()
432 bs_size = bdrv_getlength(bs->file->bs); in vpc_open()
434 error_setg_errno(errp, -bs_size, "Unable to learn image size"); in vpc_open()
438 if (s->free_data_block_offset > bs_size) { in vpc_open()
439 error_setg(errp, "block-vpc: free_data_block_offset points after " in vpc_open()
441 ret = -EINVAL; in vpc_open()
445 s->last_bitmap_offset = (int64_t) -1; in vpc_open()
448 s->pageentry_u8 = g_malloc(512); in vpc_open()
449 s->pageentry_u32 = s->pageentry_u8; in vpc_open()
450 s->pageentry_u16 = s->pageentry_u8; in vpc_open()
451 s->last_pagetable = -1; in vpc_open()
455 /* Disable migration when VHD images are used */ in vpc_open()
456 error_setg(&s->migration_blocker, "The vpc format used by node '%s' " in vpc_open()
457 "does not support live migration", in vpc_open()
460 ret = migrate_add_blocker_normal(&s->migration_blocker, errp); in vpc_open()
465 qemu_co_mutex_init(&s->lock); in vpc_open()
472 qemu_vfree(s->pagetable); in vpc_open()
474 g_free(s->pageentry_u8); in vpc_open()
487 * If the sector is not allocated, -1 is returned instead.
488 * If an error occurred trying to write an updated block bitmap back to
489 * the file, -2 is returned, and the error value is written to *err.
493 * operation (the block bitmaps is updated then), 0 otherwise.
499 BDRVVPCState *s = bs->opaque; in get_image_offset()
505 pagetable_index = offset / s->block_size; in get_image_offset()
506 offset_in_block = offset % s->block_size; in get_image_offset()
508 if (pagetable_index >= s->max_table_entries || s->pagetable[pagetable_index] == 0xffffffff) in get_image_offset()
509 return -1; /* not allocated */ in get_image_offset()
511 bitmap_offset = 512 * (uint64_t) s->pagetable[pagetable_index]; in get_image_offset()
512 block_offset = bitmap_offset + s->bitmap_size + offset_in_block; in get_image_offset()
515 unused in the bitmap. We get away with setting all bits in the block in get_image_offset()
516 bitmap each time we write to a new block. This might cause Virtual PC to in get_image_offset()
519 if (write && (s->last_bitmap_offset != bitmap_offset)) { in get_image_offset()
520 g_autofree uint8_t *bitmap = g_malloc(s->bitmap_size); in get_image_offset()
523 s->last_bitmap_offset = bitmap_offset; in get_image_offset()
524 memset(bitmap, 0xff, s->bitmap_size); in get_image_offset()
525 r = bdrv_co_pwrite_sync(bs->file, bitmap_offset, s->bitmap_size, bitmap, 0); in get_image_offset()
528 return -2; in get_image_offset()
544 BDRVVPCState *s = bs->opaque; in rewrite_footer()
545 int64_t offset = s->free_data_block_offset; in rewrite_footer()
547 ret = bdrv_co_pwrite_sync(bs->file, offset, sizeof(s->footer), &s->footer, 0); in rewrite_footer()
555 * Allocates a new block. This involves writing a new footer and updating
556 * the Block Allocation Table to use the space at the old end of the image
564 BDRVVPCState *s = bs->opaque; in alloc_block()
568 g_autofree uint8_t *bitmap = g_malloc(s->bitmap_size); in alloc_block()
571 if ((offset < 0) || (offset > bs->total_sectors * BDRV_SECTOR_SIZE)) { in alloc_block()
572 return -EINVAL; in alloc_block()
575 /* Write entry into in-memory BAT */ in alloc_block()
576 index = offset / s->block_size; in alloc_block()
577 assert(s->pagetable[index] == 0xFFFFFFFF); in alloc_block()
578 s->pagetable[index] = s->free_data_block_offset / 512; in alloc_block()
580 /* Initialize the block's bitmap */ in alloc_block()
581 memset(bitmap, 0xff, s->bitmap_size); in alloc_block()
582 ret = bdrv_co_pwrite_sync(bs->file, s->free_data_block_offset, in alloc_block()
583 s->bitmap_size, bitmap, 0); in alloc_block()
589 s->free_data_block_offset += s->block_size + s->bitmap_size; in alloc_block()
595 bat_offset = s->bat_offset + (4 * index); in alloc_block()
596 bat_value = cpu_to_be32(s->pagetable[index]); in alloc_block()
597 ret = bdrv_co_pwrite_sync(bs->file, bat_offset, 4, &bat_value, 0); in alloc_block()
604 s->free_data_block_offset -= (s->block_size + s->bitmap_size); in alloc_block()
611 BDRVVPCState *s = (BDRVVPCState *)bs->opaque; in vpc_co_get_info()
613 if (be32_to_cpu(s->footer.type) != VHD_FIXED) { in vpc_co_get_info()
614 bdi->cluster_size = s->block_size; in vpc_co_get_info()
624 BDRVVPCState *s = bs->opaque; in vpc_co_preadv()
631 if (be32_to_cpu(s->footer.type) == VHD_FIXED) { in vpc_co_preadv()
632 return bdrv_co_preadv(bs->file, offset, bytes, qiov, 0); in vpc_co_preadv()
635 qemu_co_mutex_lock(&s->lock); in vpc_co_preadv()
636 qemu_iovec_init(&local_qiov, qiov->niov); in vpc_co_preadv()
640 n_bytes = MIN(bytes, s->block_size - (offset % s->block_size)); in vpc_co_preadv()
642 if (image_offset == -1) { in vpc_co_preadv()
648 qemu_co_mutex_unlock(&s->lock); in vpc_co_preadv()
649 ret = bdrv_co_preadv(bs->file, image_offset, n_bytes, in vpc_co_preadv()
651 qemu_co_mutex_lock(&s->lock); in vpc_co_preadv()
657 bytes -= n_bytes; in vpc_co_preadv()
665 qemu_co_mutex_unlock(&s->lock); in vpc_co_preadv()
674 BDRVVPCState *s = bs->opaque; in vpc_co_pwritev()
681 if (be32_to_cpu(s->footer.type) == VHD_FIXED) { in vpc_co_pwritev()
682 return bdrv_co_pwritev(bs->file, offset, bytes, qiov, 0); in vpc_co_pwritev()
685 qemu_co_mutex_lock(&s->lock); in vpc_co_pwritev()
686 qemu_iovec_init(&local_qiov, qiov->niov); in vpc_co_pwritev()
690 if (image_offset == -2) { in vpc_co_pwritev()
691 /* Failed to write block bitmap: can't proceed with write */ in vpc_co_pwritev()
694 n_bytes = MIN(bytes, s->block_size - (offset % s->block_size)); in vpc_co_pwritev()
696 if (image_offset == -1) { in vpc_co_pwritev()
707 qemu_co_mutex_unlock(&s->lock); in vpc_co_pwritev()
708 ret = bdrv_co_pwritev(bs->file, image_offset, n_bytes, in vpc_co_pwritev()
710 qemu_co_mutex_lock(&s->lock); in vpc_co_pwritev()
715 bytes -= n_bytes; in vpc_co_pwritev()
723 qemu_co_mutex_unlock(&s->lock); in vpc_co_pwritev()
734 BDRVVPCState *s = bs->opaque; in vpc_co_block_status()
740 if (be32_to_cpu(s->footer.type) == VHD_FIXED) { in vpc_co_block_status()
743 *file = bs->file->bs; in vpc_co_block_status()
747 qemu_co_mutex_lock(&s->lock); in vpc_co_block_status()
750 allocated = (image_offset != -1); in vpc_co_block_status()
755 /* All sectors in a block are contiguous (without using the bitmap) */ in vpc_co_block_status()
756 n = ROUND_UP(offset + 1, s->block_size) - offset; in vpc_co_block_status()
761 bytes -= n; in vpc_co_block_status()
762 /* *pnum can't be greater than one block for allocated in vpc_co_block_status()
765 *file = bs->file->bs; in vpc_co_block_status()
774 } while (image_offset == -1); in vpc_co_block_status()
776 qemu_co_mutex_unlock(&s->lock); in vpc_co_block_status()
788 * Returns 0 on success, -EFBIG if the size is larger than 2040 GiB. Override
789 * the hardware EIDE and ATA-2 limit of 16 heads (max disk size of 127 GB)
911 ret = blk_co_pwrite(blk, total_size - sizeof(*footer), sizeof(*footer), in create_fixed_disk()
914 error_setg_errno(errp, -ret, "Unable to write VHD header"); in create_fixed_disk()
928 int64_t total_size = vpc_opts->size; in calculate_rounded_image_size()
938 * qemu-img convert doesn't truncate images, but rather rounds up. in calculate_rounded_image_size()
944 if (vpc_opts->force_size) { in calculate_rounded_image_size()
961 return -EFBIG; in calculate_rounded_image_size()
991 int ret = -EIO; in vpc_co_create()
994 assert(opts->driver == BLOCKDEV_DRIVER_VPC); in vpc_co_create()
995 vpc_opts = &opts->u.vpc; in vpc_co_create()
998 total_size = vpc_opts->size; in vpc_co_create()
1000 if (!vpc_opts->has_subformat) { in vpc_co_create()
1001 vpc_opts->subformat = BLOCKDEV_VPC_SUBFORMAT_DYNAMIC; in vpc_co_create()
1003 switch (vpc_opts->subformat) { in vpc_co_create()
1015 bs = bdrv_co_open_blockdev_ref(vpc_opts->file, errp); in vpc_co_create()
1017 return -EIO; in vpc_co_create()
1023 ret = -EPERM; in vpc_co_create()
1038 error_append_hint(errp, "Try size=%llu or force-size=on (the " in vpc_co_create()
1042 ret = -EINVAL; in vpc_co_create()
1050 if (vpc_opts->force_size) { in vpc_co_create()
1064 footer.timestamp = cpu_to_be32(time(NULL) - VHD_TIMESTAMP_BASE); in vpc_co_create()
1108 { VPC_OPT_FORCE_SIZE, "force-size" }, in vpc_co_create_opts()
1116 ret = -EINVAL; in vpc_co_create_opts()
1129 ret = -EIO; in vpc_co_create_opts()
1135 qdict_put_str(qdict, "file", bs->node_name); in vpc_co_create_opts()
1139 ret = -EINVAL; in vpc_co_create_opts()
1146 ret = -EINVAL; in vpc_co_create_opts()
1151 assert(create_options->driver == BLOCKDEV_DRIVER_VPC); in vpc_co_create_opts()
1152 create_options->u.vpc.size = in vpc_co_create_opts()
1153 ROUND_UP(create_options->u.vpc.size, BDRV_SECTOR_SIZE); in vpc_co_create_opts()
1155 if (!create_options->u.vpc.force_size) { in vpc_co_create_opts()
1157 ret = calculate_rounded_image_size(&create_options->u.vpc, NULL, NULL, in vpc_co_create_opts()
1163 create_options->u.vpc.size = total_sectors * BDRV_SECTOR_SIZE; in vpc_co_create_opts()
1180 BDRVVPCState *s = bs->opaque; in vpc_has_zero_init()
1182 if (be32_to_cpu(s->footer.type) == VHD_FIXED) { in vpc_has_zero_init()
1183 return bdrv_has_zero_init(bs->file->bs); in vpc_has_zero_init()
1191 BDRVVPCState *s = bs->opaque; in vpc_close()
1192 qemu_vfree(s->pagetable); in vpc_close()
1194 g_free(s->pageentry_u8); in vpc_close()
1197 migrate_del_blocker(&s->migration_blocker); in vpc_close()
1201 .name = "vpc-create-opts",
1220 "specified, rather than using the nearest CHS-based "