1203cdba3SJeff Cody /*
2203cdba3SJeff Cody * Block driver for Hyper-V VHDX Images
3203cdba3SJeff Cody *
4203cdba3SJeff Cody * Copyright (c) 2013 Red Hat, Inc.,
5203cdba3SJeff Cody *
6203cdba3SJeff Cody * Authors:
7203cdba3SJeff Cody * Jeff Cody <jcody@redhat.com>
8203cdba3SJeff Cody *
96e9d290bSJeff Cody * This is based on the "VHDX Format Specification v1.00", published 8/25/2012
10203cdba3SJeff Cody * by Microsoft:
116e9d290bSJeff Cody * https://www.microsoft.com/en-us/download/details.aspx?id=34750
12203cdba3SJeff Cody *
13203cdba3SJeff Cody * This work is licensed under the terms of the GNU LGPL, version 2 or later.
14203cdba3SJeff Cody * See the COPYING.LIB file in the top-level directory.
15203cdba3SJeff Cody *
16203cdba3SJeff Cody */
17203cdba3SJeff Cody
18203cdba3SJeff Cody #ifndef BLOCK_VHDX_H
19203cdba3SJeff Cody #define BLOCK_VHDX_H
20e9991e29SStefano Garzarella #include "qemu/units.h"
213412f7b1SJeff Cody
225366092cSChunyan Liu #define DEFAULT_LOG_SIZE 1048576 /* 1MiB */
230cb98af2SStefano Garzarella /* Note: can't use 1 * MiB, because it's passed to stringify() */
240cb98af2SStefano Garzarella
25203cdba3SJeff Cody /* Structures and fields present in the VHDX file */
26203cdba3SJeff Cody
27203cdba3SJeff Cody /* The header section has the following blocks,
28203cdba3SJeff Cody * each block is 64KB:
29203cdba3SJeff Cody *
30203cdba3SJeff Cody * _____________________________________________________________________________
31203cdba3SJeff Cody * | File Id. | Header 1 | Header 2 | Region Table | Reserved (768KB) |
32203cdba3SJeff Cody * |----------|---------------|------------|--------------|--------------------|
33203cdba3SJeff Cody * | | | | | |
34203cdba3SJeff Cody * 0.........64KB...........128KB........192KB..........256KB................1MB
35203cdba3SJeff Cody */
36203cdba3SJeff Cody
370cb98af2SStefano Garzarella #define VHDX_HEADER_BLOCK_SIZE (64 * KiB)
38203cdba3SJeff Cody
39203cdba3SJeff Cody #define VHDX_FILE_ID_OFFSET 0
40203cdba3SJeff Cody #define VHDX_HEADER1_OFFSET (VHDX_HEADER_BLOCK_SIZE * 1)
41203cdba3SJeff Cody #define VHDX_HEADER2_OFFSET (VHDX_HEADER_BLOCK_SIZE * 2)
42203cdba3SJeff Cody #define VHDX_REGION_TABLE_OFFSET (VHDX_HEADER_BLOCK_SIZE * 3)
433412f7b1SJeff Cody #define VHDX_REGION_TABLE2_OFFSET (VHDX_HEADER_BLOCK_SIZE * 4)
44203cdba3SJeff Cody
453412f7b1SJeff Cody #define VHDX_HEADER_SECTION_END (1 * MiB)
46203cdba3SJeff Cody /*
47203cdba3SJeff Cody * A note on the use of MS-GUID fields. For more details on the GUID,
48203cdba3SJeff Cody * please see: https://en.wikipedia.org/wiki/Globally_unique_identifier.
49203cdba3SJeff Cody *
50203cdba3SJeff Cody * The VHDX specification only states that these are MS GUIDs, and which
51203cdba3SJeff Cody * bytes are data1-data4. It makes no mention of what algorithm should be used
52203cdba3SJeff Cody * to generate the GUID, nor what standard. However, looking at the specified
53203cdba3SJeff Cody * known GUID fields, it appears the GUIDs are:
54203cdba3SJeff Cody * Standard/DCE GUID type (noted by 10b in the MSB of byte 0 of .data4)
55203cdba3SJeff Cody * Random algorithm (noted by 0x4XXX for .data3)
56203cdba3SJeff Cody */
57203cdba3SJeff Cody
58203cdba3SJeff Cody /* ---- HEADER SECTION STRUCTURES ---- */
59203cdba3SJeff Cody
60203cdba3SJeff Cody /* These structures are ones that are defined in the VHDX specification
61203cdba3SJeff Cody * document */
62203cdba3SJeff Cody
6362e466e8SJeff Cody #define VHDX_FILE_SIGNATURE 0x656C696678646876ULL /* "vhdxfile" in ASCII */
64203cdba3SJeff Cody typedef struct VHDXFileIdentifier {
65203cdba3SJeff Cody uint64_t signature; /* "vhdxfile" in ASCII */
66203cdba3SJeff Cody uint16_t creator[256]; /* optional; utf-16 string to identify
6761c02e56SJeff Cody the vhdx file creator. Diagnostic
68203cdba3SJeff Cody only */
69203cdba3SJeff Cody } VHDXFileIdentifier;
70203cdba3SJeff Cody
71203cdba3SJeff Cody
72203cdba3SJeff Cody /* the guid is a 16 byte unique ID - the definition for this used by
73203cdba3SJeff Cody * Microsoft is not just 16 bytes though - it is a structure that is defined,
74203cdba3SJeff Cody * so we need to follow it here so that endianness does not trip us up */
75203cdba3SJeff Cody
764f18b782SJeff Cody typedef struct QEMU_PACKED MSGUID {
77203cdba3SJeff Cody uint32_t data1;
78203cdba3SJeff Cody uint16_t data2;
79203cdba3SJeff Cody uint16_t data3;
80203cdba3SJeff Cody uint8_t data4[8];
81203cdba3SJeff Cody } MSGUID;
82203cdba3SJeff Cody
83203cdba3SJeff Cody #define guid_eq(a, b) \
84203cdba3SJeff Cody (memcmp(&(a), &(b), sizeof(MSGUID)) == 0)
85203cdba3SJeff Cody
860cb98af2SStefano Garzarella #define VHDX_HEADER_SIZE (4 * KiB) /* although the vhdx_header struct in disk
87203cdba3SJeff Cody is only 582 bytes, for purposes of crc
88203cdba3SJeff Cody the header is the first 4KB of the 64KB
89203cdba3SJeff Cody block */
90203cdba3SJeff Cody
91203cdba3SJeff Cody /* The full header is 4KB, although the actual header data is much smaller.
92203cdba3SJeff Cody * But for the checksum calculation, it is over the entire 4KB structure,
93203cdba3SJeff Cody * not just the defined portion of it */
943412f7b1SJeff Cody #define VHDX_HEADER_SIGNATURE 0x64616568
95203cdba3SJeff Cody typedef struct QEMU_PACKED VHDXHeader {
96203cdba3SJeff Cody uint32_t signature; /* "head" in ASCII */
97203cdba3SJeff Cody uint32_t checksum; /* CRC-32C hash of the whole header */
98203cdba3SJeff Cody uint64_t sequence_number; /* Seq number of this header. Each
99203cdba3SJeff Cody VHDX file has 2 of these headers,
100203cdba3SJeff Cody and only the header with the highest
101203cdba3SJeff Cody sequence number is valid */
102203cdba3SJeff Cody MSGUID file_write_guid; /* 128 bit unique identifier. Must be
103203cdba3SJeff Cody updated to new, unique value before
104203cdba3SJeff Cody the first modification is made to
105203cdba3SJeff Cody file */
106203cdba3SJeff Cody MSGUID data_write_guid; /* 128 bit unique identifier. Must be
107203cdba3SJeff Cody updated to new, unique value before
108203cdba3SJeff Cody the first modification is made to
109203cdba3SJeff Cody visible data. Visbile data is
110203cdba3SJeff Cody defined as:
111203cdba3SJeff Cody - system & user metadata
112203cdba3SJeff Cody - raw block data
113203cdba3SJeff Cody - disk size
114203cdba3SJeff Cody - any change that will
115203cdba3SJeff Cody cause the virtual disk
116203cdba3SJeff Cody sector read to differ
117203cdba3SJeff Cody
118203cdba3SJeff Cody This does not need to change if
119203cdba3SJeff Cody blocks are re-arranged */
120203cdba3SJeff Cody MSGUID log_guid; /* 128 bit unique identifier. If zero,
121203cdba3SJeff Cody there is no valid log. If non-zero,
122203cdba3SJeff Cody log entries with this guid are
123203cdba3SJeff Cody valid. */
12461c02e56SJeff Cody uint16_t log_version; /* version of the log format. Must be
12561c02e56SJeff Cody set to zero */
126203cdba3SJeff Cody uint16_t version; /* version of the vhdx file. Currently,
127203cdba3SJeff Cody only supported version is "1" */
128203cdba3SJeff Cody uint32_t log_length; /* length of the log. Must be multiple
129203cdba3SJeff Cody of 1MB */
130203cdba3SJeff Cody uint64_t log_offset; /* byte offset in the file of the log.
131203cdba3SJeff Cody Must also be a multiple of 1MB */
132203cdba3SJeff Cody } VHDXHeader;
133203cdba3SJeff Cody
134203cdba3SJeff Cody /* Header for the region table block */
1353412f7b1SJeff Cody #define VHDX_REGION_SIGNATURE 0x69676572 /* "regi" in ASCII */
136203cdba3SJeff Cody typedef struct QEMU_PACKED VHDXRegionTableHeader {
137203cdba3SJeff Cody uint32_t signature; /* "regi" in ASCII */
138203cdba3SJeff Cody uint32_t checksum; /* CRC-32C hash of the 64KB table */
139203cdba3SJeff Cody uint32_t entry_count; /* number of valid entries */
140203cdba3SJeff Cody uint32_t reserved;
141203cdba3SJeff Cody } VHDXRegionTableHeader;
142203cdba3SJeff Cody
143203cdba3SJeff Cody /* Individual region table entry. There may be a maximum of 2047 of these
144203cdba3SJeff Cody *
145203cdba3SJeff Cody * There are two known region table properties. Both are required.
146203cdba3SJeff Cody * BAT (block allocation table): 2DC27766F62342009D64115E9BFD4A08
147203cdba3SJeff Cody * Metadata: 8B7CA20647904B9AB8FE575F050F886E
148203cdba3SJeff Cody */
149203cdba3SJeff Cody #define VHDX_REGION_ENTRY_REQUIRED 0x01 /* if set, parser must understand
150203cdba3SJeff Cody this entry in order to open
151203cdba3SJeff Cody file */
152203cdba3SJeff Cody typedef struct QEMU_PACKED VHDXRegionTableEntry {
153203cdba3SJeff Cody MSGUID guid; /* 128-bit unique identifier */
154203cdba3SJeff Cody uint64_t file_offset; /* offset of the object in the file.
155203cdba3SJeff Cody Must be multiple of 1MB */
156203cdba3SJeff Cody uint32_t length; /* length, in bytes, of the object */
157203cdba3SJeff Cody uint32_t data_bits;
158203cdba3SJeff Cody } VHDXRegionTableEntry;
159203cdba3SJeff Cody
160203cdba3SJeff Cody
161203cdba3SJeff Cody /* ---- LOG ENTRY STRUCTURES ---- */
1620cb98af2SStefano Garzarella #define VHDX_LOG_MIN_SIZE (1 * MiB)
1630cb98af2SStefano Garzarella #define VHDX_LOG_SECTOR_SIZE (4 * KiB)
164203cdba3SJeff Cody #define VHDX_LOG_HDR_SIZE 64
165625565d2SJeff Cody #define VHDX_LOG_SIGNATURE 0x65676f6c
166203cdba3SJeff Cody typedef struct QEMU_PACKED VHDXLogEntryHeader {
167203cdba3SJeff Cody uint32_t signature; /* "loge" in ASCII */
168203cdba3SJeff Cody uint32_t checksum; /* CRC-32C hash of the 64KB table */
169203cdba3SJeff Cody uint32_t entry_length; /* length in bytes, multiple of 1MB */
170203cdba3SJeff Cody uint32_t tail; /* byte offset of first log entry of a
171203cdba3SJeff Cody seq, where this entry is the last
172203cdba3SJeff Cody entry */
173203cdba3SJeff Cody uint64_t sequence_number; /* incremented with each log entry.
174203cdba3SJeff Cody May not be zero. */
175203cdba3SJeff Cody uint32_t descriptor_count; /* number of descriptors in this log
176203cdba3SJeff Cody entry, must be >= 0 */
177203cdba3SJeff Cody uint32_t reserved;
178203cdba3SJeff Cody MSGUID log_guid; /* value of the log_guid from
179203cdba3SJeff Cody vhdx_header. If not found in
180203cdba3SJeff Cody vhdx_header, it is invalid */
181203cdba3SJeff Cody uint64_t flushed_file_offset; /* see spec for full details - this
18252f35022SStefan Weil should be vhdx file size in bytes */
183203cdba3SJeff Cody uint64_t last_file_offset; /* size in bytes that all allocated
184203cdba3SJeff Cody file structures fit into */
185203cdba3SJeff Cody } VHDXLogEntryHeader;
186203cdba3SJeff Cody
187203cdba3SJeff Cody #define VHDX_LOG_DESC_SIZE 32
188625565d2SJeff Cody #define VHDX_LOG_DESC_SIGNATURE 0x63736564
189625565d2SJeff Cody #define VHDX_LOG_ZERO_SIGNATURE 0x6f72657a
190203cdba3SJeff Cody typedef struct QEMU_PACKED VHDXLogDescriptor {
191203cdba3SJeff Cody uint32_t signature; /* "zero" or "desc" in ASCII */
192203cdba3SJeff Cody union {
193203cdba3SJeff Cody uint32_t reserved; /* zero desc */
194203cdba3SJeff Cody uint32_t trailing_bytes; /* data desc: bytes 4092-4096 of the
195203cdba3SJeff Cody data sector */
196203cdba3SJeff Cody };
197203cdba3SJeff Cody union {
198203cdba3SJeff Cody uint64_t zero_length; /* zero desc: length of the section to
199203cdba3SJeff Cody zero */
200203cdba3SJeff Cody uint64_t leading_bytes; /* data desc: bytes 0-7 of the data
201203cdba3SJeff Cody sector */
202203cdba3SJeff Cody };
203203cdba3SJeff Cody uint64_t file_offset; /* file offset to write zeros - multiple
204203cdba3SJeff Cody of 4kB */
205203cdba3SJeff Cody uint64_t sequence_number; /* must match same field in
206203cdba3SJeff Cody vhdx_log_entry_header */
207203cdba3SJeff Cody } VHDXLogDescriptor;
208203cdba3SJeff Cody
209625565d2SJeff Cody #define VHDX_LOG_DATA_SIGNATURE 0x61746164
210203cdba3SJeff Cody typedef struct QEMU_PACKED VHDXLogDataSector {
211203cdba3SJeff Cody uint32_t data_signature; /* "data" in ASCII */
212203cdba3SJeff Cody uint32_t sequence_high; /* 4 MSB of 8 byte sequence_number */
213203cdba3SJeff Cody uint8_t data[4084]; /* raw data, bytes 8-4091 (inclusive).
214203cdba3SJeff Cody see the data descriptor field for the
2153202d8e4SMichael Tokarev other missing bytes */
216203cdba3SJeff Cody uint32_t sequence_low; /* 4 LSB of 8 byte sequence_number */
217203cdba3SJeff Cody } VHDXLogDataSector;
218203cdba3SJeff Cody
219203cdba3SJeff Cody
220203cdba3SJeff Cody
221203cdba3SJeff Cody /* block states - different state values depending on whether it is a
222203cdba3SJeff Cody * payload block, or a sector block. */
223203cdba3SJeff Cody
224203cdba3SJeff Cody #define PAYLOAD_BLOCK_NOT_PRESENT 0
225203cdba3SJeff Cody #define PAYLOAD_BLOCK_UNDEFINED 1
226203cdba3SJeff Cody #define PAYLOAD_BLOCK_ZERO 2
227a9d1e9daSJeff Cody #define PAYLOAD_BLOCK_UNMAPPED 3
228a9d1e9daSJeff Cody #define PAYLOAD_BLOCK_UNMAPPED_v095 5
229d92aa883SJeff Cody #define PAYLOAD_BLOCK_FULLY_PRESENT 6
230203cdba3SJeff Cody #define PAYLOAD_BLOCK_PARTIALLY_PRESENT 7
231203cdba3SJeff Cody
232203cdba3SJeff Cody #define SB_BLOCK_NOT_PRESENT 0
233203cdba3SJeff Cody #define SB_BLOCK_PRESENT 6
234203cdba3SJeff Cody
235203cdba3SJeff Cody /* per the spec */
236203cdba3SJeff Cody #define VHDX_MAX_SECTORS_PER_BLOCK (1 << 23)
237203cdba3SJeff Cody
238203cdba3SJeff Cody /* upper 44 bits are the file offset in 1MB units lower 3 bits are the state
239203cdba3SJeff Cody other bits are reserved */
240203cdba3SJeff Cody #define VHDX_BAT_STATE_BIT_MASK 0x07
24162e466e8SJeff Cody #define VHDX_BAT_FILE_OFF_MASK 0xFFFFFFFFFFF00000ULL /* upper 44 bits */
242203cdba3SJeff Cody typedef uint64_t VHDXBatEntry;
243203cdba3SJeff Cody
244203cdba3SJeff Cody /* ---- METADATA REGION STRUCTURES ---- */
245203cdba3SJeff Cody
246203cdba3SJeff Cody #define VHDX_METADATA_ENTRY_SIZE 32
247203cdba3SJeff Cody #define VHDX_METADATA_MAX_ENTRIES 2047 /* not including the header */
248203cdba3SJeff Cody #define VHDX_METADATA_TABLE_MAX_SIZE \
249203cdba3SJeff Cody (VHDX_METADATA_ENTRY_SIZE * (VHDX_METADATA_MAX_ENTRIES+1))
25062e466e8SJeff Cody #define VHDX_METADATA_SIGNATURE 0x617461646174656DULL /* "metadata" in ASCII */
251203cdba3SJeff Cody typedef struct QEMU_PACKED VHDXMetadataTableHeader {
252203cdba3SJeff Cody uint64_t signature; /* "metadata" in ASCII */
253203cdba3SJeff Cody uint16_t reserved;
254203cdba3SJeff Cody uint16_t entry_count; /* number table entries. <= 2047 */
255203cdba3SJeff Cody uint32_t reserved2[5];
256203cdba3SJeff Cody } VHDXMetadataTableHeader;
257203cdba3SJeff Cody
258203cdba3SJeff Cody #define VHDX_META_FLAGS_IS_USER 0x01 /* max 1024 entries */
259203cdba3SJeff Cody #define VHDX_META_FLAGS_IS_VIRTUAL_DISK 0x02 /* virtual disk metadata if set,
2603202d8e4SMichael Tokarev otherwise file metadata */
261203cdba3SJeff Cody #define VHDX_META_FLAGS_IS_REQUIRED 0x04 /* parse must understand this
262203cdba3SJeff Cody entry to open the file */
263203cdba3SJeff Cody typedef struct QEMU_PACKED VHDXMetadataTableEntry {
264203cdba3SJeff Cody MSGUID item_id; /* 128-bit identifier for metadata */
265203cdba3SJeff Cody uint32_t offset; /* byte offset of the metadata. At
266203cdba3SJeff Cody least 64kB. Relative to start of
267203cdba3SJeff Cody metadata region */
268203cdba3SJeff Cody /* note: if length = 0, so is offset */
269203cdba3SJeff Cody uint32_t length; /* length of metadata. <= 1MB. */
270625565d2SJeff Cody uint32_t data_bits; /* least-significant 3 bits are flags,
271625565d2SJeff Cody the rest are reserved (see above) */
272203cdba3SJeff Cody uint32_t reserved2;
273203cdba3SJeff Cody } VHDXMetadataTableEntry;
274203cdba3SJeff Cody
275203cdba3SJeff Cody #define VHDX_PARAMS_LEAVE_BLOCKS_ALLOCED 0x01 /* Do not change any blocks to
276203cdba3SJeff Cody be BLOCK_NOT_PRESENT.
277203cdba3SJeff Cody If set indicates a fixed
278203cdba3SJeff Cody size VHDX file */
279203cdba3SJeff Cody #define VHDX_PARAMS_HAS_PARENT 0x02 /* has parent / backing file */
2803412f7b1SJeff Cody #define VHDX_BLOCK_SIZE_MIN (1 * MiB)
2813412f7b1SJeff Cody #define VHDX_BLOCK_SIZE_MAX (256 * MiB)
282203cdba3SJeff Cody typedef struct QEMU_PACKED VHDXFileParameters {
283203cdba3SJeff Cody uint32_t block_size; /* size of each payload block, always
284203cdba3SJeff Cody power of 2, <= 256MB and >= 1MB. */
285625565d2SJeff Cody uint32_t data_bits; /* least-significant 2 bits are flags,
286625565d2SJeff Cody the rest are reserved (see above) */
287203cdba3SJeff Cody } VHDXFileParameters;
288203cdba3SJeff Cody
2893412f7b1SJeff Cody #define VHDX_MAX_IMAGE_SIZE ((uint64_t) 64 * TiB)
290203cdba3SJeff Cody typedef struct QEMU_PACKED VHDXVirtualDiskSize {
291203cdba3SJeff Cody uint64_t virtual_disk_size; /* Size of the virtual disk, in bytes.
292203cdba3SJeff Cody Must be multiple of the sector size,
293203cdba3SJeff Cody max of 64TB */
294203cdba3SJeff Cody } VHDXVirtualDiskSize;
295203cdba3SJeff Cody
296203cdba3SJeff Cody typedef struct QEMU_PACKED VHDXPage83Data {
29761c02e56SJeff Cody MSGUID page_83_data; /* unique id for scsi devices that
298203cdba3SJeff Cody support page 0x83 */
299203cdba3SJeff Cody } VHDXPage83Data;
300203cdba3SJeff Cody
301203cdba3SJeff Cody typedef struct QEMU_PACKED VHDXVirtualDiskLogicalSectorSize {
302203cdba3SJeff Cody uint32_t logical_sector_size; /* virtual disk sector size (in bytes).
303203cdba3SJeff Cody Can only be 512 or 4096 bytes */
304203cdba3SJeff Cody } VHDXVirtualDiskLogicalSectorSize;
305203cdba3SJeff Cody
306203cdba3SJeff Cody typedef struct QEMU_PACKED VHDXVirtualDiskPhysicalSectorSize {
307203cdba3SJeff Cody uint32_t physical_sector_size; /* physical sector size (in bytes).
308203cdba3SJeff Cody Can only be 512 or 4096 bytes */
309203cdba3SJeff Cody } VHDXVirtualDiskPhysicalSectorSize;
310203cdba3SJeff Cody
311203cdba3SJeff Cody typedef struct QEMU_PACKED VHDXParentLocatorHeader {
31261c02e56SJeff Cody MSGUID locator_type; /* type of the parent virtual disk. */
313203cdba3SJeff Cody uint16_t reserved;
314203cdba3SJeff Cody uint16_t key_value_count; /* number of key/value pairs for this
315203cdba3SJeff Cody locator */
316203cdba3SJeff Cody } VHDXParentLocatorHeader;
317203cdba3SJeff Cody
318203cdba3SJeff Cody /* key and value strings are UNICODE strings, UTF-16 LE encoding, no NULs */
319203cdba3SJeff Cody typedef struct QEMU_PACKED VHDXParentLocatorEntry {
320203cdba3SJeff Cody uint32_t key_offset; /* offset in metadata for key, > 0 */
321203cdba3SJeff Cody uint32_t value_offset; /* offset in metadata for value, >0 */
322203cdba3SJeff Cody uint16_t key_length; /* length of entry key, > 0 */
323203cdba3SJeff Cody uint16_t value_length; /* length of entry value, > 0 */
324203cdba3SJeff Cody } VHDXParentLocatorEntry;
325203cdba3SJeff Cody
326203cdba3SJeff Cody
327203cdba3SJeff Cody /* ----- END VHDX SPECIFICATION STRUCTURES ---- */
328203cdba3SJeff Cody
32928541d46SJeff Cody typedef struct VHDXMetadataEntries {
33028541d46SJeff Cody VHDXMetadataTableEntry file_parameters_entry;
33128541d46SJeff Cody VHDXMetadataTableEntry virtual_disk_size_entry;
33228541d46SJeff Cody VHDXMetadataTableEntry page83_data_entry;
33328541d46SJeff Cody VHDXMetadataTableEntry logical_sector_size_entry;
33428541d46SJeff Cody VHDXMetadataTableEntry phys_sector_size_entry;
33528541d46SJeff Cody VHDXMetadataTableEntry parent_locator_entry;
33628541d46SJeff Cody uint16_t present;
33728541d46SJeff Cody } VHDXMetadataEntries;
33828541d46SJeff Cody
339625565d2SJeff Cody typedef struct VHDXLogEntries {
340625565d2SJeff Cody uint64_t offset;
341625565d2SJeff Cody uint64_t length;
3420a43a1b5SJeff Cody uint32_t write;
3430a43a1b5SJeff Cody uint32_t read;
3440a43a1b5SJeff Cody VHDXLogEntryHeader *hdr;
3450a43a1b5SJeff Cody void *desc_buffer;
3460a43a1b5SJeff Cody uint64_t sequence;
347625565d2SJeff Cody uint32_t tail;
348625565d2SJeff Cody } VHDXLogEntries;
349625565d2SJeff Cody
3501a848fd4SJeff Cody typedef struct VHDXRegionEntry {
3511a848fd4SJeff Cody uint64_t start;
3521a848fd4SJeff Cody uint64_t end;
3531a848fd4SJeff Cody QLIST_ENTRY(VHDXRegionEntry) entries;
3541a848fd4SJeff Cody } VHDXRegionEntry;
3551a848fd4SJeff Cody
35628541d46SJeff Cody typedef struct BDRVVHDXState {
35728541d46SJeff Cody CoMutex lock;
35828541d46SJeff Cody
35928541d46SJeff Cody int curr_header;
36028541d46SJeff Cody VHDXHeader *headers[2];
36128541d46SJeff Cody
36228541d46SJeff Cody VHDXRegionTableHeader rt;
36328541d46SJeff Cody VHDXRegionTableEntry bat_rt; /* region table for the BAT */
36428541d46SJeff Cody VHDXRegionTableEntry metadata_rt; /* region table for the metadata */
36528541d46SJeff Cody
36628541d46SJeff Cody VHDXMetadataTableHeader metadata_hdr;
36728541d46SJeff Cody VHDXMetadataEntries metadata_entries;
36828541d46SJeff Cody
36928541d46SJeff Cody VHDXFileParameters params;
37028541d46SJeff Cody uint32_t block_size;
37128541d46SJeff Cody uint32_t block_size_bits;
37228541d46SJeff Cody uint32_t sectors_per_block;
37328541d46SJeff Cody uint32_t sectors_per_block_bits;
37428541d46SJeff Cody
37528541d46SJeff Cody uint64_t virtual_disk_size;
37628541d46SJeff Cody uint32_t logical_sector_size;
37728541d46SJeff Cody uint32_t physical_sector_size;
37828541d46SJeff Cody
37928541d46SJeff Cody uint64_t chunk_ratio;
38028541d46SJeff Cody uint32_t chunk_ratio_bits;
38128541d46SJeff Cody uint32_t logical_sector_size_bits;
38228541d46SJeff Cody
38328541d46SJeff Cody uint32_t bat_entries;
38428541d46SJeff Cody VHDXBatEntry *bat;
38528541d46SJeff Cody uint64_t bat_offset;
38628541d46SJeff Cody
387c3906c5eSJeff Cody bool first_visible_write;
38828541d46SJeff Cody MSGUID session_guid;
38928541d46SJeff Cody
390625565d2SJeff Cody VHDXLogEntries log;
391625565d2SJeff Cody
39228541d46SJeff Cody VHDXParentLocatorHeader parent_header;
39328541d46SJeff Cody VHDXParentLocatorEntry *parent_entries;
39428541d46SJeff Cody
39528541d46SJeff Cody Error *migration_blocker;
3961a848fd4SJeff Cody
3977e30e6a6SJeff Cody bool log_replayed_on_open;
3987e30e6a6SJeff Cody
399b58deb34SPaolo Bonzini QLIST_HEAD(, VHDXRegionEntry) regions;
40028541d46SJeff Cody } BDRVVHDXState;
401e8d4e5ffSJeff Cody
4024f18b782SJeff Cody void vhdx_guid_generate(MSGUID *guid);
4034f18b782SJeff Cody
404*65ff757dSKevin Wolf int GRAPH_RDLOCK
405*65ff757dSKevin Wolf vhdx_update_headers(BlockDriverState *bs, BDRVVHDXState *s, bool rw,
406c3906c5eSJeff Cody MSGUID *log_guid);
407c3906c5eSJeff Cody
4084f18b782SJeff Cody uint32_t vhdx_update_checksum(uint8_t *buf, size_t size, int crc_offset);
409e8d4e5ffSJeff Cody uint32_t vhdx_checksum_calc(uint32_t crc, uint8_t *buf, size_t size,
410e8d4e5ffSJeff Cody int crc_offset);
411e8d4e5ffSJeff Cody
412e8d4e5ffSJeff Cody bool vhdx_checksum_is_valid(uint8_t *buf, size_t size, int crc_offset);
413e8d4e5ffSJeff Cody
414b7cfc7d5SKevin Wolf int GRAPH_RDLOCK
415b7cfc7d5SKevin Wolf vhdx_parse_log(BlockDriverState *bs, BDRVVHDXState *s, bool *flushed,
4167e30e6a6SJeff Cody Error **errp);
417e8d4e5ffSJeff Cody
418f6b08994SPaolo Bonzini int coroutine_fn GRAPH_RDLOCK
419f6b08994SPaolo Bonzini vhdx_log_write_and_flush(BlockDriverState *bs, BDRVVHDXState *s,
4208adc5233SJeff Cody void *data, uint32_t length, uint64_t offset);
4218adc5233SJeff Cody
leguid_to_cpus(MSGUID * guid)4224f18b782SJeff Cody static inline void leguid_to_cpus(MSGUID *guid)
423e8d4e5ffSJeff Cody {
4241229e46dSPeter Maydell guid->data1 = le32_to_cpu(guid->data1);
4251229e46dSPeter Maydell guid->data2 = le16_to_cpu(guid->data2);
4261229e46dSPeter Maydell guid->data3 = le16_to_cpu(guid->data3);
427e8d4e5ffSJeff Cody }
428e8d4e5ffSJeff Cody
cpu_to_leguids(MSGUID * guid)4294f18b782SJeff Cody static inline void cpu_to_leguids(MSGUID *guid)
4304f18b782SJeff Cody {
4311229e46dSPeter Maydell guid->data1 = cpu_to_le32(guid->data1);
4321229e46dSPeter Maydell guid->data2 = cpu_to_le16(guid->data2);
4331229e46dSPeter Maydell guid->data3 = cpu_to_le16(guid->data3);
4344f18b782SJeff Cody }
4354f18b782SJeff Cody
4360f48e8f0SJeff Cody void vhdx_header_le_import(VHDXHeader *h);
4370f48e8f0SJeff Cody void vhdx_header_le_export(VHDXHeader *orig_h, VHDXHeader *new_h);
4380f48e8f0SJeff Cody void vhdx_log_desc_le_import(VHDXLogDescriptor *d);
4390f48e8f0SJeff Cody void vhdx_log_desc_le_export(VHDXLogDescriptor *d);
4404f75b52aSJeff Cody void vhdx_log_data_le_import(VHDXLogDataSector *d);
4410f48e8f0SJeff Cody void vhdx_log_data_le_export(VHDXLogDataSector *d);
4420f48e8f0SJeff Cody void vhdx_log_entry_hdr_le_import(VHDXLogEntryHeader *hdr);
4430f48e8f0SJeff Cody void vhdx_log_entry_hdr_le_export(VHDXLogEntryHeader *hdr);
444c325ee1dSJeff Cody void vhdx_region_header_le_import(VHDXRegionTableHeader *hdr);
445c325ee1dSJeff Cody void vhdx_region_header_le_export(VHDXRegionTableHeader *hdr);
446c325ee1dSJeff Cody void vhdx_region_entry_le_import(VHDXRegionTableEntry *e);
447c325ee1dSJeff Cody void vhdx_region_entry_le_export(VHDXRegionTableEntry *e);
448c325ee1dSJeff Cody void vhdx_metadata_header_le_import(VHDXMetadataTableHeader *hdr);
449c325ee1dSJeff Cody void vhdx_metadata_header_le_export(VHDXMetadataTableHeader *hdr);
450c325ee1dSJeff Cody void vhdx_metadata_entry_le_import(VHDXMetadataTableEntry *e);
451c325ee1dSJeff Cody void vhdx_metadata_entry_le_export(VHDXMetadataTableEntry *e);
452*65ff757dSKevin Wolf
453*65ff757dSKevin Wolf int GRAPH_RDLOCK
454*65ff757dSKevin Wolf vhdx_user_visible_write(BlockDriverState *bs, BDRVVHDXState *s);
455c3906c5eSJeff Cody
456203cdba3SJeff Cody #endif
457