2 * Block driver for Hyper-V VHDX Images
4 * Copyright (c) 2013 Red Hat, Inc.,
7 * Jeff Cody <jcody@redhat.com>
9 * This is based on the "VHDX Format Specification v0.95", published 4/12/2012
11 * https://www.microsoft.com/en-us/download/details.aspx?id=29681
13 * This work is licensed under the terms of the GNU LGPL, version 2 or later.
14 * See the COPYING.LIB file in the top-level directory.
18 #include "qemu-common.h"
19 #include "block/block_int.h"
20 #include "qemu/module.h"
21 #include "qemu/crc32c.h"
22 #include "block/vhdx.h"
25 /* Several metadata and region table data entries are identified by
26 * guids in a MS-specific GUID format. */
29 /* ------- Known Region Table GUIDs ---------------------- */
30 static const MSGUID bat_guid
= { .data1
= 0x2dc27766,
33 .data4
= { 0x9d, 0x64, 0x11, 0x5e,
34 0x9b, 0xfd, 0x4a, 0x08} };
36 static const MSGUID metadata_guid
= { .data1
= 0x8b7ca206,
39 .data4
= { 0xb8, 0xfe, 0x57, 0x5f,
40 0x05, 0x0f, 0x88, 0x6e} };
44 /* ------- Known Metadata Entry GUIDs ---------------------- */
45 static const MSGUID file_param_guid
= { .data1
= 0xcaa16737,
48 .data4
= { 0xb3, 0xb6, 0x33, 0xf0,
49 0xaa, 0x44, 0xe7, 0x6b} };
51 static const MSGUID virtual_size_guid
= { .data1
= 0x2FA54224,
54 .data4
= { 0xb2, 0x11, 0x5d, 0xbe,
55 0xd8, 0x3b, 0xf4, 0xb8} };
57 static const MSGUID page83_guid
= { .data1
= 0xbeca12ab,
60 .data4
= { 0x93, 0xef, 0xc3, 0x09,
61 0xe0, 0x00, 0xc7, 0x46} };
64 static const MSGUID phys_sector_guid
= { .data1
= 0xcda348c7,
67 .data4
= { 0x9c, 0xc9, 0xe9, 0x88,
68 0x52, 0x51, 0xc5, 0x56} };
70 static const MSGUID parent_locator_guid
= { .data1
= 0xa8d35f2d,
73 .data4
= { 0xab, 0xf7, 0xd3,
77 static const MSGUID logical_sector_guid
= { .data1
= 0x8141bf1d,
80 .data4
= { 0xba, 0x47, 0xf2,
84 /* Each parent type must have a valid GUID; this is for parent images
85 * of type 'VHDX'. If we were to allow e.g. a QCOW2 parent, we would
86 * need to make up our own QCOW2 GUID type */
87 static const MSGUID parent_vhdx_guid
= { .data1
= 0xb04aefb7,
90 .data4
= { 0xb7, 0x89, 0x25, 0xb8,
91 0xe9, 0x44, 0x59, 0x13} };
94 #define META_FILE_PARAMETER_PRESENT 0x01
95 #define META_VIRTUAL_DISK_SIZE_PRESENT 0x02
96 #define META_PAGE_83_PRESENT 0x04
97 #define META_LOGICAL_SECTOR_SIZE_PRESENT 0x08
98 #define META_PHYS_SECTOR_SIZE_PRESENT 0x10
99 #define META_PARENT_LOCATOR_PRESENT 0x20
101 #define META_ALL_PRESENT \
102 (META_FILE_PARAMETER_PRESENT | META_VIRTUAL_DISK_SIZE_PRESENT | \
103 META_PAGE_83_PRESENT | META_LOGICAL_SECTOR_SIZE_PRESENT | \
104 META_PHYS_SECTOR_SIZE_PRESENT)
106 typedef struct VHDXMetadataEntries
{
107 VHDXMetadataTableEntry file_parameters_entry
;
108 VHDXMetadataTableEntry virtual_disk_size_entry
;
109 VHDXMetadataTableEntry page83_data_entry
;
110 VHDXMetadataTableEntry logical_sector_size_entry
;
111 VHDXMetadataTableEntry phys_sector_size_entry
;
112 VHDXMetadataTableEntry parent_locator_entry
;
114 } VHDXMetadataEntries
;
117 typedef struct BDRVVHDXState
{
121 VHDXHeader
*headers
[2];
123 VHDXRegionTableHeader rt
;
124 VHDXRegionTableEntry bat_rt
; /* region table for the BAT */
125 VHDXRegionTableEntry metadata_rt
; /* region table for the metadata */
127 VHDXMetadataTableHeader metadata_hdr
;
128 VHDXMetadataEntries metadata_entries
;
130 VHDXFileParameters params
;
132 uint32_t block_size_bits
;
133 uint32_t sectors_per_block
;
134 uint32_t sectors_per_block_bits
;
136 uint64_t virtual_disk_size
;
137 uint32_t logical_sector_size
;
138 uint32_t physical_sector_size
;
140 uint64_t chunk_ratio
;
141 uint32_t chunk_ratio_bits
;
142 uint32_t logical_sector_size_bits
;
144 uint32_t bat_entries
;
148 VHDXParentLocatorHeader parent_header
;
149 VHDXParentLocatorEntry
*parent_entries
;
153 uint32_t vhdx_checksum_calc(uint32_t crc
, uint8_t *buf
, size_t size
,
160 if (crc_offset
> 0) {
161 memcpy(&crc_orig
, buf
+ crc_offset
, sizeof(crc_orig
));
162 memset(buf
+ crc_offset
, 0, sizeof(crc_orig
));
165 crc_new
= crc32c(crc
, buf
, size
);
166 if (crc_offset
> 0) {
167 memcpy(buf
+ crc_offset
, &crc_orig
, sizeof(crc_orig
));
173 /* Validates the checksum of the buffer, with an in-place CRC.
175 * Zero is substituted during crc calculation for the original crc field,
176 * and the crc field is restored afterwards. But the buffer will be modifed
177 * during the calculation, so this may not be not suitable for multi-threaded
180 * crc_offset: byte offset in buf of the buffer crc
181 * buf: buffer pointer
182 * size: size of buffer (must be > crc_offset+4)
184 * returns true if checksum is valid, false otherwise
186 bool vhdx_checksum_is_valid(uint8_t *buf
, size_t size
, int crc_offset
)
192 assert(size
> (crc_offset
+ 4));
194 memcpy(&crc_orig
, buf
+ crc_offset
, sizeof(crc_orig
));
195 crc_orig
= le32_to_cpu(crc_orig
);
197 crc
= vhdx_checksum_calc(0xffffffff, buf
, size
, crc_offset
);
199 return crc
== crc_orig
;
204 * Per the MS VHDX Specification, for every VHDX file:
205 * - The header section is fixed size - 1 MB
206 * - The header section is always the first "object"
207 * - The first 64KB of the header is the File Identifier
208 * - The first uint64 (8 bytes) is the VHDX Signature ("vhdxfile")
209 * - The following 512 bytes constitute a UTF-16 string identifiying the
210 * software that created the file, and is optional and diagnostic only.
212 * Therefore, we probe by looking for the vhdxfile signature "vhdxfile"
214 static int vhdx_probe(const uint8_t *buf
, int buf_size
, const char *filename
)
216 if (buf_size
>= 8 && !memcmp(buf
, "vhdxfile", 8)) {
222 /* All VHDX structures on disk are little endian */
223 static void vhdx_header_le_import(VHDXHeader
*h
)
227 le32_to_cpus(&h
->signature
);
228 le32_to_cpus(&h
->checksum
);
229 le64_to_cpus(&h
->sequence_number
);
231 leguid_to_cpus(&h
->file_write_guid
);
232 leguid_to_cpus(&h
->data_write_guid
);
233 leguid_to_cpus(&h
->log_guid
);
235 le16_to_cpus(&h
->log_version
);
236 le16_to_cpus(&h
->version
);
237 le32_to_cpus(&h
->log_length
);
238 le64_to_cpus(&h
->log_offset
);
242 /* opens the specified header block from the VHDX file header section */
243 static int vhdx_parse_header(BlockDriverState
*bs
, BDRVVHDXState
*s
)
248 bool h1_valid
= false;
249 bool h2_valid
= false;
254 header1
= qemu_blockalign(bs
, sizeof(VHDXHeader
));
255 header2
= qemu_blockalign(bs
, sizeof(VHDXHeader
));
257 buffer
= qemu_blockalign(bs
, VHDX_HEADER_SIZE
);
259 s
->headers
[0] = header1
;
260 s
->headers
[1] = header2
;
262 /* We have to read the whole VHDX_HEADER_SIZE instead of
263 * sizeof(VHDXHeader), because the checksum is over the whole
265 ret
= bdrv_pread(bs
->file
, VHDX_HEADER1_OFFSET
, buffer
, VHDX_HEADER_SIZE
);
269 /* copy over just the relevant portion that we need */
270 memcpy(header1
, buffer
, sizeof(VHDXHeader
));
271 vhdx_header_le_import(header1
);
273 if (vhdx_checksum_is_valid(buffer
, VHDX_HEADER_SIZE
, 4) &&
274 !memcmp(&header1
->signature
, "head", 4) &&
275 header1
->version
== 1) {
276 h1_seq
= header1
->sequence_number
;
280 ret
= bdrv_pread(bs
->file
, VHDX_HEADER2_OFFSET
, buffer
, VHDX_HEADER_SIZE
);
284 /* copy over just the relevant portion that we need */
285 memcpy(header2
, buffer
, sizeof(VHDXHeader
));
286 vhdx_header_le_import(header2
);
288 if (vhdx_checksum_is_valid(buffer
, VHDX_HEADER_SIZE
, 4) &&
289 !memcmp(&header2
->signature
, "head", 4) &&
290 header2
->version
== 1) {
291 h2_seq
= header2
->sequence_number
;
295 /* If there is only 1 valid header (or no valid headers), we
296 * don't care what the sequence numbers are */
297 if (h1_valid
&& !h2_valid
) {
299 } else if (!h1_valid
&& h2_valid
) {
301 } else if (!h1_valid
&& !h2_valid
) {
305 /* If both headers are valid, then we choose the active one by the
306 * highest sequence number. If the sequence numbers are equal, that is
308 if (h1_seq
> h2_seq
) {
310 } else if (h2_seq
> h1_seq
) {
323 qerror_report(ERROR_CLASS_GENERIC_ERROR
, "No valid VHDX header found");
326 s
->headers
[0] = NULL
;
327 s
->headers
[1] = NULL
;
334 static int vhdx_open_region_tables(BlockDriverState
*bs
, BDRVVHDXState
*s
)
339 VHDXRegionTableEntry rt_entry
;
341 bool bat_rt_found
= false;
342 bool metadata_rt_found
= false;
344 /* We have to read the whole 64KB block, because the crc32 is over the
346 buffer
= qemu_blockalign(bs
, VHDX_HEADER_BLOCK_SIZE
);
348 ret
= bdrv_pread(bs
->file
, VHDX_REGION_TABLE_OFFSET
, buffer
,
349 VHDX_HEADER_BLOCK_SIZE
);
353 memcpy(&s
->rt
, buffer
, sizeof(s
->rt
));
354 le32_to_cpus(&s
->rt
.signature
);
355 le32_to_cpus(&s
->rt
.checksum
);
356 le32_to_cpus(&s
->rt
.entry_count
);
357 le32_to_cpus(&s
->rt
.reserved
);
358 offset
+= sizeof(s
->rt
);
360 if (!vhdx_checksum_is_valid(buffer
, VHDX_HEADER_BLOCK_SIZE
, 4) ||
361 memcmp(&s
->rt
.signature
, "regi", 4)) {
366 /* Per spec, maximum region table entry count is 2047 */
367 if (s
->rt
.entry_count
> 2047) {
372 for (i
= 0; i
< s
->rt
.entry_count
; i
++) {
373 memcpy(&rt_entry
, buffer
+ offset
, sizeof(rt_entry
));
374 offset
+= sizeof(rt_entry
);
376 leguid_to_cpus(&rt_entry
.guid
);
377 le64_to_cpus(&rt_entry
.file_offset
);
378 le32_to_cpus(&rt_entry
.length
);
379 le32_to_cpus(&rt_entry
.data_bits
);
381 /* see if we recognize the entry */
382 if (guid_eq(rt_entry
.guid
, bat_guid
)) {
383 /* must be unique; if we have already found it this is invalid */
389 s
->bat_rt
= rt_entry
;
393 if (guid_eq(rt_entry
.guid
, metadata_guid
)) {
394 /* must be unique; if we have already found it this is invalid */
395 if (metadata_rt_found
) {
399 metadata_rt_found
= true;
400 s
->metadata_rt
= rt_entry
;
404 if (rt_entry
.data_bits
& VHDX_REGION_ENTRY_REQUIRED
) {
405 /* cannot read vhdx file - required region table entry that
406 * we do not understand. per spec, we must fail to open */
420 /* Metadata initial parser
422 * This loads all the metadata entry fields. This may cause additional
423 * fields to be processed (e.g. parent locator, etc..).
425 * There are 5 Metadata items that are always required:
426 * - File Parameters (block size, has a parent)
427 * - Virtual Disk Size (size, in bytes, of the virtual drive)
428 * - Page 83 Data (scsi page 83 guid)
429 * - Logical Sector Size (logical sector size in bytes, either 512 or
430 * 4096. We only support 512 currently)
431 * - Physical Sector Size (512 or 4096)
433 * Also, if the File Parameters indicate this is a differencing file,
434 * we must also look for the Parent Locator metadata item.
436 static int vhdx_parse_metadata(BlockDriverState
*bs
, BDRVVHDXState
*s
)
442 VHDXMetadataTableEntry md_entry
;
444 buffer
= qemu_blockalign(bs
, VHDX_METADATA_TABLE_MAX_SIZE
);
446 ret
= bdrv_pread(bs
->file
, s
->metadata_rt
.file_offset
, buffer
,
447 VHDX_METADATA_TABLE_MAX_SIZE
);
451 memcpy(&s
->metadata_hdr
, buffer
, sizeof(s
->metadata_hdr
));
452 offset
+= sizeof(s
->metadata_hdr
);
454 le64_to_cpus(&s
->metadata_hdr
.signature
);
455 le16_to_cpus(&s
->metadata_hdr
.reserved
);
456 le16_to_cpus(&s
->metadata_hdr
.entry_count
);
458 if (memcmp(&s
->metadata_hdr
.signature
, "metadata", 8)) {
463 s
->metadata_entries
.present
= 0;
465 if ((s
->metadata_hdr
.entry_count
* sizeof(md_entry
)) >
466 (VHDX_METADATA_TABLE_MAX_SIZE
- offset
)) {
471 for (i
= 0; i
< s
->metadata_hdr
.entry_count
; i
++) {
472 memcpy(&md_entry
, buffer
+ offset
, sizeof(md_entry
));
473 offset
+= sizeof(md_entry
);
475 leguid_to_cpus(&md_entry
.item_id
);
476 le32_to_cpus(&md_entry
.offset
);
477 le32_to_cpus(&md_entry
.length
);
478 le32_to_cpus(&md_entry
.data_bits
);
479 le32_to_cpus(&md_entry
.reserved2
);
481 if (guid_eq(md_entry
.item_id
, file_param_guid
)) {
482 if (s
->metadata_entries
.present
& META_FILE_PARAMETER_PRESENT
) {
486 s
->metadata_entries
.file_parameters_entry
= md_entry
;
487 s
->metadata_entries
.present
|= META_FILE_PARAMETER_PRESENT
;
491 if (guid_eq(md_entry
.item_id
, virtual_size_guid
)) {
492 if (s
->metadata_entries
.present
& META_VIRTUAL_DISK_SIZE_PRESENT
) {
496 s
->metadata_entries
.virtual_disk_size_entry
= md_entry
;
497 s
->metadata_entries
.present
|= META_VIRTUAL_DISK_SIZE_PRESENT
;
501 if (guid_eq(md_entry
.item_id
, page83_guid
)) {
502 if (s
->metadata_entries
.present
& META_PAGE_83_PRESENT
) {
506 s
->metadata_entries
.page83_data_entry
= md_entry
;
507 s
->metadata_entries
.present
|= META_PAGE_83_PRESENT
;
511 if (guid_eq(md_entry
.item_id
, logical_sector_guid
)) {
512 if (s
->metadata_entries
.present
&
513 META_LOGICAL_SECTOR_SIZE_PRESENT
) {
517 s
->metadata_entries
.logical_sector_size_entry
= md_entry
;
518 s
->metadata_entries
.present
|= META_LOGICAL_SECTOR_SIZE_PRESENT
;
522 if (guid_eq(md_entry
.item_id
, phys_sector_guid
)) {
523 if (s
->metadata_entries
.present
& META_PHYS_SECTOR_SIZE_PRESENT
) {
527 s
->metadata_entries
.phys_sector_size_entry
= md_entry
;
528 s
->metadata_entries
.present
|= META_PHYS_SECTOR_SIZE_PRESENT
;
532 if (guid_eq(md_entry
.item_id
, parent_locator_guid
)) {
533 if (s
->metadata_entries
.present
& META_PARENT_LOCATOR_PRESENT
) {
537 s
->metadata_entries
.parent_locator_entry
= md_entry
;
538 s
->metadata_entries
.present
|= META_PARENT_LOCATOR_PRESENT
;
542 if (md_entry
.data_bits
& VHDX_META_FLAGS_IS_REQUIRED
) {
543 /* cannot read vhdx file - required region table entry that
544 * we do not understand. per spec, we must fail to open */
550 if (s
->metadata_entries
.present
!= META_ALL_PRESENT
) {
555 ret
= bdrv_pread(bs
->file
,
556 s
->metadata_entries
.file_parameters_entry
.offset
557 + s
->metadata_rt
.file_offset
,
565 le32_to_cpus(&s
->params
.block_size
);
566 le32_to_cpus(&s
->params
.data_bits
);
569 /* We now have the file parameters, so we can tell if this is a
570 * differencing file (i.e.. has_parent), is dynamic or fixed
571 * sized (leave_blocks_allocated), and the block size */
573 /* The parent locator required iff the file parameters has_parent set */
574 if (s
->params
.data_bits
& VHDX_PARAMS_HAS_PARENT
) {
575 if (s
->metadata_entries
.present
& META_PARENT_LOCATOR_PRESENT
) {
576 /* TODO: parse parent locator fields */
577 ret
= -ENOTSUP
; /* temp, until differencing files are supported */
580 /* if has_parent is set, but there is not parent locator present,
581 * then that is an invalid combination */
587 /* determine virtual disk size, logical sector size,
588 * and phys sector size */
590 ret
= bdrv_pread(bs
->file
,
591 s
->metadata_entries
.virtual_disk_size_entry
.offset
592 + s
->metadata_rt
.file_offset
,
593 &s
->virtual_disk_size
,
598 ret
= bdrv_pread(bs
->file
,
599 s
->metadata_entries
.logical_sector_size_entry
.offset
600 + s
->metadata_rt
.file_offset
,
601 &s
->logical_sector_size
,
606 ret
= bdrv_pread(bs
->file
,
607 s
->metadata_entries
.phys_sector_size_entry
.offset
608 + s
->metadata_rt
.file_offset
,
609 &s
->physical_sector_size
,
615 le64_to_cpus(&s
->virtual_disk_size
);
616 le32_to_cpus(&s
->logical_sector_size
);
617 le32_to_cpus(&s
->physical_sector_size
);
619 if (s
->logical_sector_size
== 0 || s
->params
.block_size
== 0) {
624 /* both block_size and sector_size are guaranteed powers of 2 */
625 s
->sectors_per_block
= s
->params
.block_size
/ s
->logical_sector_size
;
626 s
->chunk_ratio
= (VHDX_MAX_SECTORS_PER_BLOCK
) *
627 (uint64_t)s
->logical_sector_size
/
628 (uint64_t)s
->params
.block_size
;
630 /* These values are ones we will want to use for division / multiplication
631 * later on, and they are all guaranteed (per the spec) to be powers of 2,
632 * so we can take advantage of that for shift operations during
634 if (s
->logical_sector_size
& (s
->logical_sector_size
- 1)) {
638 if (s
->sectors_per_block
& (s
->sectors_per_block
- 1)) {
642 if (s
->chunk_ratio
& (s
->chunk_ratio
- 1)) {
646 s
->block_size
= s
->params
.block_size
;
647 if (s
->block_size
& (s
->block_size
- 1)) {
652 s
->logical_sector_size_bits
= 31 - clz32(s
->logical_sector_size
);
653 s
->sectors_per_block_bits
= 31 - clz32(s
->sectors_per_block
);
654 s
->chunk_ratio_bits
= 63 - clz64(s
->chunk_ratio
);
655 s
->block_size_bits
= 31 - clz32(s
->block_size
);
664 /* Parse the replay log. Per the VHDX spec, if the log is present
665 * it must be replayed prior to opening the file, even read-only.
667 * If read-only, we must replay the log in RAM (or refuse to open
668 * a dirty VHDX file read-only */
669 static int vhdx_parse_log(BlockDriverState
*bs
, BDRVVHDXState
*s
)
675 hdr
= s
->headers
[s
->curr_header
];
677 /* either the log guid, or log length is zero,
678 * then a replay log is present */
679 for (i
= 0; i
< sizeof(hdr
->log_guid
.data4
); i
++) {
680 ret
|= hdr
->log_guid
.data4
[i
];
682 if (hdr
->log_guid
.data1
== 0 &&
683 hdr
->log_guid
.data2
== 0 &&
684 hdr
->log_guid
.data3
== 0 &&
689 /* per spec, only log version of 0 is supported */
690 if (hdr
->log_version
!= 0) {
695 if (hdr
->log_length
== 0) {
699 /* We currently do not support images with logs to replay */
707 static int vhdx_open(BlockDriverState
*bs
, QDict
*options
, int flags
)
709 BDRVVHDXState
*s
= bs
->opaque
;
713 uint32_t data_blocks_cnt
, bitmap_blocks_cnt
;
718 qemu_co_mutex_init(&s
->lock
);
720 /* validate the file signature */
721 ret
= bdrv_pread(bs
->file
, 0, &signature
, sizeof(uint64_t));
725 if (memcmp(&signature
, "vhdxfile", 8)) {
730 ret
= vhdx_parse_header(bs
, s
);
735 ret
= vhdx_parse_log(bs
, s
);
740 ret
= vhdx_open_region_tables(bs
, s
);
745 ret
= vhdx_parse_metadata(bs
, s
);
749 s
->block_size
= s
->params
.block_size
;
751 /* the VHDX spec dictates that virtual_disk_size is always a multiple of
752 * logical_sector_size */
753 bs
->total_sectors
= s
->virtual_disk_size
>> s
->logical_sector_size_bits
;
755 data_blocks_cnt
= s
->virtual_disk_size
>> s
->block_size_bits
;
756 if (s
->virtual_disk_size
- (data_blocks_cnt
<< s
->block_size_bits
)) {
759 bitmap_blocks_cnt
= data_blocks_cnt
>> s
->chunk_ratio_bits
;
760 if (data_blocks_cnt
- (bitmap_blocks_cnt
<< s
->chunk_ratio_bits
)) {
764 if (s
->parent_entries
) {
765 s
->bat_entries
= bitmap_blocks_cnt
* (s
->chunk_ratio
+ 1);
767 s
->bat_entries
= data_blocks_cnt
+
768 ((data_blocks_cnt
- 1) >> s
->chunk_ratio_bits
);
771 s
->bat_offset
= s
->bat_rt
.file_offset
;
773 if (s
->bat_entries
> s
->bat_rt
.length
/ sizeof(VHDXBatEntry
)) {
774 /* BAT allocation is not large enough for all entries */
779 s
->bat
= qemu_blockalign(bs
, s
->bat_rt
.length
);
781 ret
= bdrv_pread(bs
->file
, s
->bat_offset
, s
->bat
, s
->bat_rt
.length
);
786 for (i
= 0; i
< s
->bat_entries
; i
++) {
787 le64_to_cpus(&s
->bat
[i
]);
790 if (flags
& BDRV_O_RDWR
) {
795 /* TODO: differencing files, read, write */
799 qemu_vfree(s
->headers
[0]);
800 qemu_vfree(s
->headers
[1]);
802 qemu_vfree(s
->parent_entries
);
806 static int vhdx_reopen_prepare(BDRVReopenState
*state
,
807 BlockReopenQueue
*queue
, Error
**errp
)
813 static coroutine_fn
int vhdx_co_readv(BlockDriverState
*bs
, int64_t sector_num
,
814 int nb_sectors
, QEMUIOVector
*qiov
)
821 static coroutine_fn
int vhdx_co_writev(BlockDriverState
*bs
, int64_t sector_num
,
822 int nb_sectors
, QEMUIOVector
*qiov
)
828 static void vhdx_close(BlockDriverState
*bs
)
830 BDRVVHDXState
*s
= bs
->opaque
;
831 qemu_vfree(s
->headers
[0]);
832 qemu_vfree(s
->headers
[1]);
834 qemu_vfree(s
->parent_entries
);
837 static BlockDriver bdrv_vhdx
= {
838 .format_name
= "vhdx",
839 .instance_size
= sizeof(BDRVVHDXState
),
840 .bdrv_probe
= vhdx_probe
,
841 .bdrv_open
= vhdx_open
,
842 .bdrv_close
= vhdx_close
,
843 .bdrv_reopen_prepare
= vhdx_reopen_prepare
,
844 .bdrv_co_readv
= vhdx_co_readv
,
845 .bdrv_co_writev
= vhdx_co_writev
,
848 static void bdrv_vhdx_init(void)
850 bdrv_register(&bdrv_vhdx
);
853 block_init(bdrv_vhdx_init
);