VirtualBox

source: vbox/trunk/src/VBox/Storage/VDICore.h@ 39417

Last change on this file since 39417 was 38876, checked in by vboxsync, 13 years ago

Storage: Add async discard API

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.8 KB
Line 
1/* $Id: VDICore.h 38876 2011-09-27 09:03:15Z vboxsync $ */
2/** @file
3 * Virtual Disk Image (VDI), Core Code Header (internal).
4 */
5
6/*
7 * Copyright (C) 2006-2011 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#ifndef ___VDICore_h___
19
20
21/*******************************************************************************
22* Header Files *
23*******************************************************************************/
24#include <VBox/vd.h>
25#include <VBox/err.h>
26
27#include <VBox/log.h>
28#include <iprt/alloc.h>
29#include <iprt/assert.h>
30#include <iprt/uuid.h>
31#include <iprt/string.h>
32#include <iprt/asm.h>
33
34
35/*******************************************************************************
36* Constants And Macros, Structures and Typedefs *
37*******************************************************************************/
38
39/** Image info, not handled anyhow.
40 * Must be less than 64 bytes in length, including the trailing 0.
41 */
42#define VDI_IMAGE_FILE_INFO "<<< Oracle VM VirtualBox Disk Image >>>\n"
43
44/** The Sector size.
45 * Currently we support only 512 bytes sectors.
46 */
47#define VDI_GEOMETRY_SECTOR_SIZE (512)
48/** 512 = 2^^9 */
49#define VDI_GEOMETRY_SECTOR_SHIFT (9)
50
51/**
52 * Harddisk geometry.
53 */
54#pragma pack(1)
55typedef struct VDIDISKGEOMETRY
56{
57 /** Cylinders. */
58 uint32_t cCylinders;
59 /** Heads. */
60 uint32_t cHeads;
61 /** Sectors per track. */
62 uint32_t cSectors;
63 /** Sector size. (bytes per sector) */
64 uint32_t cbSector;
65} VDIDISKGEOMETRY, *PVDIDISKGEOMETRY;
66#pragma pack()
67
68/** Image signature. */
69#define VDI_IMAGE_SIGNATURE (0xbeda107f)
70
71/**
72 * Pre-Header to be stored in image file - used for version control.
73 */
74#pragma pack(1)
75typedef struct VDIPREHEADER
76{
77 /** Just text info about image type, for eyes only. */
78 char szFileInfo[64];
79 /** The image signature (VDI_IMAGE_SIGNATURE). */
80 uint32_t u32Signature;
81 /** The image version (VDI_IMAGE_VERSION). */
82 uint32_t u32Version;
83} VDIPREHEADER, *PVDIPREHEADER;
84#pragma pack()
85
86/**
87 * Size of szComment field of HDD image header.
88 */
89#define VDI_IMAGE_COMMENT_SIZE 256
90
91/**
92 * Header to be stored in image file, VDI_IMAGE_VERSION_MAJOR = 0.
93 * Prepended by VDIPREHEADER.
94 */
95#pragma pack(1)
96typedef struct VDIHEADER0
97{
98 /** The image type (VDI_IMAGE_TYPE_*). */
99 uint32_t u32Type;
100 /** Image flags (VDI_IMAGE_FLAGS_*). */
101 uint32_t fFlags;
102 /** Image comment. (UTF-8) */
103 char szComment[VDI_IMAGE_COMMENT_SIZE];
104 /** Legacy image geometry (previous code stored PCHS there). */
105 VDIDISKGEOMETRY LegacyGeometry;
106 /** Size of disk (in bytes). */
107 uint64_t cbDisk;
108 /** Block size. (For instance VDI_IMAGE_BLOCK_SIZE.) */
109 uint32_t cbBlock;
110 /** Number of blocks. */
111 uint32_t cBlocks;
112 /** Number of allocated blocks. */
113 uint32_t cBlocksAllocated;
114 /** UUID of image. */
115 RTUUID uuidCreate;
116 /** UUID of image's last modification. */
117 RTUUID uuidModify;
118 /** Only for secondary images - UUID of primary image. */
119 RTUUID uuidLinkage;
120} VDIHEADER0, *PVDIHEADER0;
121#pragma pack()
122
123/**
124 * Header to be stored in image file, VDI_IMAGE_VERSION_MAJOR = 1,
125 * VDI_IMAGE_VERSION_MINOR = 1. Prepended by VDIPREHEADER.
126 */
127#pragma pack(1)
128typedef struct VDIHEADER1
129{
130 /** Size of this structure in bytes. */
131 uint32_t cbHeader;
132 /** The image type (VDI_IMAGE_TYPE_*). */
133 uint32_t u32Type;
134 /** Image flags (VDI_IMAGE_FLAGS_*). */
135 uint32_t fFlags;
136 /** Image comment. (UTF-8) */
137 char szComment[VDI_IMAGE_COMMENT_SIZE];
138 /** Offset of Blocks array from the beginning of image file.
139 * Should be sector-aligned for HDD access optimization. */
140 uint32_t offBlocks;
141 /** Offset of image data from the beginning of image file.
142 * Should be sector-aligned for HDD access optimization. */
143 uint32_t offData;
144 /** Legacy image geometry (previous code stored PCHS there). */
145 VDIDISKGEOMETRY LegacyGeometry;
146 /** Was BIOS HDD translation mode, now unused. */
147 uint32_t u32Dummy;
148 /** Size of disk (in bytes). */
149 uint64_t cbDisk;
150 /** Block size. (For instance VDI_IMAGE_BLOCK_SIZE.) Should be a power of 2! */
151 uint32_t cbBlock;
152 /** Size of additional service information of every data block.
153 * Prepended before block data. May be 0.
154 * Should be a power of 2 and sector-aligned for optimization reasons. */
155 uint32_t cbBlockExtra;
156 /** Number of blocks. */
157 uint32_t cBlocks;
158 /** Number of allocated blocks. */
159 uint32_t cBlocksAllocated;
160 /** UUID of image. */
161 RTUUID uuidCreate;
162 /** UUID of image's last modification. */
163 RTUUID uuidModify;
164 /** Only for secondary images - UUID of previous image. */
165 RTUUID uuidLinkage;
166 /** Only for secondary images - UUID of previous image's last modification. */
167 RTUUID uuidParentModify;
168} VDIHEADER1, *PVDIHEADER1;
169#pragma pack()
170
171/**
172 * Header to be stored in image file, VDI_IMAGE_VERSION_MAJOR = 1,
173 * VDI_IMAGE_VERSION_MINOR = 1, the slightly changed variant necessary as the
174 * old released code doesn't support changing the minor version at all.
175 */
176#pragma pack(1)
177typedef struct VDIHEADER1PLUS
178{
179 /** Size of this structure in bytes. */
180 uint32_t cbHeader;
181 /** The image type (VDI_IMAGE_TYPE_*). */
182 uint32_t u32Type;
183 /** Image flags (VDI_IMAGE_FLAGS_*). */
184 uint32_t fFlags;
185 /** Image comment. (UTF-8) */
186 char szComment[VDI_IMAGE_COMMENT_SIZE];
187 /** Offset of blocks array from the beginning of image file.
188 * Should be sector-aligned for HDD access optimization. */
189 uint32_t offBlocks;
190 /** Offset of image data from the beginning of image file.
191 * Should be sector-aligned for HDD access optimization. */
192 uint32_t offData;
193 /** Legacy image geometry (previous code stored PCHS there). */
194 VDIDISKGEOMETRY LegacyGeometry;
195 /** Was BIOS HDD translation mode, now unused. */
196 uint32_t u32Dummy;
197 /** Size of disk (in bytes). */
198 uint64_t cbDisk;
199 /** Block size. (For instance VDI_IMAGE_BLOCK_SIZE.) Should be a power of 2! */
200 uint32_t cbBlock;
201 /** Size of additional service information of every data block.
202 * Prepended before block data. May be 0.
203 * Should be a power of 2 and sector-aligned for optimization reasons. */
204 uint32_t cbBlockExtra;
205 /** Number of blocks. */
206 uint32_t cBlocks;
207 /** Number of allocated blocks. */
208 uint32_t cBlocksAllocated;
209 /** UUID of image. */
210 RTUUID uuidCreate;
211 /** UUID of image's last modification. */
212 RTUUID uuidModify;
213 /** Only for secondary images - UUID of previous image. */
214 RTUUID uuidLinkage;
215 /** Only for secondary images - UUID of previous image's last modification. */
216 RTUUID uuidParentModify;
217 /** LCHS image geometry (new field in VDI1.2 version. */
218 VDIDISKGEOMETRY LCHSGeometry;
219} VDIHEADER1PLUS, *PVDIHEADER1PLUS;
220#pragma pack()
221
222/**
223 * Header structure for all versions.
224 */
225typedef struct VDIHEADER
226{
227 unsigned uVersion;
228 union
229 {
230 VDIHEADER0 v0;
231 VDIHEADER1 v1;
232 VDIHEADER1PLUS v1plus;
233 } u;
234} VDIHEADER, *PVDIHEADER;
235
236/**
237 * File alignment boundary for both the block array and data area. Should be
238 * at least the size of a physical sector on disk for performance reasons.
239 * With the growing market share of disks with 4K sectors this needs to be
240 * bumped, and maybe again later. */
241#define VDI_DATA_ALIGN _4K
242
243/** Block 'pointer'. */
244typedef uint32_t VDIIMAGEBLOCKPOINTER;
245/** Pointer to a block 'pointer'. */
246typedef VDIIMAGEBLOCKPOINTER *PVDIIMAGEBLOCKPOINTER;
247
248/**
249 * Block marked as free is not allocated in image file, read from this
250 * block may returns any random data.
251 */
252#define VDI_IMAGE_BLOCK_FREE ((VDIIMAGEBLOCKPOINTER)~0)
253
254/**
255 * Block marked as zero is not allocated in image file, read from this
256 * block returns zeroes.
257 */
258#define VDI_IMAGE_BLOCK_ZERO ((VDIIMAGEBLOCKPOINTER)~1)
259
260/**
261 * Block 'pointer' >= VDI_IMAGE_BLOCK_UNALLOCATED indicates block is not
262 * allocated in image file.
263 */
264#define VDI_IMAGE_BLOCK_UNALLOCATED (VDI_IMAGE_BLOCK_ZERO)
265#define IS_VDI_IMAGE_BLOCK_ALLOCATED(bp) (bp < VDI_IMAGE_BLOCK_UNALLOCATED)
266
267#define GET_MAJOR_HEADER_VERSION(ph) (VDI_GET_VERSION_MAJOR((ph)->uVersion))
268#define GET_MINOR_HEADER_VERSION(ph) (VDI_GET_VERSION_MINOR((ph)->uVersion))
269
270/** @name VDI image types
271 * @{ */
272typedef enum VDIIMAGETYPE
273{
274 /** Normal dynamically growing base image file. */
275 VDI_IMAGE_TYPE_NORMAL = 1,
276 /** Preallocated base image file of a fixed size. */
277 VDI_IMAGE_TYPE_FIXED,
278 /** Dynamically growing image file for undo/commit changes support. */
279 VDI_IMAGE_TYPE_UNDO,
280 /** Dynamically growing image file for differencing support. */
281 VDI_IMAGE_TYPE_DIFF,
282
283 /** First valid image type value. */
284 VDI_IMAGE_TYPE_FIRST = VDI_IMAGE_TYPE_NORMAL,
285 /** Last valid image type value. */
286 VDI_IMAGE_TYPE_LAST = VDI_IMAGE_TYPE_DIFF
287} VDIIMAGETYPE;
288/** Pointer to VDI image type. */
289typedef VDIIMAGETYPE *PVDIIMAGETYPE;
290/** @} */
291
292/*******************************************************************************
293* Internal Functions for header access *
294*******************************************************************************/
295DECLINLINE(VDIIMAGETYPE) getImageType(PVDIHEADER ph)
296{
297 switch (GET_MAJOR_HEADER_VERSION(ph))
298 {
299 case 0: return (VDIIMAGETYPE)ph->u.v0.u32Type;
300 case 1: return (VDIIMAGETYPE)ph->u.v1.u32Type;
301 }
302 AssertFailed();
303 return (VDIIMAGETYPE)0;
304}
305
306DECLINLINE(unsigned) getImageFlags(PVDIHEADER ph)
307{
308 switch (GET_MAJOR_HEADER_VERSION(ph))
309 {
310 case 0:
311 /* VDI image flag conversion to VD image flags. */
312 return ph->u.v0.fFlags << 8;
313 case 1:
314 /* VDI image flag conversion to VD image flags. */
315 return ph->u.v1.fFlags << 8;
316 }
317 AssertFailed();
318 return 0;
319}
320
321DECLINLINE(char *) getImageComment(PVDIHEADER ph)
322{
323 switch (GET_MAJOR_HEADER_VERSION(ph))
324 {
325 case 0: return &ph->u.v0.szComment[0];
326 case 1: return &ph->u.v1.szComment[0];
327 }
328 AssertFailed();
329 return NULL;
330}
331
332DECLINLINE(unsigned) getImageBlocksOffset(PVDIHEADER ph)
333{
334 switch (GET_MAJOR_HEADER_VERSION(ph))
335 {
336 case 0: return (sizeof(VDIPREHEADER) + sizeof(VDIHEADER0));
337 case 1: return ph->u.v1.offBlocks;
338 }
339 AssertFailed();
340 return 0;
341}
342
343DECLINLINE(uint32_t) getImageDataOffset(PVDIHEADER ph)
344{
345 switch (GET_MAJOR_HEADER_VERSION(ph))
346 {
347 case 0: return sizeof(VDIPREHEADER) + sizeof(VDIHEADER0) + \
348 (ph->u.v0.cBlocks * sizeof(VDIIMAGEBLOCKPOINTER));
349 case 1: return ph->u.v1.offData;
350 }
351 AssertFailed();
352 return 0;
353}
354
355DECLINLINE(void) setImageDataOffset(PVDIHEADER ph, uint32_t offData)
356{
357 switch (GET_MAJOR_HEADER_VERSION(ph))
358 {
359 case 0: return;
360 case 1: ph->u.v1.offData = offData; return;
361 }
362 AssertFailed();
363}
364
365DECLINLINE(PVDIDISKGEOMETRY) getImageLCHSGeometry(PVDIHEADER ph)
366{
367 switch (GET_MAJOR_HEADER_VERSION(ph))
368 {
369 case 0: return NULL;
370 case 1:
371 switch (GET_MINOR_HEADER_VERSION(ph))
372 {
373 case 1:
374 if (ph->u.v1.cbHeader < sizeof(ph->u.v1plus))
375 return NULL;
376 else
377 return &ph->u.v1plus.LCHSGeometry;
378 }
379 }
380 AssertFailed();
381 return NULL;
382}
383
384DECLINLINE(uint64_t) getImageDiskSize(PVDIHEADER ph)
385{
386 switch (GET_MAJOR_HEADER_VERSION(ph))
387 {
388 case 0: return ph->u.v0.cbDisk;
389 case 1: return ph->u.v1.cbDisk;
390 }
391 AssertFailed();
392 return 0;
393}
394
395DECLINLINE(void) setImageDiskSize(PVDIHEADER ph, uint64_t cbDisk)
396{
397 switch (GET_MAJOR_HEADER_VERSION(ph))
398 {
399 case 0: ph->u.v0.cbDisk = cbDisk; return;
400 case 1: ph->u.v1.cbDisk = cbDisk; return;
401 }
402 AssertFailed();
403}
404
405DECLINLINE(unsigned) getImageBlockSize(PVDIHEADER ph)
406{
407 switch (GET_MAJOR_HEADER_VERSION(ph))
408 {
409 case 0: return ph->u.v0.cbBlock;
410 case 1: return ph->u.v1.cbBlock;
411 }
412 AssertFailed();
413 return 0;
414}
415
416DECLINLINE(unsigned) getImageExtraBlockSize(PVDIHEADER ph)
417{
418 switch (GET_MAJOR_HEADER_VERSION(ph))
419 {
420 case 0: return 0;
421 case 1: return ph->u.v1.cbBlockExtra;
422 }
423 AssertFailed();
424 return 0;
425}
426
427DECLINLINE(unsigned) getImageBlocks(PVDIHEADER ph)
428{
429 switch (GET_MAJOR_HEADER_VERSION(ph))
430 {
431 case 0: return ph->u.v0.cBlocks;
432 case 1: return ph->u.v1.cBlocks;
433 }
434 AssertFailed();
435 return 0;
436}
437
438DECLINLINE(void) setImageBlocks(PVDIHEADER ph, unsigned cBlocks)
439{
440 switch (GET_MAJOR_HEADER_VERSION(ph))
441 {
442 case 0: ph->u.v0.cBlocks = cBlocks; return;
443 case 1: ph->u.v1.cBlocks = cBlocks; return;
444 }
445 AssertFailed();
446}
447
448
449DECLINLINE(unsigned) getImageBlocksAllocated(PVDIHEADER ph)
450{
451 switch (GET_MAJOR_HEADER_VERSION(ph))
452 {
453 case 0: return ph->u.v0.cBlocksAllocated;
454 case 1: return ph->u.v1.cBlocksAllocated;
455 }
456 AssertFailed();
457 return 0;
458}
459
460DECLINLINE(void) setImageBlocksAllocated(PVDIHEADER ph, unsigned cBlocks)
461{
462 switch (GET_MAJOR_HEADER_VERSION(ph))
463 {
464 case 0: ph->u.v0.cBlocksAllocated = cBlocks; return;
465 case 1: ph->u.v1.cBlocksAllocated = cBlocks; return;
466 }
467 AssertFailed();
468}
469
470DECLINLINE(PRTUUID) getImageCreationUUID(PVDIHEADER ph)
471{
472 switch (GET_MAJOR_HEADER_VERSION(ph))
473 {
474 case 0: return &ph->u.v0.uuidCreate;
475 case 1: return &ph->u.v1.uuidCreate;
476 }
477 AssertFailed();
478 return NULL;
479}
480
481DECLINLINE(PRTUUID) getImageModificationUUID(PVDIHEADER ph)
482{
483 switch (GET_MAJOR_HEADER_VERSION(ph))
484 {
485 case 0: return &ph->u.v0.uuidModify;
486 case 1: return &ph->u.v1.uuidModify;
487 }
488 AssertFailed();
489 return NULL;
490}
491
492DECLINLINE(PRTUUID) getImageParentUUID(PVDIHEADER ph)
493{
494 switch (GET_MAJOR_HEADER_VERSION(ph))
495 {
496 case 0: return &ph->u.v0.uuidLinkage;
497 case 1: return &ph->u.v1.uuidLinkage;
498 }
499 AssertFailed();
500 return NULL;
501}
502
503DECLINLINE(PRTUUID) getImageParentModificationUUID(PVDIHEADER ph)
504{
505 switch (GET_MAJOR_HEADER_VERSION(ph))
506 {
507 case 1: return &ph->u.v1.uuidParentModify;
508 }
509 AssertFailed();
510 return NULL;
511}
512
513/**
514 * Image structure
515 */
516typedef struct VDIIMAGEDESC
517{
518 /** Opaque storage handle. */
519 PVDIOSTORAGE pStorage;
520 /** Image open flags, VD_OPEN_FLAGS_*. */
521 unsigned uOpenFlags;
522 /** Image pre-header. */
523 VDIPREHEADER PreHeader;
524 /** Image header. */
525 VDIHEADER Header;
526 /** Pointer to a block array. */
527 PVDIIMAGEBLOCKPOINTER paBlocks;
528 /** Pointer to the block array for back resolving (used if discarding is enabled). */
529 unsigned *paBlocksRev;
530 /** fFlags copy from image header, for speed optimization. */
531 unsigned uImageFlags;
532 /** Start offset of block array in image file, here for speed optimization. */
533 unsigned offStartBlocks;
534 /** Start offset of data in image file, here for speed optimization. */
535 unsigned offStartData;
536 /** Block mask for getting the offset into a block from a byte hdd offset. */
537 unsigned uBlockMask;
538 /** Block shift value for converting byte hdd offset into paBlock index. */
539 unsigned uShiftOffset2Index;
540 /** Offset of data from the beginning of block. */
541 unsigned offStartBlockData;
542 /** Total size of image block (including the extra data). */
543 unsigned cbTotalBlockData;
544 /** Container filename. (UTF-8) */
545 const char *pszFilename;
546 /** Physical geometry of this image (never actually stored). */
547 VDGEOMETRY PCHSGeometry;
548 /** Pointer to the per-disk VD interface list. */
549 PVDINTERFACE pVDIfsDisk;
550 /** Pointer to the per-image VD interface list. */
551 PVDINTERFACE pVDIfsImage;
552 /** Error interface. */
553 PVDINTERFACEERROR pIfError;
554 /** I/O interface. */
555 PVDINTERFACEIOINT pIfIo;
556} VDIIMAGEDESC, *PVDIIMAGEDESC;
557
558/**
559 * Async block discard states.
560 */
561typedef enum VDIBLOCKDISCARDSTATE
562{
563 /** Invalid. */
564 VDIBLOCKDISCARDSTATE_INVALID = 0,
565 /** Read the last block. */
566 VDIBLOCKDISCARDSTATE_READ_BLOCK,
567 /** Write block into the hole. */
568 VDIBLOCKDISCARDSTATE_WRITE_BLOCK,
569 /** Update metadata. */
570 VDIBLOCKDISCARDSTATE_UPDATE_METADATA,
571 /** 32bit hack. */
572 VDIBLOCKDISCARDSTATE_32BIT_HACK = 0x7fffffff
573} VDIBLOCKDISCARDSTATE;
574
575/**
576 * Async block discard structure.
577 */
578typedef struct VDIBLOCKDISCARDASYNC
579{
580 /** State of the block discard. */
581 VDIBLOCKDISCARDSTATE enmState;
582 /** Pointer to the block data. */
583 void *pvBlock;
584 /** Block index in the block table. */
585 unsigned uBlock;
586 /** Block pointer to the block to discard. */
587 VDIIMAGEBLOCKPOINTER ptrBlockDiscard;
588 /** Index of the last block in the reverse block table. */
589 unsigned idxLastBlock;
590 /** Index of the last block in the block table (gathered from the reverse block table). */
591 unsigned uBlockLast;
592} VDIBLOCKDISCARDASYNC, *PVDIBLOCKDISCARDASYNC;
593
594#endif
595
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette