Lines Matching +full:bat +full:- +full:temp

2  * Block driver for Hyper-V VHDX Images
11 * https://www.microsoft.com/en-us/download/details.aspx?id=34750
14 * See the COPYING.LIB file in the top-level directory.
22 #include "sysemu/block-backend.h"
27 #include "qemu/error-report.h"
33 #include "qapi/qobject-input-visitor.h"
34 #include "qapi/qapi-visit-block-core.h"
51 * guids in a MS-specific GUID format. */
54 /* ------- Known Region Table GUIDs ---------------------- */
69 /* ------- Known Metadata Entry GUIDs ---------------------- */
134 uint32_t bat_idx; /* BAT entry index */
149 * Note: The buffer should have all multi-byte data in little-endian format,
187 /* Validates the checksum of the buffer, with an in-place CRC.
191 * during the calculation, so this may not be not suitable for multi-threaded
238 QLIST_FOREACH(r, &s->regions, entries) { in vhdx_region_check()
239 if (!((start >= r->end) || (end <= r->start))) { in vhdx_region_check()
240 error_report("VHDX region %" PRIu64 "-%" PRIu64 " overlaps with " in vhdx_region_check()
241 "region %" PRIu64 "-%." PRIu64, start, end, r->start, in vhdx_region_check()
242 r->end); in vhdx_region_check()
243 ret = -EINVAL; in vhdx_region_check()
260 r->start = start; in vhdx_region_register()
261 r->end = start + length; in vhdx_region_register()
263 QLIST_INSERT_HEAD(&s->regions, r, entries); in vhdx_region_register()
271 QLIST_FOREACH_SAFE(r, &s->regions, entries, r_next) { in vhdx_region_unregister_all()
279 s->logical_sector_size_bits = ctz32(s->logical_sector_size); in vhdx_set_shift_bits()
280 s->sectors_per_block_bits = ctz32(s->sectors_per_block); in vhdx_set_shift_bits()
281 s->chunk_ratio_bits = ctz64(s->chunk_ratio); in vhdx_set_shift_bits()
282 s->block_size_bits = ctz32(s->block_size); in vhdx_set_shift_bits()
287 * - The header section is fixed size - 1 MB
288 * - The header section is always the first "object"
289 * - The first 64KB of the header is the File Identifier
290 * - The first uint64 (8 bytes) is the VHDX Signature ("vhdxfile")
291 * - The following 512 bytes constitute a UTF-16 string identifiying the
307 * This will optionally read in buffer data from disk (otherwise zero-fill),
314 BlockDriverState *bs_file = file->bs; in vhdx_write_header()
354 * - non-current header is updated with largest sequence number
367 /* operate on the non-current header */ in vhdx_update_header()
368 if (s->curr_header == 0) { in vhdx_update_header()
373 active_header = s->headers[s->curr_header]; in vhdx_update_header()
374 inactive_header = s->headers[hdr_idx]; in vhdx_update_header()
376 inactive_header->sequence_number = active_header->sequence_number + 1; in vhdx_update_header()
380 inactive_header->file_write_guid = s->session_guid; in vhdx_update_header()
382 /* a new data guid only needs to be generated before any guest-visible in vhdx_update_header()
385 vhdx_guid_generate(&inactive_header->data_write_guid); in vhdx_update_header()
390 inactive_header->log_guid = *log_guid; in vhdx_update_header()
393 ret = vhdx_write_header(bs->file, inactive_header, header_offset, true); in vhdx_update_header()
397 s->curr_header = hdr_idx; in vhdx_update_header()
405 * the current and non-current header have valid info
438 s->headers[0] = header1; in vhdx_parse_header()
439 s->headers[1] = header2; in vhdx_parse_header()
444 ret = bdrv_pread(bs->file, VHDX_HEADER1_OFFSET, VHDX_HEADER_SIZE, buffer, in vhdx_parse_header()
454 if (header1->signature == VHDX_HEADER_SIGNATURE && in vhdx_parse_header()
455 header1->version == 1) { in vhdx_parse_header()
456 h1_seq = header1->sequence_number; in vhdx_parse_header()
461 ret = bdrv_pread(bs->file, VHDX_HEADER2_OFFSET, VHDX_HEADER_SIZE, buffer, in vhdx_parse_header()
471 if (header2->signature == VHDX_HEADER_SIGNATURE && in vhdx_parse_header()
472 header2->version == 1) { in vhdx_parse_header()
473 h2_seq = header2->sequence_number; in vhdx_parse_header()
481 s->curr_header = 0; in vhdx_parse_header()
483 s->curr_header = 1; in vhdx_parse_header()
491 s->curr_header = 0; in vhdx_parse_header()
493 s->curr_header = 1; in vhdx_parse_header()
499 s->curr_header = 0; in vhdx_parse_header()
506 vhdx_region_register(s, s->headers[s->curr_header]->log_offset, in vhdx_parse_header()
507 s->headers[s->curr_header]->log_length); in vhdx_parse_header()
511 error_setg_errno(errp, -ret, "No valid VHDX header found"); in vhdx_parse_header()
514 s->headers[0] = NULL; in vhdx_parse_header()
515 s->headers[1] = NULL; in vhdx_parse_header()
536 ret = bdrv_pread(bs->file, VHDX_REGION_TABLE_OFFSET, in vhdx_open_region_tables()
541 memcpy(&s->rt, buffer, sizeof(s->rt)); in vhdx_open_region_tables()
542 offset += sizeof(s->rt); in vhdx_open_region_tables()
545 ret = -EINVAL; in vhdx_open_region_tables()
549 vhdx_region_header_le_import(&s->rt); in vhdx_open_region_tables()
551 if (s->rt.signature != VHDX_REGION_SIGNATURE) { in vhdx_open_region_tables()
552 ret = -EINVAL; in vhdx_open_region_tables()
558 if (s->rt.entry_count > 2047) { in vhdx_open_region_tables()
559 ret = -EINVAL; in vhdx_open_region_tables()
563 for (i = 0; i < s->rt.entry_count; i++) { in vhdx_open_region_tables()
582 ret = -EINVAL; in vhdx_open_region_tables()
586 s->bat_rt = rt_entry; in vhdx_open_region_tables()
593 ret = -EINVAL; in vhdx_open_region_tables()
597 s->metadata_rt = rt_entry; in vhdx_open_region_tables()
602 /* cannot read vhdx file - required region table entry that in vhdx_open_region_tables()
604 ret = -ENOTSUP; in vhdx_open_region_tables()
610 ret = -EINVAL; in vhdx_open_region_tables()
629 * - File Parameters (block size, has a parent)
630 * - Virtual Disk Size (size, in bytes, of the virtual drive)
631 * - Page 83 Data (scsi page 83 guid)
632 * - Logical Sector Size (logical sector size in bytes, either 512 or
634 * - Physical Sector Size (512 or 4096)
650 ret = bdrv_pread(bs->file, s->metadata_rt.file_offset, in vhdx_parse_metadata()
655 memcpy(&s->metadata_hdr, buffer, sizeof(s->metadata_hdr)); in vhdx_parse_metadata()
656 offset += sizeof(s->metadata_hdr); in vhdx_parse_metadata()
658 vhdx_metadata_header_le_import(&s->metadata_hdr); in vhdx_parse_metadata()
660 if (s->metadata_hdr.signature != VHDX_METADATA_SIGNATURE) { in vhdx_parse_metadata()
661 ret = -EINVAL; in vhdx_parse_metadata()
665 s->metadata_entries.present = 0; in vhdx_parse_metadata()
667 if ((s->metadata_hdr.entry_count * sizeof(md_entry)) > in vhdx_parse_metadata()
668 (VHDX_METADATA_TABLE_MAX_SIZE - offset)) { in vhdx_parse_metadata()
669 ret = -EINVAL; in vhdx_parse_metadata()
673 for (i = 0; i < s->metadata_hdr.entry_count; i++) { in vhdx_parse_metadata()
680 if (s->metadata_entries.present & META_FILE_PARAMETER_PRESENT) { in vhdx_parse_metadata()
681 ret = -EINVAL; in vhdx_parse_metadata()
684 s->metadata_entries.file_parameters_entry = md_entry; in vhdx_parse_metadata()
685 s->metadata_entries.present |= META_FILE_PARAMETER_PRESENT; in vhdx_parse_metadata()
690 if (s->metadata_entries.present & META_VIRTUAL_DISK_SIZE_PRESENT) { in vhdx_parse_metadata()
691 ret = -EINVAL; in vhdx_parse_metadata()
694 s->metadata_entries.virtual_disk_size_entry = md_entry; in vhdx_parse_metadata()
695 s->metadata_entries.present |= META_VIRTUAL_DISK_SIZE_PRESENT; in vhdx_parse_metadata()
700 if (s->metadata_entries.present & META_PAGE_83_PRESENT) { in vhdx_parse_metadata()
701 ret = -EINVAL; in vhdx_parse_metadata()
704 s->metadata_entries.page83_data_entry = md_entry; in vhdx_parse_metadata()
705 s->metadata_entries.present |= META_PAGE_83_PRESENT; in vhdx_parse_metadata()
710 if (s->metadata_entries.present & in vhdx_parse_metadata()
712 ret = -EINVAL; in vhdx_parse_metadata()
715 s->metadata_entries.logical_sector_size_entry = md_entry; in vhdx_parse_metadata()
716 s->metadata_entries.present |= META_LOGICAL_SECTOR_SIZE_PRESENT; in vhdx_parse_metadata()
721 if (s->metadata_entries.present & META_PHYS_SECTOR_SIZE_PRESENT) { in vhdx_parse_metadata()
722 ret = -EINVAL; in vhdx_parse_metadata()
725 s->metadata_entries.phys_sector_size_entry = md_entry; in vhdx_parse_metadata()
726 s->metadata_entries.present |= META_PHYS_SECTOR_SIZE_PRESENT; in vhdx_parse_metadata()
731 if (s->metadata_entries.present & META_PARENT_LOCATOR_PRESENT) { in vhdx_parse_metadata()
732 ret = -EINVAL; in vhdx_parse_metadata()
735 s->metadata_entries.parent_locator_entry = md_entry; in vhdx_parse_metadata()
736 s->metadata_entries.present |= META_PARENT_LOCATOR_PRESENT; in vhdx_parse_metadata()
741 /* cannot read vhdx file - required region table entry that in vhdx_parse_metadata()
743 ret = -ENOTSUP; in vhdx_parse_metadata()
748 if (s->metadata_entries.present != META_ALL_PRESENT) { in vhdx_parse_metadata()
749 ret = -ENOTSUP; in vhdx_parse_metadata()
753 ret = bdrv_pread(bs->file, in vhdx_parse_metadata()
754 s->metadata_entries.file_parameters_entry.offset in vhdx_parse_metadata()
755 + s->metadata_rt.file_offset, in vhdx_parse_metadata()
756 sizeof(s->params), in vhdx_parse_metadata()
757 &s->params, in vhdx_parse_metadata()
764 s->params.block_size = le32_to_cpu(s->params.block_size); in vhdx_parse_metadata()
765 s->params.data_bits = le32_to_cpu(s->params.data_bits); in vhdx_parse_metadata()
773 if (s->params.data_bits & VHDX_PARAMS_HAS_PARENT) { in vhdx_parse_metadata()
774 if (s->metadata_entries.present & META_PARENT_LOCATOR_PRESENT) { in vhdx_parse_metadata()
776 ret = -ENOTSUP; /* temp, until differencing files are supported */ in vhdx_parse_metadata()
781 ret = -EINVAL; in vhdx_parse_metadata()
789 ret = bdrv_pread(bs->file, in vhdx_parse_metadata()
790 s->metadata_entries.virtual_disk_size_entry.offset in vhdx_parse_metadata()
791 + s->metadata_rt.file_offset, in vhdx_parse_metadata()
793 &s->virtual_disk_size, in vhdx_parse_metadata()
798 ret = bdrv_pread(bs->file, in vhdx_parse_metadata()
799 s->metadata_entries.logical_sector_size_entry.offset in vhdx_parse_metadata()
800 + s->metadata_rt.file_offset, in vhdx_parse_metadata()
802 &s->logical_sector_size, in vhdx_parse_metadata()
807 ret = bdrv_pread(bs->file, in vhdx_parse_metadata()
808 s->metadata_entries.phys_sector_size_entry.offset in vhdx_parse_metadata()
809 + s->metadata_rt.file_offset, in vhdx_parse_metadata()
811 &s->physical_sector_size, in vhdx_parse_metadata()
817 s->virtual_disk_size = le64_to_cpu(s->virtual_disk_size); in vhdx_parse_metadata()
818 s->logical_sector_size = le32_to_cpu(s->logical_sector_size); in vhdx_parse_metadata()
819 s->physical_sector_size = le32_to_cpu(s->physical_sector_size); in vhdx_parse_metadata()
821 if (s->params.block_size < VHDX_BLOCK_SIZE_MIN || in vhdx_parse_metadata()
822 s->params.block_size > VHDX_BLOCK_SIZE_MAX) { in vhdx_parse_metadata()
823 ret = -EINVAL; in vhdx_parse_metadata()
828 if (s->logical_sector_size != 512) { in vhdx_parse_metadata()
829 ret = -ENOTSUP; in vhdx_parse_metadata()
834 Due to range checks above, s->sectors_per_block can never be < 256 */ in vhdx_parse_metadata()
835 s->sectors_per_block = s->params.block_size / s->logical_sector_size; in vhdx_parse_metadata()
836 s->chunk_ratio = (VHDX_MAX_SECTORS_PER_BLOCK) * in vhdx_parse_metadata()
837 (uint64_t)s->logical_sector_size / in vhdx_parse_metadata()
838 (uint64_t)s->params.block_size; in vhdx_parse_metadata()
844 if (s->logical_sector_size & (s->logical_sector_size - 1)) { in vhdx_parse_metadata()
845 ret = -EINVAL; in vhdx_parse_metadata()
848 if (s->sectors_per_block & (s->sectors_per_block - 1)) { in vhdx_parse_metadata()
849 ret = -EINVAL; in vhdx_parse_metadata()
852 if (s->chunk_ratio & (s->chunk_ratio - 1)) { in vhdx_parse_metadata()
853 ret = -EINVAL; in vhdx_parse_metadata()
856 s->block_size = s->params.block_size; in vhdx_parse_metadata()
857 if (s->block_size & (s->block_size - 1)) { in vhdx_parse_metadata()
858 ret = -EINVAL; in vhdx_parse_metadata()
872 * Calculate the number of BAT entries, including sector
879 data_blocks_cnt = DIV_ROUND_UP(s->virtual_disk_size, s->block_size); in vhdx_calc_bat_entries()
880 bitmap_blocks_cnt = DIV_ROUND_UP(data_blocks_cnt, s->chunk_ratio); in vhdx_calc_bat_entries()
882 if (s->parent_entries) { in vhdx_calc_bat_entries()
883 s->bat_entries = bitmap_blocks_cnt * (s->chunk_ratio + 1); in vhdx_calc_bat_entries()
885 s->bat_entries = data_blocks_cnt + in vhdx_calc_bat_entries()
886 ((data_blocks_cnt - 1) >> s->chunk_ratio_bits); in vhdx_calc_bat_entries()
894 BDRVVHDXState *s = bs->opaque; in vhdx_check_bat_entries()
895 int64_t image_file_size = bdrv_getlength(bs->file->bs); in vhdx_check_bat_entries()
896 uint64_t payblocks = s->chunk_ratio; in vhdx_check_bat_entries()
905 for (i = 0; i < s->bat_entries; i++) { in vhdx_check_bat_entries()
906 if ((s->bat[i] & VHDX_BAT_STATE_BIT_MASK) == in vhdx_check_bat_entries()
908 uint64_t offset = s->bat[i] & VHDX_BAT_FILE_OFF_MASK; in vhdx_check_bat_entries()
914 uint32_t block_length = MIN(s->block_size, in vhdx_check_bat_entries()
915 bs->total_sectors * BDRV_SECTOR_SIZE - i * s->block_size); in vhdx_check_bat_entries()
917 * Check for BAT entry overflow. in vhdx_check_bat_entries()
919 if (offset > INT64_MAX - s->block_size) { in vhdx_check_bat_entries()
920 error_report("VHDX BAT entry %" PRIu64 " offset overflow.", i); in vhdx_check_bat_entries()
921 ret = -EINVAL; in vhdx_check_bat_entries()
928 * Check if fully allocated BAT entries do not reside after in vhdx_check_bat_entries()
932 error_report("VHDX BAT entry %" PRIu64 " start offset %" PRIu64 in vhdx_check_bat_entries()
936 ret = -EINVAL; in vhdx_check_bat_entries()
942 error_report("VHDX BAT entry %" PRIu64 " end offset %" PRIu64 in vhdx_check_bat_entries()
945 i, offset + block_length - 1, image_file_size); in vhdx_check_bat_entries()
946 ret = -EINVAL; in vhdx_check_bat_entries()
954 * verify populated BAT field file offsets against in vhdx_check_bat_entries()
957 if (payblocks--) { in vhdx_check_bat_entries()
958 /* payload bat entries */ in vhdx_check_bat_entries()
960 ret2 = vhdx_region_check(s, offset, s->block_size); in vhdx_check_bat_entries()
962 ret = -EINVAL; in vhdx_check_bat_entries()
969 payblocks = s->chunk_ratio; in vhdx_check_bat_entries()
983 BDRVVHDXState *s = bs->opaque; in vhdx_close()
984 qemu_vfree(s->headers[0]); in vhdx_close()
985 s->headers[0] = NULL; in vhdx_close()
986 qemu_vfree(s->headers[1]); in vhdx_close()
987 s->headers[1] = NULL; in vhdx_close()
988 qemu_vfree(s->bat); in vhdx_close()
989 s->bat = NULL; in vhdx_close()
990 qemu_vfree(s->parent_entries); in vhdx_close()
991 s->parent_entries = NULL; in vhdx_close()
992 migrate_del_blocker(&s->migration_blocker); in vhdx_close()
993 qemu_vfree(s->log.hdr); in vhdx_close()
994 s->log.hdr = NULL; in vhdx_close()
1001 BDRVVHDXState *s = bs->opaque; in vhdx_open()
1016 s->bat = NULL; in vhdx_open()
1017 s->first_visible_write = true; in vhdx_open()
1019 qemu_co_mutex_init(&s->lock); in vhdx_open()
1020 QLIST_INIT(&s->regions); in vhdx_open()
1023 ret = bdrv_pread(bs->file, 0, sizeof(uint64_t), &signature, 0); in vhdx_open()
1028 ret = -EINVAL; in vhdx_open()
1035 vhdx_guid_generate(&s->session_guid); in vhdx_open()
1040 ret = -EINVAL; in vhdx_open()
1044 ret = vhdx_parse_log(bs, s, &s->log_replayed_on_open, errp); in vhdx_open()
1059 s->block_size = s->params.block_size; in vhdx_open()
1063 bs->total_sectors = s->virtual_disk_size >> s->logical_sector_size_bits; in vhdx_open()
1067 s->bat_offset = s->bat_rt.file_offset; in vhdx_open()
1069 if (s->bat_entries > s->bat_rt.length / sizeof(VHDXBatEntry)) { in vhdx_open()
1070 /* BAT allocation is not large enough for all entries */ in vhdx_open()
1071 ret = -EINVAL; in vhdx_open()
1075 /* s->bat is freed in vhdx_close() */ in vhdx_open()
1076 s->bat = qemu_try_blockalign(bs->file->bs, s->bat_rt.length); in vhdx_open()
1077 if (s->bat == NULL) { in vhdx_open()
1078 ret = -ENOMEM; in vhdx_open()
1082 ret = bdrv_pread(bs->file, s->bat_offset, s->bat_rt.length, s->bat, 0); in vhdx_open()
1087 /* endian convert populated BAT field entries */ in vhdx_open()
1088 for (i = 0; i < s->bat_entries; i++) { in vhdx_open()
1089 s->bat[i] = le64_to_cpu(s->bat[i]); in vhdx_open()
1100 error_setg(&s->migration_blocker, "The vhdx format used by node '%s' " in vhdx_open()
1103 ret = migrate_add_blocker_normal(&s->migration_blocker, errp); in vhdx_open()
1132 sinfo->bat_idx = sector_num >> s->sectors_per_block_bits; in vhdx_block_translate()
1133 /* effectively a modulo - this gives us the offset into the block in vhdx_block_translate()
1135 block_offset = sector_num - (sinfo->bat_idx << s->sectors_per_block_bits); in vhdx_block_translate()
1139 sinfo->bat_idx += sinfo->bat_idx >> s->chunk_ratio_bits; in vhdx_block_translate()
1142 sinfo->sectors_avail = s->sectors_per_block - block_offset; in vhdx_block_translate()
1144 sinfo->bytes_left = sinfo->sectors_avail << s->logical_sector_size_bits; in vhdx_block_translate()
1146 if (sinfo->sectors_avail > nb_sectors) { in vhdx_block_translate()
1147 sinfo->sectors_avail = nb_sectors; in vhdx_block_translate()
1150 sinfo->bytes_avail = sinfo->sectors_avail << s->logical_sector_size_bits; in vhdx_block_translate()
1152 sinfo->file_offset = s->bat[sinfo->bat_idx] & VHDX_BAT_FILE_OFF_MASK; in vhdx_block_translate()
1154 sinfo->block_offset = block_offset << s->logical_sector_size_bits; in vhdx_block_translate()
1157 if (sinfo->file_offset == 0) { in vhdx_block_translate()
1166 sinfo->file_offset += sinfo->block_offset; in vhdx_block_translate()
1173 BDRVVHDXState *s = bs->opaque; in vhdx_co_get_info()
1175 bdi->cluster_size = s->block_size; in vhdx_co_get_info()
1185 BDRVVHDXState *s = bs->opaque; in vhdx_co_readv()
1191 qemu_iovec_init(&hd_qiov, qiov->niov); in vhdx_co_readv()
1193 qemu_co_mutex_lock(&s->lock); in vhdx_co_readv()
1198 if (s->params.data_bits & VHDX_PARAMS_HAS_PARENT) { in vhdx_co_readv()
1200 ret = -ENOTSUP; in vhdx_co_readv()
1209 switch (s->bat[sinfo.bat_idx] & VHDX_BAT_STATE_BIT_MASK) { in vhdx_co_readv()
1219 qemu_co_mutex_unlock(&s->lock); in vhdx_co_readv()
1220 ret = bdrv_co_preadv(bs->file, sinfo.file_offset, in vhdx_co_readv()
1223 qemu_co_mutex_lock(&s->lock); in vhdx_co_readv()
1232 ret = -EIO; in vhdx_co_readv()
1236 nb_sectors -= sinfo.sectors_avail; in vhdx_co_readv()
1243 qemu_co_mutex_unlock(&s->lock); in vhdx_co_readv()
1265 current_len = bdrv_co_getlength(bs->file->bs); in vhdx_allocate_block()
1275 return -EINVAL; in vhdx_allocate_block()
1281 ret = bdrv_co_truncate(bs->file, *new_offset + s->block_size, false, in vhdx_allocate_block()
1283 if (ret != -ENOTSUP) { in vhdx_allocate_block()
1289 return bdrv_co_truncate(bs->file, *new_offset + s->block_size, false, in vhdx_allocate_block()
1294 * Update the BAT table entry with the new file offset, and the new entry
1301 /* The BAT entry is a uint64, with 44 bits for the file offset in units of in vhdx_update_bat_table_entry()
1307 s->bat[sinfo->bat_idx] = 0; /* For PAYLOAD_BLOCK_ZERO, the in vhdx_update_bat_table_entry()
1310 non-zero, MS Hyper-V will fail to read in vhdx_update_bat_table_entry()
1313 s->bat[sinfo->bat_idx] = sinfo->file_offset; in vhdx_update_bat_table_entry()
1316 s->bat[sinfo->bat_idx] |= state & VHDX_BAT_STATE_BIT_MASK; in vhdx_update_bat_table_entry()
1318 *bat_entry_le = cpu_to_le64(s->bat[sinfo->bat_idx]); in vhdx_update_bat_table_entry()
1319 *bat_offset = s->bat_offset + sinfo->bat_idx * sizeof(VHDXBatEntry); in vhdx_update_bat_table_entry()
1323 /* Per the spec, on the first write of guest-visible data to the file the
1328 if (s->first_visible_write) { in vhdx_user_visible_write()
1329 s->first_visible_write = false; in vhdx_user_visible_write()
1339 int ret = -ENOTSUP; in vhdx_co_writev()
1340 BDRVVHDXState *s = bs->opaque; in vhdx_co_writev()
1353 qemu_iovec_init(&hd_qiov, qiov->niov); in vhdx_co_writev()
1355 qemu_co_mutex_lock(&s->lock); in vhdx_co_writev()
1365 if (s->params.data_bits & VHDX_PARAMS_HAS_PARENT) { in vhdx_co_writev()
1367 ret = -ENOTSUP; in vhdx_co_writev()
1375 bat_state = s->bat[sinfo.bat_idx] & VHDX_BAT_STATE_BIT_MASK; in vhdx_co_writev()
1428 if ((sinfo.bytes_avail - sinfo.block_offset) < in vhdx_co_writev()
1429 s->block_size) { in vhdx_co_writev()
1430 iov2.iov_len = s->block_size - in vhdx_co_writev()
1445 ret = -EFAULT; in vhdx_co_writev()
1454 qemu_co_mutex_unlock(&s->lock); in vhdx_co_writev()
1455 ret = bdrv_co_pwritev(bs->file, sinfo.file_offset, in vhdx_co_writev()
1458 qemu_co_mutex_lock(&s->lock); in vhdx_co_writev()
1467 ret = -EIO; in vhdx_co_writev()
1473 /* this will update the BAT entry into the log journal, and in vhdx_co_writev()
1483 nb_sectors -= sinfo.sectors_avail; in vhdx_co_writev()
1494 /* keep metadata in sync, and restore the bat entry state in vhdx_co_writev()
1503 qemu_co_mutex_unlock(&s->lock); in vhdx_co_writev()
1529 hdr->signature = VHDX_HEADER_SIGNATURE; in vhdx_create_new_headers()
1530 hdr->sequence_number = g_random_int(); in vhdx_create_new_headers()
1531 hdr->log_version = 0; in vhdx_create_new_headers()
1532 hdr->version = 1; in vhdx_create_new_headers()
1533 hdr->log_length = log_size; in vhdx_create_new_headers()
1534 hdr->log_offset = VHDX_HEADER_SECTION_END; in vhdx_create_new_headers()
1535 vhdx_guid_generate(&hdr->file_write_guid); in vhdx_create_new_headers()
1536 vhdx_guid_generate(&hdr->data_write_guid); in vhdx_create_new_headers()
1538 /* XXX Ugly way to get blk->root, but that's a feature, not a bug. This in vhdx_create_new_headers()
1541 child = QLIST_FIRST(&bs->parents); in vhdx_create_new_headers()
1548 hdr->sequence_number++; in vhdx_create_new_headers()
1613 mt_file_params->block_size = cpu_to_le32(block_size); in vhdx_create_new_metadata()
1615 mt_file_params->data_bits |= VHDX_PARAMS_LEAVE_BLOCKS_ALLOCED; in vhdx_create_new_metadata()
1616 mt_file_params->data_bits = cpu_to_le32(mt_file_params->data_bits); in vhdx_create_new_metadata()
1619 vhdx_guid_generate(&mt_page83->page_83_data); in vhdx_create_new_metadata()
1620 cpu_to_leguids(&mt_page83->page_83_data); in vhdx_create_new_metadata()
1621 mt_virtual_size->virtual_disk_size = cpu_to_le64(image_size); in vhdx_create_new_metadata()
1622 mt_log_sector_size->logical_sector_size = cpu_to_le32(sector_size); in vhdx_create_new_metadata()
1623 mt_phys_sector_size->physical_sector_size = cpu_to_le32(sector_size); in vhdx_create_new_metadata()
1628 md_table->signature = VHDX_METADATA_SIGNATURE; in vhdx_create_new_metadata()
1629 md_table->entry_count = 5; in vhdx_create_new_metadata()
1694 /* This create the actual BAT itself. We currently only support
1697 * Dynamic images: default state of the BAT is all zeroes.
1699 * Fixed images: default state of the BAT is fully populated, with
1717 assert(s->bat == NULL); in vhdx_create_bat()
1719 /* this gives a data start after BAT/bitmap entries, and well in vhdx_create_bat()
1723 total_sectors = image_size >> s->logical_sector_size_bits; in vhdx_create_bat()
1726 /* All zeroes, so we can just extend the file - the end of the BAT in vhdx_create_bat()
1741 ret = -ENOTSUP; in vhdx_create_bat()
1752 /* for a fixed file, the default BAT entry is not zero */ in vhdx_create_bat()
1753 s->bat = g_try_malloc0(length); in vhdx_create_bat()
1754 if (length && s->bat == NULL) { in vhdx_create_bat()
1755 error_setg(errp, "Failed to allocate memory for the BAT"); in vhdx_create_bat()
1756 ret = -ENOMEM; in vhdx_create_bat()
1762 /* fill the BAT by emulating sector writes of sectors_per_block size */ in vhdx_create_bat()
1764 vhdx_block_translate(s, sector_num, s->sectors_per_block, &sinfo); in vhdx_create_bat()
1766 (sector_num << s->logical_sector_size_bits); in vhdx_create_bat()
1770 s->bat[sinfo.bat_idx] = cpu_to_le64(s->bat[sinfo.bat_idx]); in vhdx_create_bat()
1771 sector_num += s->sectors_per_block; in vhdx_create_bat()
1773 ret = blk_co_pwrite(blk, file_offset, length, s->bat, 0); in vhdx_create_bat()
1775 error_setg_errno(errp, -ret, "Failed to write the BAT"); in vhdx_create_bat()
1783 g_free(s->bat); in vhdx_create_bat()
1788 * There are 2 supported region table entries: BAT, and Metadata/
1790 * As the calculations for the BAT region table are also needed
1791 * to create the BAT itself, we will also cause the BAT to be
1814 * pre-existing BAT calculation, translation, and update functions */ in vhdx_create_new_region_table()
1817 s->chunk_ratio = (VHDX_MAX_SECTORS_PER_BLOCK) * in vhdx_create_new_region_table()
1820 s->sectors_per_block = block_size / sector_size; in vhdx_create_new_region_table()
1821 s->virtual_disk_size = image_size; in vhdx_create_new_region_table()
1822 s->block_size = block_size; in vhdx_create_new_region_table()
1823 s->logical_sector_size = sector_size; in vhdx_create_new_region_table()
1840 region_table->signature = VHDX_REGION_SIGNATURE; in vhdx_create_new_region_table()
1841 region_table->entry_count = 2; /* BAT and Metadata */ in vhdx_create_new_region_table()
1843 rt_bat->guid = bat_guid; in vhdx_create_new_region_table()
1844 rt_bat->length = ROUND_UP(s->bat_entries * sizeof(VHDXBatEntry), MiB); in vhdx_create_new_region_table()
1845 rt_bat->file_offset = ROUND_UP(VHDX_HEADER_SECTION_END + log_size, MiB); in vhdx_create_new_region_table()
1846 s->bat_offset = rt_bat->file_offset; in vhdx_create_new_region_table()
1848 rt_metadata->guid = metadata_guid; in vhdx_create_new_region_table()
1849 rt_metadata->file_offset = ROUND_UP(rt_bat->file_offset + rt_bat->length, in vhdx_create_new_region_table()
1851 rt_metadata->length = 1 * MiB; /* min size, and more than enough */ in vhdx_create_new_region_table()
1852 *metadata_offset = rt_metadata->file_offset; in vhdx_create_new_region_table()
1854 bat_file_offset = rt_bat->file_offset; in vhdx_create_new_region_table()
1855 bat_length = rt_bat->length; in vhdx_create_new_region_table()
1865 /* The region table gives us the data we need to create the BAT, in vhdx_create_new_region_table()
1877 error_setg_errno(errp, -ret, "Failed to write first region table"); in vhdx_create_new_region_table()
1884 error_setg_errno(errp, -ret, "Failed to write second region table"); in vhdx_create_new_region_table()
1896 * .-----------------------------------------------------------------.
1900 * .-----------------------------------------------------------------.
1904 * .---- ~ ----------- ~ ------------ ~ ---------------- ~ -----------.
1906 * | Journal Log | BAT / Bitmap | Metadata | .... data ...... |
1908 * .---- ~ ----------- ~ ------------ ~ ---------------- ~ -----------.
1930 assert(opts->driver == BLOCKDEV_DRIVER_VHDX); in vhdx_co_create()
1931 vhdx_opts = &opts->u.vhdx; in vhdx_co_create()
1934 image_size = vhdx_opts->size; in vhdx_co_create()
1937 return -EINVAL; in vhdx_co_create()
1940 if (!vhdx_opts->has_log_size) { in vhdx_co_create()
1943 if (vhdx_opts->log_size > UINT32_MAX) { in vhdx_co_create()
1945 return -EINVAL; in vhdx_co_create()
1947 log_size = vhdx_opts->log_size; in vhdx_co_create()
1951 return -EINVAL; in vhdx_co_create()
1954 if (!vhdx_opts->has_block_state_zero) { in vhdx_co_create()
1957 use_zero_blocks = vhdx_opts->block_state_zero; in vhdx_co_create()
1960 if (!vhdx_opts->has_subformat) { in vhdx_co_create()
1961 vhdx_opts->subformat = BLOCKDEV_VHDX_SUBFORMAT_DYNAMIC; in vhdx_co_create()
1964 switch (vhdx_opts->subformat) { in vhdx_co_create()
1975 /* These are pretty arbitrary, and mainly designed to keep the BAT in vhdx_co_create()
1977 if (vhdx_opts->has_block_size) { in vhdx_co_create()
1978 block_size = vhdx_opts->block_size; in vhdx_co_create()
1993 return -EINVAL; in vhdx_co_create()
1997 return -EINVAL; in vhdx_co_create()
2002 return -EINVAL; in vhdx_co_create()
2006 bs = bdrv_co_open_blockdev_ref(vhdx_opts->file, errp); in vhdx_co_create()
2008 return -EIO; in vhdx_co_create()
2014 ret = -EPERM; in vhdx_co_create()
2023 creator = g_utf8_to_utf16("QEMU v" QEMU_VERSION, -1, NULL, in vhdx_co_create()
2029 error_setg_errno(errp, -ret, "Failed to write file signature"); in vhdx_co_create()
2036 error_setg_errno(errp, -ret, "Failed to write creator field"); in vhdx_co_create()
2045 error_setg_errno(errp, -ret, "Failed to write image headers"); in vhdx_co_create()
2049 /* Creates (D),(E),(G) explicitly. (F) created as by-product */ in vhdx_co_create()
2061 error_setg_errno(errp, -ret, "Failed to initialize metadata"); in vhdx_co_create()
2084 { VHDX_BLOCK_OPT_LOG_SIZE, "log-size" }, in vhdx_co_create_opts()
2085 { VHDX_BLOCK_OPT_BLOCK_SIZE, "block-size" }, in vhdx_co_create_opts()
2086 { VHDX_BLOCK_OPT_ZERO, "block-state-zero" }, in vhdx_co_create_opts()
2094 ret = -EINVAL; in vhdx_co_create_opts()
2107 ret = -EIO; in vhdx_co_create_opts()
2113 qdict_put_str(qdict, "file", bs->node_name); in vhdx_co_create_opts()
2117 ret = -EINVAL; in vhdx_co_create_opts()
2124 ret = -EINVAL; in vhdx_co_create_opts()
2133 assert(create_options->driver == BLOCKDEV_DRIVER_VHDX); in vhdx_co_create_opts()
2134 create_options->u.vhdx.size = in vhdx_co_create_opts()
2135 ROUND_UP(create_options->u.vhdx.size, BDRV_SECTOR_SIZE); in vhdx_co_create_opts()
2137 if (create_options->u.vhdx.has_log_size) { in vhdx_co_create_opts()
2138 create_options->u.vhdx.log_size = in vhdx_co_create_opts()
2139 ROUND_UP(create_options->u.vhdx.log_size, MiB); in vhdx_co_create_opts()
2141 if (create_options->u.vhdx.has_block_size) { in vhdx_co_create_opts()
2142 create_options->u.vhdx.block_size = in vhdx_co_create_opts()
2143 ROUND_UP(create_options->u.vhdx.block_size, MiB); in vhdx_co_create_opts()
2145 if (create_options->u.vhdx.block_size == 0) { in vhdx_co_create_opts()
2146 create_options->u.vhdx.has_block_size = false; in vhdx_co_create_opts()
2148 if (create_options->u.vhdx.block_size > VHDX_BLOCK_SIZE_MAX) { in vhdx_co_create_opts()
2149 create_options->u.vhdx.block_size = VHDX_BLOCK_SIZE_MAX; in vhdx_co_create_opts()
2166 * If qemu-img check -r all is called, the image is automatically opened
2174 BDRVVHDXState *s = bs->opaque; in vhdx_co_check()
2176 if (s->log_replayed_on_open) { in vhdx_co_check()
2177 result->corruptions_fixed++; in vhdx_co_check()
2180 vhdx_check_bat_entries(bs, &result->corruptions); in vhdx_co_check()
2187 BDRVVHDXState *s = bs->opaque; in vhdx_has_zero_init()
2191 * Check the subformat: Fixed images have all BAT entries present, in vhdx_has_zero_init()
2193 * therefore enough to check the first BAT entry. in vhdx_has_zero_init()
2195 if (!s->bat_entries) { in vhdx_has_zero_init()
2199 state = s->bat[0] & VHDX_BAT_STATE_BIT_MASK; in vhdx_has_zero_init()
2202 return bdrv_has_zero_init(bs->file->bs); in vhdx_has_zero_init()
2210 .name = "vhdx-create-opts",
2229 "0 means auto-calculate based on image size."
2241 "Non-standard, but default. Do not set to 'off' when "
2242 "using 'qemu-img convert' with subformat=dynamic."