VirtualBox

source: vbox/trunk/src/VBox/Storage/VCICache.cpp@ 36140

Last change on this file since 36140 was 33745, checked in by vboxsync, 14 years ago

VCI: Updates

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 68.3 KB
Line 
1/* $Id: VCICache.cpp 33745 2010-11-03 18:31:53Z vboxsync $ */
2/** @file
3 * VCICacheCore - VirtualBox Cache Image, Core Code.
4 */
5
6/*
7 * Copyright (C) 2006-2010 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/*******************************************************************************
19* Header Files *
20*******************************************************************************/
21#define LOG_GROUP LOG_GROUP_VD_RAW /** @todo logging group */
22#include <VBox/vd-cache-plugin.h>
23#include <VBox/err.h>
24
25#include <VBox/log.h>
26#include <iprt/assert.h>
27#include <iprt/alloc.h>
28#include <iprt/file.h>
29#include <iprt/asm.h>
30
31/*******************************************************************************
32* On disk data structures *
33*******************************************************************************/
34
35/** @note All structures which are written to the disk are written in camel case
36 * and packed. */
37
38/** Block size used internally, because we cache sectors the smallest unit we
39 * have to care about is 512 bytes. */
40#define VCI_BLOCK_SIZE 512
41
42/** Convert block number/size to byte offset/size. */
43#define VCI_BLOCK2BYTE(u) ((uint64_t)(u) << 9)
44
45/** Convert byte offset/size to block number/size. */
46#define VCI_BYTE2BLOCK(u) ((u) >> 9)
47
48/**
49 * The VCI header - at the beginning of the file.
50 *
51 * All entries a stored in little endian order.
52 */
53#pragma pack(1)
54typedef struct VciHdr
55{
56 /** The signature to identify a cache image. */
57 uint32_t u32Signature;
58 /** Version of the layout of metadata in the cache. */
59 uint32_t u32Version;
60 /** Maximum size of the cache file in blocks.
61 * This includes all metadata. */
62 uint64_t cBlocksCache;
63 /** Flag indicating whether the cache was closed cleanly. */
64 uint8_t fUncleanShutdown;
65 /** Cache type. */
66 uint32_t u32CacheType;
67 /** Offset of the B+-Tree root in the image in blocks. */
68 uint64_t offTreeRoot;
69 /** Offset of the block allocation bitmap in blocks. */
70 uint64_t offBlkMap;
71 /** Size of the block allocation bitmap in blocks. */
72 uint32_t cBlkMap;
73 /** UUID of the image. */
74 RTUUID uuidImage;
75 /** Modification UUID for the cache. */
76 RTUUID uuidModification;
77 /** Reserved for future use. */
78 uint8_t abReserved[951];
79} VciHdr, *PVciHdr;
80#pragma pack()
81AssertCompileSize(VciHdr, 2 * VCI_BLOCK_SIZE);
82
83/** VCI signature to identify a valid image. */
84#define VCI_HDR_SIGNATURE UINT32_C(0x00494356) /* \0ICV */
85/** Current version we support. */
86#define VCI_HDR_VERSION UINT32_C(0x00000001)
87
88/** Value for an unclean cache shutdown. */
89#define VCI_HDR_UNCLEAN_SHUTDOWN UINT8_C(0x01)
90/** Value for a clean cache shutdown. */
91#define VCI_HDR_CLEAN_SHUTDOWN UINT8_C(0x00)
92
93/** Cache type: Dynamic image growing to the maximum value. */
94#define VCI_HDR_CACHE_TYPE_DYNAMIC UINT32_C(0x00000001)
95/** Cache type: Fixed image, space is preallocated. */
96#define VCI_HDR_CACHE_TYPE_FIXED UINT32_C(0x00000002)
97
98/**
99 * On disk representation of an extent describing a range of cached data.
100 *
101 * All entries a stored in little endian order.
102 */
103#pragma pack(1)
104typedef struct VciCacheExtent
105{
106 /** Block address of the previous extent in the LRU list. */
107 uint64_t u64ExtentPrev;
108 /** Block address of the next extent in the LRU list. */
109 uint64_t u64ExtentNext;
110 /** Flags (for compression, encryption etc.) - currently unused and should be always 0. */
111 uint8_t u8Flags;
112 /** Reserved */
113 uint8_t u8Reserved;
114 /** First block of cached data the extent represents. */
115 uint64_t u64BlockOffset;
116 /** Number of blocks the extent represents. */
117 uint32_t u32Blocks;
118 /** First block in the image where the data is stored. */
119 uint64_t u64BlockAddr;
120} VciCacheExtent, *PVciCacheExtent;
121#pragma pack()
122AssertCompileSize(VciCacheExtent, 38);
123
124/**
125 * On disk representation of an internal node.
126 *
127 * All entries a stored in little endian order.
128 */
129#pragma pack(1)
130typedef struct VciTreeNodeInternal
131{
132 /** First block of cached data the internal node represents. */
133 uint64_t u64BlockOffset;
134 /** Number of blocks the internal node represents. */
135 uint32_t u32Blocks;
136 /** Block address in the image where the next node in the tree is stored. */
137 uint64_t u64ChildAddr;
138} VciTreeNodeInternal, *PVciTreeNodeInternal;
139#pragma pack()
140AssertCompileSize(VciTreeNodeInternal, 20);
141
142/**
143 * On-disk representation of a node in the B+-Tree.
144 *
145 * All entries a stored in little endian order.
146 */
147#pragma pack(1)
148typedef struct VciTreeNode
149{
150 /** Type of the node (root, internal, leaf). */
151 uint8_t u8Type;
152 /** Data in the node. */
153 uint8_t au8Data[4095];
154} VciTreeNode, *PVciTreeNode;
155#pragma pack()
156AssertCompileSize(VciTreeNode, 8 * VCI_BLOCK_SIZE);
157
158/** Node type: Internal node containing links to other nodes (VciTreeNodeInternal). */
159#define VCI_TREE_NODE_TYPE_INTERNAL UINT8_C(0x01)
160/** Node type: Leaf of the tree (VciCacheExtent). */
161#define VCI_TREE_NODE_TYPE_LEAF UINT8_C(0x02)
162
163/** Number of cache extents described by one node. */
164#define VCI_TREE_EXTENTS_PER_NODE ((sizeof(VciTreeNode)-1) / sizeof(VciCacheExtent))
165/** Number of internal nodes managed by one tree node. */
166#define VCI_TREE_INTERNAL_NODES_PER_NODE ((sizeof(VciTreeNode)-1) / sizeof(VciTreeNodeInternal))
167
168/**
169 * VCI block bitmap header.
170 *
171 * All entries a stored in little endian order.
172 */
173#pragma pack(1)
174typedef struct VciBlkMap
175{
176 /** Magic of the block bitmap. */
177 uint32_t u32Magic;
178 /** Version of the block bitmap. */
179 uint32_t u32Version;
180 /** Number of blocks this block map manages. */
181 uint64_t cBlocks;
182 /** Number of free blocks. */
183 uint64_t cBlocksFree;
184 /** Number of blocks allocated for metadata. */
185 uint64_t cBlocksAllocMeta;
186 /** Number of blocks allocated for actual cached data. */
187 uint64_t cBlocksAllocData;
188 /** Reserved for future use. */
189 uint8_t au8Reserved[472];
190} VciBlkMap, *PVciBlkMap;
191#pragma pack()
192AssertCompileSize(VciBlkMap, VCI_BLOCK_SIZE);
193
194/** The magic which identifies a block map. */
195#define VCI_BLKMAP_MAGIC UINT32_C(0x4b4c4256) /* KLBV */
196/** Current version. */
197#define VCI_BLKMAP_VERSION UINT32_C(0x00000001)
198
199/** Block bitmap entry */
200typedef uint8_t VciBlkMapEnt;
201
202/*******************************************************************************
203* Constants And Macros, Structures and Typedefs *
204*******************************************************************************/
205
206/**
207 * Block range descriptor.
208 */
209typedef struct VCIBLKRANGEDESC
210{
211 /** Previous entry in the list. */
212 struct VCIBLKRANGEDESC *pPrev;
213 /** Next entry in the list. */
214 struct VCIBLKRANGEDESC *pNext;
215 /** Start address of the range. */
216 uint64_t offAddrStart;
217 /** Number of blocks in the range. */
218 uint64_t cBlocks;
219 /** Flag whether the range is free or allocated. */
220 bool fFree;
221} VCIBLKRANGEDESC, *PVCIBLKRANGEDESC;
222
223/**
224 * Block map for the cache image - in memory structure.
225 */
226typedef struct VCIBLKMAP
227{
228 /** Number of blocks the map manages. */
229 uint64_t cBlocks;
230 /** Number of blocks allocated for metadata. */
231 uint64_t cBlocksAllocMeta;
232 /** Number of blocks allocated for actual cached data. */
233 uint64_t cBlocksAllocData;
234 /** Number of free blocks. */
235 uint64_t cBlocksFree;
236
237 /** Pointer to the head of the block range list. */
238 PVCIBLKRANGEDESC pRangesHead;
239 /** Pointer to the tail of the block range list. */
240 PVCIBLKRANGEDESC pRangesTail;
241
242} VCIBLKMAP;
243/** Pointer to a block map. */
244typedef VCIBLKMAP *PVCIBLKMAP;
245
246/**
247 * B+-Tree node header.
248 */
249typedef struct VCITREENODE
250{
251 /** Type of the node (VCI_TREE_NODE_TYPE_*). */
252 uint8_t u8Type;
253 /** Block address where the node is stored. */
254 uint64_t u64BlockAddr;
255 /** Pointer to the parent. */
256 struct VCITREENODE *pParent;
257} VCITREENODE, *PVCITREENODE;
258
259/**
260 * B+-Tree node pointer.
261 */
262typedef struct VCITREENODEPTR
263{
264 /** Flag whether the node is in memory or still on the disk. */
265 bool fInMemory;
266 /** Type dependent data. */
267 union
268 {
269 /** Pointer to a in memory node. */
270 PVCITREENODE pNode;
271 /** Start block address of the node. */
272 uint64_t offAddrBlockNode;
273 } u;
274} VCITREENODEPTR, *PVCITREENODEPTR;
275
276/**
277 * Internal node.
278 */
279typedef struct VCINODEINTERNAL
280{
281 /** First block of cached data the internal node represents. */
282 uint64_t u64BlockOffset;
283 /** Number of blocks the internal node represents. */
284 uint32_t u32Blocks;
285 /** Pointer to the child node. */
286 VCITREENODEPTR PtrChild;
287} VCINODEINTERNAL, *PVCINODEINTERNAL;
288
289/**
290 * A in memory internal B+-tree node.
291 */
292typedef struct VCITREENODEINT
293{
294 /** Node core. */
295 VCITREENODE Core;
296 /** Number of used nodes. */
297 unsigned cUsedNodes;
298 /** Array of internal nodes. */
299 VCINODEINTERNAL aIntNodes[VCI_TREE_INTERNAL_NODES_PER_NODE];
300} VCITREENODEINT, *PVCITREENODEINT;
301
302/**
303 * A in memory cache extent.
304 */
305typedef struct VCICACHEEXTENT
306{
307 /** First block of cached data the extent represents. */
308 uint64_t u64BlockOffset;
309 /** Number of blocks the extent represents. */
310 uint32_t u32Blocks;
311 /** First block in the image where the data is stored. */
312 uint64_t u64BlockAddr;
313} VCICACHEEXTENT, *PVCICACHEEXTENT;
314
315/**
316 * A in memory leaf B+-tree node.
317 */
318typedef struct VCITREENODELEAF
319{
320 /** Node core. */
321 VCITREENODE Core;
322 /** Number of used nodes. */
323 unsigned cUsedNodes;
324 /** The extents in the node. */
325 VCICACHEEXTENT aExtents[VCI_TREE_EXTENTS_PER_NODE];
326} VCITREENODELEAF, *PVCITREENODELEAF;
327
328/**
329 * VCI image data structure.
330 */
331typedef struct VCICACHE
332{
333 /** Image name. */
334 const char *pszFilename;
335 /** Storage handle. */
336 PVDIOSTORAGE pStorage;
337 /** I/O interface. */
338 PVDINTERFACE pInterfaceIO;
339 /** Async I/O interface callbacks. */
340 PVDINTERFACEIOINT pInterfaceIOCallbacks;
341
342 /** Pointer to the per-disk VD interface list. */
343 PVDINTERFACE pVDIfsDisk;
344 /** Pointer to the per-image VD interface list. */
345 PVDINTERFACE pVDIfsImage;
346
347 /** Error callback. */
348 PVDINTERFACE pInterfaceError;
349 /** Opaque data for error callback. */
350 PVDINTERFACEERROR pInterfaceErrorCallbacks;
351
352 /** Open flags passed by VBoxHD layer. */
353 unsigned uOpenFlags;
354 /** Image flags defined during creation or determined during open. */
355 unsigned uImageFlags;
356 /** Total size of the image. */
357 uint64_t cbSize;
358
359 /** Offset of the B+-Tree in the image in bytes. */
360 uint64_t offTreeRoot;
361 /** Pointer to the root node of the B+-Tree. */
362 PVCITREENODE pRoot;
363 /** Offset to the block allocation bitmap in bytes. */
364 uint64_t offBlksBitmap;
365 /** Block map. */
366 PVCIBLKMAP pBlkMap;
367} VCICACHE, *PVCICACHE;
368
369/** No block free in bitmap error code. */
370#define VERR_VCI_NO_BLOCKS_FREE (-65536)
371
372/*******************************************************************************
373* Static Variables *
374*******************************************************************************/
375
376/** NULL-terminated array of supported file extensions. */
377static const char *const s_apszVciFileExtensions[] =
378{
379 "vci",
380 NULL
381};
382
383/*******************************************************************************
384* Internal Functions *
385*******************************************************************************/
386
387/**
388 * Internal: signal an error to the frontend.
389 */
390DECLINLINE(int) vciError(PVCICACHE pCache, int rc, RT_SRC_POS_DECL,
391 const char *pszFormat, ...)
392{
393 va_list va;
394 va_start(va, pszFormat);
395 if (pCache->pInterfaceError)
396 pCache->pInterfaceErrorCallbacks->pfnError(pCache->pInterfaceError->pvUser, rc, RT_SRC_POS_ARGS,
397 pszFormat, va);
398 va_end(va);
399 return rc;
400}
401
402/**
403 * Internal: signal an informational message to the frontend.
404 */
405DECLINLINE(int) vciMessage(PVCICACHE pCache, const char *pszFormat, ...)
406{
407 int rc = VINF_SUCCESS;
408 va_list va;
409 va_start(va, pszFormat);
410 if (pCache->pInterfaceError)
411 rc = pCache->pInterfaceErrorCallbacks->pfnMessage(pCache->pInterfaceError->pvUser,
412 pszFormat, va);
413 va_end(va);
414 return rc;
415}
416
417
418DECLINLINE(int) vciFileOpen(PVCICACHE pCache, const char *pszFilename,
419 uint32_t fOpen)
420{
421 return pCache->pInterfaceIOCallbacks->pfnOpen(pCache->pInterfaceIO->pvUser,
422 pszFilename, fOpen,
423 &pCache->pStorage);
424}
425
426DECLINLINE(int) vciFileClose(PVCICACHE pCache)
427{
428 return pCache->pInterfaceIOCallbacks->pfnClose(pCache->pInterfaceIO->pvUser,
429 pCache->pStorage);
430}
431
432DECLINLINE(int) vciFileDelete(PVCICACHE pCache, const char *pszFilename)
433{
434 return pCache->pInterfaceIOCallbacks->pfnDelete(pCache->pInterfaceIO->pvUser,
435 pszFilename);
436}
437
438DECLINLINE(int) vciFileMove(PVCICACHE pCache, const char *pszSrc,
439 const char *pszDst, unsigned fMove)
440{
441 return pCache->pInterfaceIOCallbacks->pfnMove(pCache->pInterfaceIO->pvUser,
442 pszSrc, pszDst, fMove);
443}
444
445DECLINLINE(int) vciFileGetFreeSpace(PVCICACHE pCache, const char *pszFilename,
446 int64_t *pcbFree)
447{
448 return pCache->pInterfaceIOCallbacks->pfnGetFreeSpace(pCache->pInterfaceIO->pvUser,
449 pszFilename, pcbFree);
450}
451
452DECLINLINE(int) vciFileGetSize(PVCICACHE pCache, uint64_t *pcbSize)
453{
454 return pCache->pInterfaceIOCallbacks->pfnGetSize(pCache->pInterfaceIO->pvUser,
455 pCache->pStorage, pcbSize);
456}
457
458DECLINLINE(int) vciFileSetSize(PVCICACHE pCache, uint64_t cbSize)
459{
460 return pCache->pInterfaceIOCallbacks->pfnSetSize(pCache->pInterfaceIO->pvUser,
461 pCache->pStorage, cbSize);
462}
463
464DECLINLINE(int) vciFileWriteSync(PVCICACHE pCache, uint64_t uOffset,
465 const void *pvBuffer, size_t cbBuffer)
466{
467 return pCache->pInterfaceIOCallbacks->pfnWriteSync(pCache->pInterfaceIO->pvUser,
468 pCache->pStorage, VCI_BLOCK2BYTE(uOffset),
469 pvBuffer, VCI_BLOCK2BYTE(cbBuffer), NULL);
470}
471
472DECLINLINE(int) vciFileReadSync(PVCICACHE pCache, uint64_t uOffset,
473 void *pvBuffer, size_t cbBuffer)
474{
475 return pCache->pInterfaceIOCallbacks->pfnReadSync(pCache->pInterfaceIO->pvUser,
476 pCache->pStorage, VCI_BLOCK2BYTE(uOffset),
477 pvBuffer, VCI_BLOCK2BYTE(cbBuffer), NULL);
478}
479
480DECLINLINE(int) vciFileFlushSync(PVCICACHE pCache)
481{
482 return pCache->pInterfaceIOCallbacks->pfnFlushSync(pCache->pInterfaceIO->pvUser,
483 pCache->pStorage);
484}
485
486DECLINLINE(int) vciFileReadUserAsync(PVCICACHE pCache, uint64_t uOffset,
487 PVDIOCTX pIoCtx, size_t cbRead)
488{
489 return pCache->pInterfaceIOCallbacks->pfnReadUserAsync(pCache->pInterfaceIO->pvUser,
490 pCache->pStorage,
491 uOffset, pIoCtx,
492 cbRead);
493}
494
495DECLINLINE(int) vciFileWriteUserAsync(PVCICACHE pCache, uint64_t uOffset,
496 PVDIOCTX pIoCtx, size_t cbWrite,
497 PFNVDXFERCOMPLETED pfnComplete,
498 void *pvCompleteUser)
499{
500 return pCache->pInterfaceIOCallbacks->pfnWriteUserAsync(pCache->pInterfaceIO->pvUser,
501 pCache->pStorage,
502 uOffset, pIoCtx,
503 cbWrite,
504 pfnComplete,
505 pvCompleteUser);
506}
507
508DECLINLINE(int) vciFileFlushAsync(PVCICACHE pCache, PVDIOCTX pIoCtx,
509 PFNVDXFERCOMPLETED pfnComplete,
510 void *pvCompleteUser)
511{
512 return pCache->pInterfaceIOCallbacks->pfnFlushAsync(pCache->pInterfaceIO->pvUser,
513 pCache->pStorage,
514 pIoCtx, pfnComplete,
515 pvCompleteUser);
516}
517
518/**
519 * Internal. Flush image data to disk.
520 */
521static int vciFlushImage(PVCICACHE pCache)
522{
523 int rc = VINF_SUCCESS;
524
525 if ( pCache->pStorage
526 && !(pCache->uOpenFlags & VD_OPEN_FLAGS_READONLY))
527 rc = vciFileFlushSync(pCache);
528
529 return rc;
530}
531
532/**
533 * Internal. Free all allocated space for representing an image except pCache,
534 * and optionally delete the image from disk.
535 */
536static int vciFreeImage(PVCICACHE pCache, bool fDelete)
537{
538 int rc = VINF_SUCCESS;
539
540 /* Freeing a never allocated image (e.g. because the open failed) is
541 * not signalled as an error. After all nothing bad happens. */
542 if (pCache)
543 {
544 if (pCache->pStorage)
545 {
546 /* No point updating the file that is deleted anyway. */
547 if (!fDelete)
548 vciFlushImage(pCache);
549
550 vciFileClose(pCache);
551 pCache->pStorage = NULL;
552 }
553
554 if (fDelete && pCache->pszFilename)
555 vciFileDelete(pCache, pCache->pszFilename);
556 }
557
558 LogFlowFunc(("returns %Rrc\n", rc));
559 return rc;
560}
561
562/**
563 * Creates a new block map which can manage the given number of blocks.
564 *
565 * The size of the bitmap is aligned to the VCI block size.
566 *
567 * @returns VBox status code.
568 * @param cBlocks The number of blocks the bitmap can manage.
569 * @param ppBlkMap Where to store the pointer to the block bitmap.
570 * @param pcbBlkMap Where to store the size of the block bitmap in blocks
571 * needed on the disk.
572 */
573static int vciBlkMapCreate(uint64_t cBlocks, PVCIBLKMAP *ppBlkMap, uint32_t *pcBlkMap)
574{
575 int rc = VINF_SUCCESS;
576 uint32_t cbBlkMap = RT_ALIGN_Z(cBlocks / sizeof(VciBlkMapEnt) / 8, VCI_BLOCK_SIZE);
577 PVCIBLKMAP pBlkMap = (PVCIBLKMAP)RTMemAllocZ(sizeof(VCIBLKMAP));
578 PVCIBLKRANGEDESC pFree = (PVCIBLKRANGEDESC)RTMemAllocZ(sizeof(VCIBLKRANGEDESC));
579
580 LogFlowFunc(("cBlocks=%u ppBlkMap=%#p pcBlkMap=%#p\n", cBlocks, ppBlkMap, pcBlkMap));
581
582 if (pBlkMap && pFree)
583 {
584 pBlkMap->cBlocks = cBlocks;
585 pBlkMap->cBlocksAllocMeta = 0;
586 pBlkMap->cBlocksAllocData = 0;
587 pBlkMap->cBlocksFree = cBlocks;
588
589 pFree->pPrev = NULL;
590 pFree->pNext = NULL;
591 pFree->offAddrStart = 0;
592 pFree->cBlocks = cBlocks;
593 pFree->fFree = true;
594
595 pBlkMap->pRangesHead = pFree;
596 pBlkMap->pRangesTail = pFree;
597
598 Assert(!((cbBlkMap + sizeof(VciBlkMap)) % VCI_BLOCK_SIZE));
599 *ppBlkMap = pBlkMap;
600 *pcBlkMap = VCI_BYTE2BLOCK(cbBlkMap + sizeof(VciBlkMap));
601 }
602 else
603 {
604 if (pBlkMap)
605 RTMemFree(pBlkMap);
606 if (pFree)
607 RTMemFree(pFree);
608
609 rc = VERR_NO_MEMORY;
610 }
611
612 LogFlowFunc(("returns rc=%Rrc cBlkMap=%u\n", rc, *pcBlkMap));
613 return rc;
614}
615
616/**
617 * Frees a block map.
618 *
619 * @returns nothing.
620 * @param pBlkMap The block bitmap to destroy.
621 */
622static void vciBlkMapDestroy(PVCIBLKMAP pBlkMap)
623{
624 LogFlowFunc(("pBlkMap=%#p\n", pBlkMap));
625
626 PVCIBLKRANGEDESC pRangeCur = pBlkMap->pRangesHead;
627
628 while (pRangeCur)
629 {
630 PVCIBLKRANGEDESC pTmp = pRangeCur;
631
632 RTMemFree(pTmp);
633
634 pRangeCur = pRangeCur->pNext;
635 }
636
637 RTMemFree(pBlkMap);
638
639 LogFlowFunc(("returns\n"));
640}
641
642/**
643 * Loads the block map from the specified medium and creates all necessary
644 * in memory structures to manage used and free blocks.
645 *
646 * @returns VBox status code.
647 * @param pStorage Storage handle to read the block bitmap from.
648 * @param offBlkMap Start of the block bitmap in blocks.
649 * @param cBlkMap Size of the block bitmap on the disk in blocks.
650 * @param ppBlkMap Where to store the block bitmap on success.
651 */
652static int vciBlkMapLoad(PVCICACHE pStorage, uint64_t offBlkMap, uint32_t cBlkMap, PVCIBLKMAP *ppBlkMap)
653{
654 int rc = VINF_SUCCESS;
655 VciBlkMap BlkMap;
656
657 LogFlowFunc(("pStorage=%#p offBlkMap=%llu cBlkMap=%u ppBlkMap=%#p\n",
658 pStorage, offBlkMap, cBlkMap, ppBlkMap));
659
660 if (cBlkMap >= VCI_BYTE2BLOCK(sizeof(VciBlkMap)))
661 {
662 cBlkMap -= VCI_BYTE2BLOCK(sizeof(VciBlkMap));
663
664 rc = vciFileReadSync(pStorage, offBlkMap, &BlkMap, VCI_BYTE2BLOCK(sizeof(VciBlkMap)));
665 if (RT_SUCCESS(rc))
666 {
667 offBlkMap += VCI_BYTE2BLOCK(sizeof(VciBlkMap));
668
669 BlkMap.u32Magic = RT_LE2H_U32(BlkMap.u32Magic);
670 BlkMap.u32Version = RT_LE2H_U32(BlkMap.u32Version);
671 BlkMap.cBlocks = RT_LE2H_U32(BlkMap.cBlocks);
672 BlkMap.cBlocksFree = RT_LE2H_U32(BlkMap.cBlocksFree);
673 BlkMap.cBlocksAllocMeta = RT_LE2H_U32(BlkMap.cBlocksAllocMeta);
674 BlkMap.cBlocksAllocData = RT_LE2H_U32(BlkMap.cBlocksAllocData);
675
676 if ( BlkMap.u32Magic == VCI_BLKMAP_MAGIC
677 && BlkMap.u32Version == VCI_BLKMAP_VERSION
678 && BlkMap.cBlocks == BlkMap.cBlocksFree + BlkMap.cBlocksAllocMeta + BlkMap.cBlocksAllocData
679 && VCI_BYTE2BLOCK(BlkMap.cBlocks / 8) == cBlkMap)
680 {
681 PVCIBLKMAP pBlkMap = (PVCIBLKMAP)RTMemAllocZ(sizeof(VCIBLKMAP));
682 if (pBlkMap)
683 {
684 pBlkMap->cBlocks = BlkMap.cBlocks;
685 pBlkMap->cBlocksFree = BlkMap.cBlocksFree;
686 pBlkMap->cBlocksAllocMeta = BlkMap.cBlocksAllocMeta;
687 pBlkMap->cBlocksAllocData = BlkMap.cBlocksAllocData;
688
689 /* Load the bitmap and construct the range list. */
690 uint32_t cBlocksFree = 0;
691 uint32_t cBlocksAllocated = 0;
692 PVCIBLKRANGEDESC pRangeCur = (PVCIBLKRANGEDESC)RTMemAllocZ(sizeof(VCIBLKRANGEDESC));
693
694 if (pRangeCur)
695 {
696 uint8_t abBitmapBuffer[16 * _1K];
697 uint32_t cBlocksRead = 0;
698 uint64_t cBlocksLeft = VCI_BYTE2BLOCK(pBlkMap->cBlocks / 8);
699
700 cBlocksRead = RT_MIN(VCI_BYTE2BLOCK(sizeof(abBitmapBuffer)), cBlocksLeft);
701 rc = vciFileReadSync(pStorage, offBlkMap, abBitmapBuffer,
702 cBlocksRead);
703
704 if (RT_SUCCESS(rc))
705 {
706 pRangeCur->fFree = !(abBitmapBuffer[0] & 0x01);
707 pRangeCur->offAddrStart = 0;
708 pRangeCur->cBlocks = 0;
709 pRangeCur->pNext = NULL;
710 pRangeCur->pPrev = NULL;
711 pBlkMap->pRangesHead = pRangeCur;
712 pBlkMap->pRangesTail = pRangeCur;
713 }
714
715 while ( RT_SUCCESS(rc)
716 && cBlocksLeft)
717 {
718 int iBit = 0;
719 uint32_t cBits = VCI_BLOCK2BYTE(cBlocksRead) * 8;
720 uint32_t iBitPrev = 0xffffffff;
721
722 while (cBits)
723 {
724 if (pRangeCur->fFree)
725 {
726 /* Check for the first set bit. */
727 iBit = ASMBitNextSet(abBitmapBuffer, cBits, iBitPrev);
728 }
729 else
730 {
731 /* Check for the first free bit. */
732 iBit = ASMBitNextClear(abBitmapBuffer, cBits, iBitPrev);
733 }
734
735 if (iBit == -1)
736 {
737 /* No change. */
738 pRangeCur->cBlocks += cBits;
739 cBits = 0;
740 }
741 else
742 {
743 Assert((uint32_t)iBit < cBits);
744 pRangeCur->cBlocks += iBit;
745
746 /* Create a new range descriptor. */
747 PVCIBLKRANGEDESC pRangeNew = (PVCIBLKRANGEDESC)RTMemAllocZ(sizeof(VCIBLKRANGEDESC));
748 if (!pRangeNew)
749 {
750 rc = VERR_NO_MEMORY;
751 break;
752 }
753
754 pRangeNew->fFree = !pRangeCur->fFree;
755 pRangeNew->offAddrStart = pRangeCur->offAddrStart + pRangeCur->cBlocks;
756 pRangeNew->cBlocks = 0;
757 pRangeNew->pPrev = pRangeCur;
758 pRangeCur->pNext = pRangeNew;
759 pBlkMap->pRangesTail = pRangeNew;
760 pRangeCur = pRangeNew;
761 cBits -= iBit;
762 iBitPrev = iBit;
763 }
764 }
765
766 cBlocksLeft -= cBlocksRead;
767 offBlkMap += cBlocksRead;
768
769 if ( RT_SUCCESS(rc)
770 && cBlocksLeft)
771 {
772 /* Read next chunk. */
773 cBlocksRead = RT_MIN(VCI_BYTE2BLOCK(sizeof(abBitmapBuffer)), cBlocksLeft);
774 rc = vciFileReadSync(pStorage, offBlkMap, abBitmapBuffer, cBlocksRead);
775 }
776 }
777 }
778 else
779 rc = VERR_NO_MEMORY;
780
781 if (RT_SUCCESS(rc))
782 {
783 *ppBlkMap = pBlkMap;
784 LogFlowFunc(("return success\n"));
785 return VINF_SUCCESS;
786 }
787 else
788 RTMemFree(pBlkMap);
789 }
790 else
791 rc = VERR_NO_MEMORY;
792 }
793 else
794 rc = VERR_VD_GEN_INVALID_HEADER;
795 }
796 else if (RT_SUCCESS(rc))
797 rc = VERR_VD_GEN_INVALID_HEADER;
798 }
799 else
800 rc = VERR_VD_GEN_INVALID_HEADER;
801
802 LogFlowFunc(("returns rc=%Rrc\n", rc));
803 return rc;
804}
805
806/**
807 * Saves the block map in the cache image. All necessary on disk structures
808 * are written.
809 *
810 * @returns VBox status code.
811 * @param pBlkMap The block bitmap to save.
812 * @param pStorage Where the block bitmap should be written to.
813 * @param offBlkMap Start of the block bitmap in blocks.
814 * @param cBlkMap Size of the block bitmap on the disk in blocks.
815 */
816static int vciBlkMapSave(PVCIBLKMAP pBlkMap, PVCICACHE pStorage, uint64_t offBlkMap, uint32_t cBlkMap)
817{
818 int rc = VINF_SUCCESS;
819 VciBlkMap BlkMap;
820
821 LogFlowFunc(("pBlkMap=%#p pStorage=%#p offBlkMap=%llu cBlkMap=%u\n",
822 pBlkMap, pStorage, offBlkMap, cBlkMap));
823
824 /* Make sure the number of blocks allocated for us match our expectations. */
825 if (VCI_BYTE2BLOCK(pBlkMap->cBlocks / 8) + VCI_BYTE2BLOCK(sizeof(VciBlkMap)) == cBlkMap)
826 {
827 /* Setup the header */
828 memset(&BlkMap, 0, sizeof(VciBlkMap));
829
830 BlkMap.u32Magic = RT_H2LE_U32(VCI_BLKMAP_MAGIC);
831 BlkMap.u32Version = RT_H2LE_U32(VCI_BLKMAP_VERSION);
832 BlkMap.cBlocks = RT_H2LE_U32(pBlkMap->cBlocks);
833 BlkMap.cBlocksFree = RT_H2LE_U32(pBlkMap->cBlocksFree);
834 BlkMap.cBlocksAllocMeta = RT_H2LE_U32(pBlkMap->cBlocksAllocMeta);
835 BlkMap.cBlocksAllocData = RT_H2LE_U32(pBlkMap->cBlocksAllocData);
836
837 rc = vciFileWriteSync(pStorage, offBlkMap, &BlkMap, VCI_BYTE2BLOCK(sizeof(VciBlkMap)));
838 if (RT_SUCCESS(rc))
839 {
840 uint8_t abBitmapBuffer[16*_1K];
841 unsigned iBit = 0;
842 PVCIBLKRANGEDESC pCur = pBlkMap->pRangesHead;
843
844 offBlkMap += VCI_BYTE2BLOCK(sizeof(VciBlkMap));
845
846 /* Write the descriptor ranges. */
847 while (pCur)
848 {
849 uint64_t cBlocks = pCur->cBlocks;
850
851 while (cBlocks)
852 {
853 uint64_t cBlocksMax = RT_MIN(cBlocks, sizeof(abBitmapBuffer) * 8 - iBit);
854
855 if (pCur->fFree)
856 ASMBitClearRange(abBitmapBuffer, iBit, iBit + cBlocksMax);
857 else
858 ASMBitSetRange(abBitmapBuffer, iBit, iBit + cBlocksMax);
859
860 iBit += cBlocksMax;
861 cBlocks -= cBlocksMax;
862
863 if (iBit == sizeof(abBitmapBuffer) * 8)
864 {
865 /* Buffer is full, write to file and reset. */
866 rc = vciFileWriteSync(pStorage, offBlkMap, abBitmapBuffer, VCI_BYTE2BLOCK(sizeof(abBitmapBuffer)));
867 if (RT_FAILURE(rc))
868 break;
869
870 offBlkMap += VCI_BYTE2BLOCK(sizeof(abBitmapBuffer));
871 iBit = 0;
872 }
873 }
874
875 pCur = pCur->pNext;
876 }
877
878 Assert(iBit % 8 == 0);
879
880 if (RT_SUCCESS(rc) && iBit)
881 rc = vciFileWriteSync(pStorage, offBlkMap, abBitmapBuffer, VCI_BYTE2BLOCK(iBit / 8));
882 }
883 }
884 else
885 rc = VERR_INTERNAL_ERROR; /* @todo Better error code. */
886
887 LogFlowFunc(("returns rc=%Rrc\n", rc));
888 return rc;
889}
890
891/**
892 * Finds the range block describing the given block address.
893 *
894 * @returns Pointer to the block range descriptor or NULL if none could be found.
895 * @param pBlkMap The block bitmap to search on.
896 * @param offBlockAddr The block address to search for.
897 */
898static PVCIBLKRANGEDESC vciBlkMapFindByBlock(PVCIBLKMAP pBlkMap, uint64_t offBlockAddr)
899{
900 PVCIBLKRANGEDESC pBlk = pBlkMap->pRangesHead;
901
902 while ( pBlk
903 && pBlk->offAddrStart < offBlockAddr)
904 pBlk = pBlk->pNext;
905
906 return pBlk;
907}
908
909/**
910 * Allocates the given number of blocks in the bitmap and returns the start block address.
911 *
912 * @returns VBox status code.
913 * @param pBlkMap The block bitmap to allocate the blocks from.
914 * @param cBlocks How many blocks to allocate.
915 * @param poffBlockAddr Where to store the start address of the allocated region.
916 */
917static int vciBlkMapAllocate(PVCIBLKMAP pBlkMap, uint32_t cBlocks, uint64_t *poffBlockAddr)
918{
919 PVCIBLKRANGEDESC pBestFit = NULL;
920 PVCIBLKRANGEDESC pCur = NULL;
921 int rc = VINF_SUCCESS;
922
923 LogFlowFunc(("pBlkMap=%#p cBlocks=%u poffBlockAddr=%#p\n",
924 pBlkMap, cBlocks, poffBlockAddr));
925
926 pCur = pBlkMap->pRangesHead;
927
928 while (pCur)
929 {
930 if ( pCur->fFree
931 && pCur->cBlocks >= cBlocks)
932 {
933 if ( !pBestFit
934 || pCur->cBlocks < pBestFit->cBlocks)
935 {
936 pBestFit = pCur;
937 /* Stop searching if the size is matching exactly. */
938 if (pBestFit->cBlocks == cBlocks)
939 break;
940 }
941 }
942 pCur = pCur->pNext;
943 }
944
945 Assert(!pBestFit || pBestFit->fFree);
946
947 if (pBestFit)
948 {
949 pBestFit->fFree = false;
950
951 if (pBestFit->cBlocks > cBlocks)
952 {
953 /* Create a new free block. */
954 PVCIBLKRANGEDESC pFree = (PVCIBLKRANGEDESC)RTMemAllocZ(sizeof(VCIBLKRANGEDESC));
955
956 if (pFree)
957 {
958 pFree->fFree = true;
959 pFree->cBlocks = pBestFit->cBlocks - cBlocks;
960 pBestFit->cBlocks -= pFree->cBlocks;
961 pFree->offAddrStart = pBestFit->offAddrStart + cBlocks;
962
963 /* Link into the list. */
964 pFree->pNext = pBestFit->pNext;
965 pBestFit->pNext = pFree;
966 pFree->pPrev = pBestFit;
967 if (!pFree->pNext)
968 pBlkMap->pRangesTail = pFree;
969
970 *poffBlockAddr = pBestFit->offAddrStart;
971 }
972 else
973 {
974 rc = VERR_NO_MEMORY;
975 pBestFit->fFree = true;
976 }
977 }
978 }
979 else
980 rc = VERR_VCI_NO_BLOCKS_FREE;
981
982 LogFlowFunc(("returns rc=%Rrc offBlockAddr=%llu\n", rc, *poffBlockAddr));
983 return rc;
984}
985
986/**
987 * Try to extend the space of an already allocated block.
988 *
989 * @returns VBox status code.
990 * @param pBlkMap The block bitmap to allocate the blocks from.
991 * @param cBlocksNew How many blocks the extended block should have.
992 * @param offBlockAddrOld The start address of the block to reallocate.
993 * @param poffBlockAddr Where to store the start address of the allocated region.
994 */
995static int vciBlkMapRealloc(PVCIBLKMAP pBlkMap, uint32_t cBlocksNew, uint64_t offBlockAddrOld,
996 uint64_t *poffBlockAddr)
997{
998 int rc = VINF_SUCCESS;
999
1000 LogFlowFunc(("pBlkMap=%#p cBlocksNew=%u offBlockAddrOld=%llu poffBlockAddr=%#p\n",
1001 pBlkMap, cBlocksNew, offBlockAddrOld, poffBlockAddr));
1002
1003 AssertMsgFailed(("Implement\n"));
1004
1005 LogFlowFunc(("returns rc=%Rrc offBlockAddr=%llu\n", rc, *poffBlockAddr));
1006 return rc;
1007}
1008
1009/**
1010 * Frees a range of blocks.
1011 *
1012 * @returns nothing.
1013 * @param pBlkMap The block bitmap.
1014 * @param offBlockAddr Address of the first block to free.
1015 * @param cBlocks How many blocks to free.
1016 */
1017static void vciBlkMapFree(PVCIBLKMAP pBlkMap, uint64_t offBlockAddr, uint32_t cBlocks)
1018{
1019 PVCIBLKRANGEDESC pBlk;
1020
1021 LogFlowFunc(("pBlkMap=%#p offBlockAddr=%llu cBlocks=%u\n",
1022 pBlkMap, offBlockAddr, cBlocks));
1023
1024 while (cBlocks)
1025 {
1026 pBlk = vciBlkMapFindByBlock(pBlkMap, offBlockAddr);
1027 AssertPtr(pBlk);
1028
1029 /* Easy case, the whole block is freed. */
1030 if ( pBlk->offAddrStart == offBlockAddr
1031 && pBlk->cBlocks <= cBlocks)
1032 {
1033 pBlk->fFree = true;
1034 cBlocks -= pBlk->cBlocks;
1035 offBlockAddr += pBlk->cBlocks;
1036
1037 /* Check if it is possible to merge free blocks. */
1038 if ( pBlk->pPrev
1039 && pBlk->pPrev->fFree)
1040 {
1041 PVCIBLKRANGEDESC pBlkPrev = pBlk->pPrev;
1042
1043 Assert(pBlkPrev->offAddrStart + pBlkPrev->cBlocks == pBlk->offAddrStart);
1044 pBlkPrev->cBlocks += pBlk->cBlocks;
1045 pBlkPrev->pNext = pBlk->pNext;
1046 if (pBlk->pNext)
1047 pBlk->pNext->pPrev = pBlkPrev;
1048 else
1049 pBlkMap->pRangesTail = pBlkPrev;
1050
1051 RTMemFree(pBlk);
1052 pBlk = pBlkPrev;
1053 }
1054
1055 /* Now the one to the right. */
1056 if ( pBlk->pNext
1057 && pBlk->pNext->fFree)
1058 {
1059 PVCIBLKRANGEDESC pBlkNext = pBlk->pNext;
1060
1061 Assert(pBlk->offAddrStart + pBlk->cBlocks == pBlkNext->offAddrStart);
1062 pBlk->cBlocks += pBlkNext->cBlocks;
1063 pBlk->pNext = pBlkNext->pNext;
1064 if (pBlkNext->pNext)
1065 pBlkNext->pNext->pPrev = pBlk;
1066 else
1067 pBlkMap->pRangesTail = pBlk;
1068
1069 RTMemFree(pBlkNext);
1070 }
1071 }
1072 else
1073 {
1074 /* The block is intersecting. */
1075 AssertMsgFailed(("TODO\n"));
1076 }
1077 }
1078
1079 LogFlowFunc(("returns\n"));
1080}
1081
1082/**
1083 * Converts a tree node from the image to the in memory structure.
1084 *
1085 * @returns Pointer to the in memory tree node.
1086 * @param offBlockAddrNode Block address of the node.
1087 * @param pNodeImage Pointer to the image representation of the node.
1088 */
1089static PVCITREENODE vciTreeNodeImage2Host(uint64_t offBlockAddrNode, PVciTreeNode pNodeImage)
1090{
1091 PVCITREENODE pNode = NULL;
1092
1093 if (pNodeImage->u8Type == VCI_TREE_NODE_TYPE_LEAF)
1094 {
1095 PVCITREENODELEAF pLeaf = (PVCITREENODELEAF)RTMemAllocZ(sizeof(VCITREENODELEAF));
1096
1097 if (pLeaf)
1098 {
1099 PVciCacheExtent pExtent = (PVciCacheExtent)&pNodeImage->au8Data[0];
1100
1101 pLeaf->Core.u8Type = VCI_TREE_NODE_TYPE_LEAF;
1102
1103 for (unsigned idx = 0; idx < RT_ELEMENTS(pLeaf->aExtents); idx++)
1104 {
1105 pLeaf->aExtents[idx].u64BlockOffset = RT_LE2H_U64(pExtent->u64BlockOffset);
1106 pLeaf->aExtents[idx].u32Blocks = RT_LE2H_U32(pExtent->u32Blocks);
1107 pLeaf->aExtents[idx].u64BlockAddr = RT_LE2H_U64(pExtent->u64BlockAddr);
1108 pExtent++;
1109
1110 if ( pLeaf->aExtents[idx].u32Blocks
1111 && pLeaf->aExtents[idx].u64BlockAddr)
1112 pLeaf->cUsedNodes++;
1113 }
1114
1115 pNode = &pLeaf->Core;
1116 }
1117 }
1118 else if (pNodeImage->u8Type == VCI_TREE_NODE_TYPE_INTERNAL)
1119 {
1120 PVCITREENODEINT pInt = (PVCITREENODEINT)RTMemAllocZ(sizeof(VCITREENODEINT));
1121
1122 if (pInt)
1123 {
1124 PVciTreeNodeInternal pIntImage = (PVciTreeNodeInternal)&pNodeImage->au8Data[0];
1125
1126 pInt->Core.u8Type = VCI_TREE_NODE_TYPE_INTERNAL;
1127
1128 for (unsigned idx = 0; idx < RT_ELEMENTS(pInt->aIntNodes); idx++)
1129 {
1130 pInt->aIntNodes[idx].u64BlockOffset = RT_LE2H_U64(pIntImage->u64BlockOffset);
1131 pInt->aIntNodes[idx].u32Blocks = RT_LE2H_U32(pIntImage->u32Blocks);
1132 pInt->aIntNodes[idx].PtrChild.fInMemory = false;
1133 pInt->aIntNodes[idx].PtrChild.u.offAddrBlockNode = RT_LE2H_U64(pIntImage->u64ChildAddr);
1134 pIntImage++;
1135
1136 if ( pInt->aIntNodes[idx].u32Blocks
1137 && pInt->aIntNodes[idx].PtrChild.u.offAddrBlockNode)
1138 pInt->cUsedNodes++;
1139 }
1140
1141 pNode = &pInt->Core;
1142 }
1143 }
1144 else
1145 AssertMsgFailed(("Invalid node type %d\n", pNodeImage->u8Type));
1146
1147 if (pNode)
1148 pNode->u64BlockAddr = offBlockAddrNode;
1149
1150 return pNode;
1151}
1152
1153/**
1154 * Looks up the cache extent for the given virtual block address.
1155 *
1156 * @returns Pointer to the cache extent or NULL if none could be found.
1157 * @param pCache The cache image instance.
1158 * @param offBlockOffset The block offset to search for.
1159 */
1160static PVCICACHEEXTENT vciCacheExtentLookup(PVCICACHE pCache, uint64_t offBlockOffset)
1161{
1162 int rc = VINF_SUCCESS;
1163 PVCICACHEEXTENT pExtent = NULL;
1164 PVCITREENODE pNodeCur = pCache->pRoot;
1165
1166 while ( RT_SUCCESS(rc)
1167 && pNodeCur
1168 && pNodeCur->u8Type != VCI_TREE_NODE_TYPE_LEAF)
1169 {
1170 PVCITREENODEINT pNodeInt = (PVCITREENODEINT)pNodeCur;
1171
1172 Assert(pNodeCur->u8Type == VCI_TREE_NODE_TYPE_INTERNAL);
1173
1174 /* Search for the correct internal node. */
1175 unsigned idxMin = 0;
1176 unsigned idxMax = pNodeInt->cUsedNodes;
1177 unsigned idxCur = pNodeInt->cUsedNodes / 2;
1178
1179 while (idxMin < idxMax)
1180 {
1181 PVCINODEINTERNAL pInt = &pNodeInt->aIntNodes[idxCur];
1182
1183 /* Determine the search direction. */
1184 if (offBlockOffset < pInt->u64BlockOffset)
1185 {
1186 /* Search left from the current extent. */
1187 idxMax = idxCur;
1188 }
1189 else if (offBlockOffset >= pInt->u64BlockOffset + pInt->u32Blocks)
1190 {
1191 /* Search right from the current extent. */
1192 idxMin = idxCur;
1193 }
1194 else
1195 {
1196 /* The block lies in the node, stop searching. */
1197 if (pInt->PtrChild.fInMemory)
1198 pNodeCur = pInt->PtrChild.u.pNode;
1199 else
1200 {
1201 PVCITREENODE pNodeNew;
1202 VciTreeNode NodeTree;
1203
1204 /* Read from disk and add to the tree. */
1205 rc = vciFileReadSync(pCache, VCI_BLOCK2BYTE(pInt->PtrChild.u.offAddrBlockNode),
1206 &NodeTree, sizeof(NodeTree));
1207 AssertRC(rc);
1208
1209 pNodeNew = vciTreeNodeImage2Host(pInt->PtrChild.u.offAddrBlockNode, &NodeTree);
1210 if (pNodeNew)
1211 {
1212 /* Link to the parent. */
1213 pInt->PtrChild.fInMemory = true;
1214 pInt->PtrChild.u.pNode = pNodeNew;
1215 pNodeNew->pParent = pNodeCur;
1216 pNodeCur = pNodeNew;
1217 }
1218 else
1219 rc = VERR_NO_MEMORY;
1220 }
1221 break;
1222 }
1223
1224 idxCur = idxMin + (idxMax - idxMin) / 2;
1225 }
1226 }
1227
1228 if ( RT_SUCCESS(rc)
1229 && pNodeCur)
1230 {
1231 PVCITREENODELEAF pLeaf = (PVCITREENODELEAF)pNodeCur;
1232 Assert(pNodeCur->u8Type == VCI_TREE_NODE_TYPE_LEAF);
1233
1234 /* Search the range. */
1235 unsigned idxMin = 0;
1236 unsigned idxMax = pLeaf->cUsedNodes;
1237 unsigned idxCur = pLeaf->cUsedNodes / 2;
1238
1239 while (idxMin < idxMax)
1240 {
1241 PVCICACHEEXTENT pExtentCur = &pLeaf->aExtents[idxCur];
1242
1243 /* Determine the search direction. */
1244 if (offBlockOffset < pExtentCur->u64BlockOffset)
1245 {
1246 /* Search left from the current extent. */
1247 idxMax = idxCur;
1248 }
1249 else if (offBlockOffset >= pExtentCur->u64BlockOffset + pExtentCur->u32Blocks)
1250 {
1251 /* Search right from the current extent. */
1252 idxMin = idxCur;
1253 }
1254 else
1255 {
1256 /* We found the extent, stop searching. */
1257 pExtent = pExtentCur;
1258 break;
1259 }
1260
1261 idxCur = idxMin + (idxMax - idxMin) / 2;
1262 }
1263 }
1264
1265 return pExtent;
1266}
1267
1268/**
1269 * Internal: Open an image, constructing all necessary data structures.
1270 */
1271static int vciOpenImage(PVCICACHE pCache, unsigned uOpenFlags)
1272{
1273 VciHdr Hdr;
1274 uint64_t cbFile;
1275 int rc;
1276
1277 pCache->uOpenFlags = uOpenFlags;
1278
1279 pCache->pInterfaceError = VDInterfaceGet(pCache->pVDIfsDisk, VDINTERFACETYPE_ERROR);
1280 if (pCache->pInterfaceError)
1281 pCache->pInterfaceErrorCallbacks = VDGetInterfaceError(pCache->pInterfaceError);
1282
1283 /* Get I/O interface. */
1284 pCache->pInterfaceIO = VDInterfaceGet(pCache->pVDIfsImage, VDINTERFACETYPE_IOINT);
1285 AssertPtrReturn(pCache->pInterfaceIO, VERR_INVALID_PARAMETER);
1286 pCache->pInterfaceIOCallbacks = VDGetInterfaceIOInt(pCache->pInterfaceIO);
1287 AssertPtrReturn(pCache->pInterfaceIOCallbacks, VERR_INVALID_PARAMETER);
1288
1289 /*
1290 * Open the image.
1291 */
1292 rc = vciFileOpen(pCache, pCache->pszFilename,
1293 VDOpenFlagsToFileOpenFlags(uOpenFlags,
1294 false /* fCreate */));
1295 if (RT_FAILURE(rc))
1296 {
1297 /* Do NOT signal an appropriate error here, as the VD layer has the
1298 * choice of retrying the open if it failed. */
1299 goto out;
1300 }
1301
1302 rc = vciFileGetSize(pCache, &cbFile);
1303 if (RT_FAILURE(rc) || cbFile < sizeof(VciHdr))
1304 {
1305 rc = VERR_VD_GEN_INVALID_HEADER;
1306 goto out;
1307 }
1308
1309 rc = vciFileReadSync(pCache, 0, &Hdr, VCI_BYTE2BLOCK(sizeof(Hdr)));
1310 if (RT_FAILURE(rc))
1311 {
1312 rc = VERR_VD_GEN_INVALID_HEADER;
1313 goto out;
1314 }
1315
1316 Hdr.u32Signature = RT_LE2H_U32(Hdr.u32Signature);
1317 Hdr.u32Version = RT_LE2H_U32(Hdr.u32Version);
1318 Hdr.cBlocksCache = RT_LE2H_U64(Hdr.cBlocksCache);
1319 Hdr.u32CacheType = RT_LE2H_U32(Hdr.u32CacheType);
1320 Hdr.offTreeRoot = RT_LE2H_U64(Hdr.offTreeRoot);
1321 Hdr.offBlkMap = RT_LE2H_U64(Hdr.offBlkMap);
1322 Hdr.cBlkMap = RT_LE2H_U64(Hdr.cBlkMap);
1323
1324 if ( Hdr.u32Signature == VCI_HDR_SIGNATURE
1325 && Hdr.u32Version == VCI_HDR_VERSION)
1326 {
1327 pCache->offTreeRoot = Hdr.offTreeRoot;
1328 pCache->offBlksBitmap = Hdr.offBlkMap;
1329
1330 /* Load the block map. */
1331 rc = vciBlkMapLoad(pCache, pCache->offBlksBitmap, Hdr.cBlkMap, &pCache->pBlkMap);
1332 if (RT_SUCCESS(rc))
1333 {
1334 /* Load the first tree node. */
1335 VciTreeNode RootNode;
1336
1337 rc = vciFileReadSync(pCache, pCache->offTreeRoot, &RootNode, VCI_BYTE2BLOCK(sizeof(VciTreeNode)));
1338 if (RT_SUCCESS(rc))
1339 {
1340 pCache->pRoot = vciTreeNodeImage2Host(pCache->offTreeRoot, &RootNode);
1341 if (!pCache->pRoot)
1342 rc = VERR_NO_MEMORY;
1343 }
1344 }
1345 }
1346 else
1347 rc = VERR_VD_GEN_INVALID_HEADER;
1348
1349out:
1350 if (RT_FAILURE(rc))
1351 vciFreeImage(pCache, false);
1352 return rc;
1353}
1354
1355/**
1356 * Internal: Create a vci image.
1357 */
1358static int vciCreateImage(PVCICACHE pCache, uint64_t cbSize,
1359 unsigned uImageFlags, const char *pszComment,
1360 unsigned uOpenFlags, PFNVDPROGRESS pfnProgress,
1361 void *pvUser, unsigned uPercentStart,
1362 unsigned uPercentSpan)
1363{
1364 VciHdr Hdr;
1365 VciTreeNode NodeRoot;
1366 int rc;
1367 uint64_t cBlocks = cbSize / VCI_BLOCK_SIZE; /* Size of the cache in blocks. */
1368
1369 if (uImageFlags & VD_IMAGE_FLAGS_DIFF)
1370 {
1371 rc = vciError(pCache, VERR_VD_RAW_INVALID_TYPE, RT_SRC_POS, N_("VCI: cannot create diff image '%s'"), pCache->pszFilename);
1372 return rc;
1373 }
1374
1375 pCache->uImageFlags = uImageFlags;
1376
1377 pCache->uOpenFlags = uOpenFlags & ~VD_OPEN_FLAGS_READONLY;
1378
1379 pCache->pInterfaceError = VDInterfaceGet(pCache->pVDIfsDisk, VDINTERFACETYPE_ERROR);
1380 if (pCache->pInterfaceError)
1381 pCache->pInterfaceErrorCallbacks = VDGetInterfaceError(pCache->pInterfaceError);
1382
1383 pCache->pInterfaceIO = VDInterfaceGet(pCache->pVDIfsImage, VDINTERFACETYPE_IOINT);
1384 AssertPtrReturn(pCache->pInterfaceIO, VERR_INVALID_PARAMETER);
1385 pCache->pInterfaceIOCallbacks = VDGetInterfaceIOInt(pCache->pInterfaceIO);
1386 AssertPtrReturn(pCache->pInterfaceIOCallbacks, VERR_INVALID_PARAMETER);
1387
1388 do
1389 {
1390 /* Create image file. */
1391 rc = vciFileOpen(pCache, pCache->pszFilename,
1392 VDOpenFlagsToFileOpenFlags(uOpenFlags & ~VD_OPEN_FLAGS_READONLY,
1393 true /* fCreate */));
1394 if (RT_FAILURE(rc))
1395 {
1396 rc = vciError(pCache, rc, RT_SRC_POS, N_("VCI: cannot create image '%s'"), pCache->pszFilename);
1397 break;
1398 }
1399
1400 /* Allocate block bitmap. */
1401 uint32_t cBlkMap = 0;
1402 rc = vciBlkMapCreate(cBlocks, &pCache->pBlkMap, &cBlkMap);
1403 if (RT_FAILURE(rc))
1404 {
1405 rc = vciError(pCache, rc, RT_SRC_POS, N_("VCI: cannot create block bitmap '%s'"), pCache->pszFilename);
1406 break;
1407 }
1408
1409 /*
1410 * Allocate space for the header in the block bitmap.
1411 * Because the block map is empty the header has to start at block 0
1412 */
1413 uint64_t offHdr = 0;
1414 rc = vciBlkMapAllocate(pCache->pBlkMap, VCI_BYTE2BLOCK(sizeof(VciHdr)), &offHdr);
1415 if (RT_FAILURE(rc))
1416 {
1417 rc = vciError(pCache, rc, RT_SRC_POS, N_("VCI: cannot allocate space for header in block bitmap '%s'"), pCache->pszFilename);
1418 break;
1419 }
1420
1421 Assert(offHdr == 0);
1422
1423 /*
1424 * Allocate space for the block map itself.
1425 */
1426 uint64_t offBlkMap = 0;
1427 rc = vciBlkMapAllocate(pCache->pBlkMap, cBlkMap, &offBlkMap);
1428 if (RT_FAILURE(rc))
1429 {
1430 rc = vciError(pCache, rc, RT_SRC_POS, N_("VCI: cannot allocate space for block map in block map '%s'"), pCache->pszFilename);
1431 break;
1432 }
1433
1434 /*
1435 * Allocate space for the tree root node.
1436 */
1437 uint64_t offTreeRoot = 0;
1438 rc = vciBlkMapAllocate(pCache->pBlkMap, VCI_BYTE2BLOCK(sizeof(VciTreeNode)), &offTreeRoot);
1439 if (RT_FAILURE(rc))
1440 {
1441 rc = vciError(pCache, rc, RT_SRC_POS, N_("VCI: cannot allocate space for block map in block map '%s'"), pCache->pszFilename);
1442 break;
1443 }
1444
1445 /*
1446 * Allocate the in memory root node.
1447 */
1448 pCache->pRoot = (PVCITREENODE)RTMemAllocZ(sizeof(VCITREENODELEAF));
1449 if (!pCache->pRoot)
1450 {
1451 rc = vciError(pCache, rc, RT_SRC_POS, N_("VCI: cannot allocate B+-Tree root pointer '%s'"), pCache->pszFilename);
1452 break;
1453 }
1454
1455 pCache->pRoot->u8Type = VCI_TREE_NODE_TYPE_LEAF;
1456 /* Rest remains 0 as the tree is still empty. */
1457
1458 /*
1459 * Now that we are here we have all the basic structures and know where to place them in the image.
1460 * It's time to write it now.
1461 */
1462
1463 /* Setup the header. */
1464 memset(&Hdr, 0, sizeof(VciHdr));
1465 Hdr.u32Signature = RT_H2LE_U32(VCI_HDR_SIGNATURE);
1466 Hdr.u32Version = RT_H2LE_U32(VCI_HDR_VERSION);
1467 Hdr.cBlocksCache = RT_H2LE_U64(cBlocks);
1468 Hdr.fUncleanShutdown = VCI_HDR_UNCLEAN_SHUTDOWN;
1469 Hdr.u32CacheType = uImageFlags & VD_IMAGE_FLAGS_FIXED
1470 ? RT_H2LE_U32(VCI_HDR_CACHE_TYPE_FIXED)
1471 : RT_H2LE_U32(VCI_HDR_CACHE_TYPE_DYNAMIC);
1472 Hdr.offTreeRoot = RT_H2LE_U64(offTreeRoot);
1473 Hdr.offBlkMap = RT_H2LE_U64(offBlkMap);
1474 Hdr.cBlkMap = RT_H2LE_U64(cBlkMap);
1475
1476 rc = vciFileWriteSync(pCache, offHdr, &Hdr, VCI_BYTE2BLOCK(sizeof(VciHdr)));
1477 if (RT_FAILURE(rc))
1478 {
1479 rc = vciError(pCache, rc, RT_SRC_POS, N_("VCI: cannot write header '%s'"), pCache->pszFilename);
1480 break;
1481 }
1482
1483 rc = vciBlkMapSave(pCache->pBlkMap, pCache, offBlkMap, cBlkMap);
1484 if (RT_FAILURE(rc))
1485 {
1486 rc = vciError(pCache, rc, RT_SRC_POS, N_("VCI: cannot write block map '%s'"), pCache->pszFilename);
1487 break;
1488 }
1489
1490 /* Setup the root tree. */
1491 memset(&NodeRoot, 0, sizeof(VciTreeNode));
1492 NodeRoot.u8Type = RT_H2LE_U32(VCI_TREE_NODE_TYPE_LEAF);
1493
1494 rc = vciFileWriteSync(pCache, offTreeRoot, &NodeRoot, VCI_BYTE2BLOCK(sizeof(VciTreeNode)));
1495 if (RT_FAILURE(rc))
1496 {
1497 rc = vciError(pCache, rc, RT_SRC_POS, N_("VCI: cannot write root node '%s'"), pCache->pszFilename);
1498 break;
1499 }
1500
1501 rc = vciFlushImage(pCache);
1502 if (RT_FAILURE(rc))
1503 {
1504 rc = vciError(pCache, rc, RT_SRC_POS, N_("VCI: cannot flush '%s'"), pCache->pszFilename);
1505 break;
1506 }
1507
1508 pCache->cbSize = cbSize;
1509
1510 } while (0);
1511
1512 if (RT_SUCCESS(rc) && pfnProgress)
1513 pfnProgress(pvUser, uPercentStart + uPercentSpan);
1514
1515 if (RT_FAILURE(rc))
1516 vciFreeImage(pCache, rc != VERR_ALREADY_EXISTS);
1517 return rc;
1518}
1519
1520/** @copydoc VDCACHEBACKEND::pfnProbe */
1521static int vciProbe(const char *pszFilename, PVDINTERFACE pVDIfsCache,
1522 PVDINTERFACE pVDIfsImage)
1523{
1524 VciHdr Hdr;
1525 PVDIOSTORAGE pStorage;
1526 uint64_t cbFile;
1527 int rc = VINF_SUCCESS;
1528
1529 LogFlowFunc(("pszFilename=\"%s\"\n", pszFilename));
1530
1531 /* Get I/O interface. */
1532 PVDINTERFACE pInterfaceIO = VDInterfaceGet(pVDIfsImage, VDINTERFACETYPE_IOINT);
1533 AssertPtrReturn(pInterfaceIO, VERR_INVALID_PARAMETER);
1534 PVDINTERFACEIOINT pInterfaceIOCallbacks = VDGetInterfaceIOInt(pInterfaceIO);
1535 AssertPtrReturn(pInterfaceIOCallbacks, VERR_INVALID_PARAMETER);
1536
1537 rc = pInterfaceIOCallbacks->pfnOpen(pInterfaceIO->pvUser, pszFilename,
1538 VDOpenFlagsToFileOpenFlags(VD_OPEN_FLAGS_READONLY,
1539 false /* fCreate */),
1540 &pStorage);
1541 if (RT_FAILURE(rc))
1542 goto out;
1543
1544 rc = pInterfaceIOCallbacks->pfnGetSize(pInterfaceIO->pvUser, pStorage, &cbFile);
1545 if (RT_FAILURE(rc) || cbFile < sizeof(VciHdr))
1546 {
1547 pInterfaceIOCallbacks->pfnClose(pInterfaceIO->pvUser, pStorage);
1548 rc = VERR_VD_GEN_INVALID_HEADER;
1549 goto out;
1550 }
1551
1552 rc = pInterfaceIOCallbacks->pfnReadSync(pInterfaceIO->pvUser, pStorage, 0, &Hdr, sizeof(Hdr), NULL);
1553 if (RT_FAILURE(rc))
1554 {
1555 pInterfaceIOCallbacks->pfnClose(pInterfaceIO->pvUser, pStorage);
1556 rc = VERR_VD_GEN_INVALID_HEADER;
1557 goto out;
1558 }
1559
1560 Hdr.u32Signature = RT_LE2H_U32(Hdr.u32Signature);
1561 Hdr.u32Version = RT_LE2H_U32(Hdr.u32Version);
1562 Hdr.cBlocksCache = RT_LE2H_U64(Hdr.cBlocksCache);
1563 Hdr.u32CacheType = RT_LE2H_U32(Hdr.u32CacheType);
1564 Hdr.offTreeRoot = RT_LE2H_U64(Hdr.offTreeRoot);
1565 Hdr.offBlkMap = RT_LE2H_U64(Hdr.offBlkMap);
1566 Hdr.cBlkMap = RT_LE2H_U64(Hdr.cBlkMap);
1567
1568 if ( Hdr.u32Signature == VCI_HDR_SIGNATURE
1569 && Hdr.u32Version == VCI_HDR_VERSION)
1570 rc = VINF_SUCCESS;
1571 else
1572 rc = VERR_VD_GEN_INVALID_HEADER;
1573
1574 pInterfaceIOCallbacks->pfnClose(pInterfaceIO->pvUser, pStorage);
1575
1576out:
1577 LogFlowFunc(("returns %Rrc\n", rc));
1578 return rc;
1579}
1580
1581/** @copydoc VDCACHEBACKEND::pfnOpen */
1582static int vciOpen(const char *pszFilename, unsigned uOpenFlags,
1583 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
1584 void **ppBackendData)
1585{
1586 LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x pVDIfsDisk=%#p pVDIfsImage=%#p ppBackendData=%#p\n", pszFilename, uOpenFlags, pVDIfsDisk, pVDIfsImage, ppBackendData));
1587 int rc;
1588 PVCICACHE pCache;
1589
1590 /* Check open flags. All valid flags are supported. */
1591 if (uOpenFlags & ~VD_OPEN_FLAGS_MASK)
1592 {
1593 rc = VERR_INVALID_PARAMETER;
1594 goto out;
1595 }
1596
1597 /* Check remaining arguments. */
1598 if ( !VALID_PTR(pszFilename)
1599 || !*pszFilename)
1600 {
1601 rc = VERR_INVALID_PARAMETER;
1602 goto out;
1603 }
1604
1605
1606 pCache = (PVCICACHE)RTMemAllocZ(sizeof(VCICACHE));
1607 if (!pCache)
1608 {
1609 rc = VERR_NO_MEMORY;
1610 goto out;
1611 }
1612 pCache->pszFilename = pszFilename;
1613 pCache->pStorage = NULL;
1614 pCache->pVDIfsDisk = pVDIfsDisk;
1615 pCache->pVDIfsImage = pVDIfsImage;
1616
1617 rc = vciOpenImage(pCache, uOpenFlags);
1618 if (RT_SUCCESS(rc))
1619 *ppBackendData = pCache;
1620 else
1621 RTMemFree(pCache);
1622
1623out:
1624 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
1625 return rc;
1626}
1627
1628/** @copydoc VDCACHEBACKEND::pfnCreate */
1629static int vciCreate(const char *pszFilename, uint64_t cbSize,
1630 unsigned uImageFlags, const char *pszComment,
1631 PCRTUUID pUuid, unsigned uOpenFlags,
1632 unsigned uPercentStart, unsigned uPercentSpan,
1633 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
1634 PVDINTERFACE pVDIfsOperation, void **ppBackendData)
1635{
1636 LogFlowFunc(("pszFilename=\"%s\" cbSize=%llu uImageFlags=%#x pszComment=\"%s\" Uuid=%RTuuid uOpenFlags=%#x uPercentStart=%u uPercentSpan=%u pVDIfsDisk=%#p pVDIfsImage=%#p pVDIfsOperation=%#p ppBackendData=%#p",
1637 pszFilename, cbSize, uImageFlags, pszComment, pUuid, uOpenFlags, uPercentStart, uPercentSpan, pVDIfsDisk, pVDIfsImage, pVDIfsOperation, ppBackendData));
1638 int rc;
1639 PVCICACHE pCache;
1640
1641 PFNVDPROGRESS pfnProgress = NULL;
1642 void *pvUser = NULL;
1643 PVDINTERFACE pIfProgress = VDInterfaceGet(pVDIfsOperation,
1644 VDINTERFACETYPE_PROGRESS);
1645 PVDINTERFACEPROGRESS pCbProgress = NULL;
1646 if (pIfProgress)
1647 {
1648 pCbProgress = VDGetInterfaceProgress(pIfProgress);
1649 if (pCbProgress)
1650 pfnProgress = pCbProgress->pfnProgress;
1651 pvUser = pIfProgress->pvUser;
1652 }
1653
1654 /* Check open flags. All valid flags are supported. */
1655 if (uOpenFlags & ~VD_OPEN_FLAGS_MASK)
1656 {
1657 rc = VERR_INVALID_PARAMETER;
1658 goto out;
1659 }
1660
1661 /* Check remaining arguments. */
1662 if ( !VALID_PTR(pszFilename)
1663 || !*pszFilename)
1664 {
1665 rc = VERR_INVALID_PARAMETER;
1666 goto out;
1667 }
1668
1669 pCache = (PVCICACHE)RTMemAllocZ(sizeof(VCICACHE));
1670 if (!pCache)
1671 {
1672 rc = VERR_NO_MEMORY;
1673 goto out;
1674 }
1675 pCache->pszFilename = pszFilename;
1676 pCache->pStorage = NULL;
1677 pCache->pVDIfsDisk = pVDIfsDisk;
1678 pCache->pVDIfsImage = pVDIfsImage;
1679
1680 rc = vciCreateImage(pCache, cbSize, uImageFlags, pszComment, uOpenFlags,
1681 pfnProgress, pvUser, uPercentStart, uPercentSpan);
1682 if (RT_SUCCESS(rc))
1683 {
1684 /* So far the image is opened in read/write mode. Make sure the
1685 * image is opened in read-only mode if the caller requested that. */
1686 if (uOpenFlags & VD_OPEN_FLAGS_READONLY)
1687 {
1688 vciFreeImage(pCache, false);
1689 rc = vciOpenImage(pCache, uOpenFlags);
1690 if (RT_FAILURE(rc))
1691 {
1692 RTMemFree(pCache);
1693 goto out;
1694 }
1695 }
1696 *ppBackendData = pCache;
1697 }
1698 else
1699 RTMemFree(pCache);
1700
1701out:
1702 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
1703 return rc;
1704}
1705
1706/** @copydoc VDCACHEBACKEND::pfnClose */
1707static int vciClose(void *pBackendData, bool fDelete)
1708{
1709 LogFlowFunc(("pBackendData=%#p fDelete=%d\n", pBackendData, fDelete));
1710 PVCICACHE pCache = (PVCICACHE)pBackendData;
1711 int rc;
1712
1713 rc = vciFreeImage(pCache, fDelete);
1714 RTMemFree(pCache);
1715
1716 LogFlowFunc(("returns %Rrc\n", rc));
1717 return rc;
1718}
1719
1720/** @copydoc VDCACHEBACKEND::pfnRead */
1721static int vciRead(void *pBackendData, uint64_t uOffset, void *pvBuf,
1722 size_t cbToRead, size_t *pcbActuallyRead)
1723{
1724 LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToRead=%zu pcbActuallyRead=%#p\n", pBackendData, uOffset, pvBuf, cbToRead, pcbActuallyRead));
1725 PVCICACHE pCache = (PVCICACHE)pBackendData;
1726 int rc = VINF_SUCCESS;
1727 PVCICACHEEXTENT pExtent;
1728
1729 AssertPtr(pCache);
1730 Assert(uOffset % 512 == 0);
1731 Assert(cbToRead % 512 == 0);
1732
1733
1734 pExtent = vciCacheExtentLookup(pCache, VCI_BYTE2BLOCK(uOffset));
1735 if (pExtent)
1736 {
1737 uint64_t offRead = uOffset - VCI_BLOCK2BYTE(pExtent->u64BlockOffset);
1738 cbToRead = RT_MIN(cbToRead, VCI_BLOCK2BYTE(pExtent->u32Blocks) - offRead);
1739
1740 rc = vciFileReadSync(pCache, VCI_BLOCK2BYTE(pExtent->u64BlockAddr) + offRead,
1741 pvBuf, cbToRead);
1742 }
1743 else
1744 {
1745 /** @todo Best fit to check whether we have cached data later and set
1746 * pcbActuallyRead accordingly. */
1747 rc = VERR_VD_BLOCK_FREE;
1748 }
1749
1750 if (pcbActuallyRead)
1751 *pcbActuallyRead = cbToRead;
1752
1753out:
1754 LogFlowFunc(("returns %Rrc\n", rc));
1755 return rc;
1756}
1757
1758/** @copydoc VDCACHEBACKEND::pfnWrite */
1759static int vciWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf,
1760 size_t cbToWrite, size_t *pcbWriteProcess)
1761{
1762 LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToWrite=%zu pcbWriteProcess=%#p\n",
1763 pBackendData, uOffset, pvBuf, cbToWrite, pcbWriteProcess));
1764 PVCICACHE pCache = (PVCICACHE)pBackendData;
1765 int rc = VINF_SUCCESS;
1766
1767 AssertPtr(pCache);
1768 Assert(uOffset % 512 == 0);
1769 Assert(cbToWrite % 512 == 0);
1770
1771 *pcbWriteProcess = cbToWrite; /** @todo: Implement. */
1772out:
1773 LogFlowFunc(("returns %Rrc\n", rc));
1774 return rc;
1775}
1776
1777/** @copydoc VDCACHEBACKEND::pfnFlush */
1778static int vciFlush(void *pBackendData)
1779{
1780 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
1781 PVCICACHE pCache = (PVCICACHE)pBackendData;
1782 int rc = VINF_SUCCESS;
1783
1784 rc = vciFlushImage(pCache);
1785 LogFlowFunc(("returns %Rrc\n", rc));
1786 return rc;
1787}
1788
1789/** @copydoc VDCACHEBACKEND::pfnGetVersion */
1790static unsigned vciGetVersion(void *pBackendData)
1791{
1792 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
1793 PVCICACHE pCache = (PVCICACHE)pBackendData;
1794
1795 AssertPtr(pCache);
1796
1797 if (pCache)
1798 return 1;
1799 else
1800 return 0;
1801}
1802
1803/** @copydoc VDCACHEBACKEND::pfnGetSize */
1804static uint64_t vciGetSize(void *pBackendData)
1805{
1806 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
1807 PVCICACHE pCache = (PVCICACHE)pBackendData;
1808 uint64_t cb = 0;
1809
1810 AssertPtr(pCache);
1811
1812 if (pCache && pCache->pStorage)
1813 cb = pCache->cbSize;
1814
1815 LogFlowFunc(("returns %llu\n", cb));
1816 return cb;
1817}
1818
1819/** @copydoc VDCACHEBACKEND::pfnGetFileSize */
1820static uint64_t vciGetFileSize(void *pBackendData)
1821{
1822 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
1823 PVCICACHE pCache = (PVCICACHE)pBackendData;
1824 uint64_t cb = 0;
1825
1826 AssertPtr(pCache);
1827
1828 if (pCache)
1829 {
1830 uint64_t cbFile;
1831 if (pCache->pStorage)
1832 {
1833 int rc = vciFileGetSize(pCache, &cbFile);
1834 if (RT_SUCCESS(rc))
1835 cb = cbFile;
1836 }
1837 }
1838
1839 LogFlowFunc(("returns %lld\n", cb));
1840 return cb;
1841}
1842
1843/** @copydoc VDCACHEBACKEND::pfnGetImageFlags */
1844static unsigned vciGetImageFlags(void *pBackendData)
1845{
1846 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
1847 PVCICACHE pCache = (PVCICACHE)pBackendData;
1848 unsigned uImageFlags;
1849
1850 AssertPtr(pCache);
1851
1852 if (pCache)
1853 uImageFlags = pCache->uImageFlags;
1854 else
1855 uImageFlags = 0;
1856
1857 LogFlowFunc(("returns %#x\n", uImageFlags));
1858 return uImageFlags;
1859}
1860
1861/** @copydoc VDCACHEBACKEND::pfnGetOpenFlags */
1862static unsigned vciGetOpenFlags(void *pBackendData)
1863{
1864 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
1865 PVCICACHE pCache = (PVCICACHE)pBackendData;
1866 unsigned uOpenFlags;
1867
1868 AssertPtr(pCache);
1869
1870 if (pCache)
1871 uOpenFlags = pCache->uOpenFlags;
1872 else
1873 uOpenFlags = 0;
1874
1875 LogFlowFunc(("returns %#x\n", uOpenFlags));
1876 return uOpenFlags;
1877}
1878
1879/** @copydoc VDCACHEBACKEND::pfnSetOpenFlags */
1880static int vciSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
1881{
1882 LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
1883 PVCICACHE pCache = (PVCICACHE)pBackendData;
1884 int rc;
1885
1886 /* Image must be opened and the new flags must be valid. Just readonly and
1887 * info flags are supported. */
1888 if (!pCache || (uOpenFlags & ~(VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO)))
1889 {
1890 rc = VERR_INVALID_PARAMETER;
1891 goto out;
1892 }
1893
1894 /* Implement this operation via reopening the image. */
1895 rc = vciFreeImage(pCache, false);
1896 if (RT_FAILURE(rc))
1897 goto out;
1898 rc = vciOpenImage(pCache, uOpenFlags);
1899
1900out:
1901 LogFlowFunc(("returns %Rrc\n", rc));
1902 return rc;
1903}
1904
1905/** @copydoc VDCACHEBACKEND::pfnGetComment */
1906static int vciGetComment(void *pBackendData, char *pszComment,
1907 size_t cbComment)
1908{
1909 LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
1910 PVCICACHE pCache = (PVCICACHE)pBackendData;
1911 int rc;
1912
1913 AssertPtr(pCache);
1914
1915 if (pCache)
1916 rc = VERR_NOT_SUPPORTED;
1917 else
1918 rc = VERR_VD_NOT_OPENED;
1919
1920 LogFlowFunc(("returns %Rrc comment='%s'\n", rc, pszComment));
1921 return rc;
1922}
1923
1924/** @copydoc VDCACHEBACKEND::pfnSetComment */
1925static int vciSetComment(void *pBackendData, const char *pszComment)
1926{
1927 LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
1928 PVCICACHE pCache = (PVCICACHE)pBackendData;
1929 int rc;
1930
1931 AssertPtr(pCache);
1932
1933 if (pCache)
1934 {
1935 if (pCache->uOpenFlags & VD_OPEN_FLAGS_READONLY)
1936 rc = VERR_VD_IMAGE_READ_ONLY;
1937 else
1938 rc = VERR_NOT_SUPPORTED;
1939 }
1940 else
1941 rc = VERR_VD_NOT_OPENED;
1942
1943out:
1944 LogFlowFunc(("returns %Rrc\n", rc));
1945 return rc;
1946}
1947
1948/** @copydoc VDCACHEBACKEND::pfnGetUuid */
1949static int vciGetUuid(void *pBackendData, PRTUUID pUuid)
1950{
1951 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1952 PVCICACHE pCache = (PVCICACHE)pBackendData;
1953 int rc;
1954
1955 AssertPtr(pCache);
1956
1957 if (pCache)
1958 rc = VERR_NOT_SUPPORTED;
1959 else
1960 rc = VERR_VD_NOT_OPENED;
1961
1962 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1963 return rc;
1964}
1965
1966/** @copydoc VDCACHEBACKEND::pfnSetUuid */
1967static int vciSetUuid(void *pBackendData, PCRTUUID pUuid)
1968{
1969 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1970 PVCICACHE pCache = (PVCICACHE)pBackendData;
1971 int rc;
1972
1973 LogFlowFunc(("%RTuuid\n", pUuid));
1974 AssertPtr(pCache);
1975
1976 if (pCache)
1977 {
1978 if (!(pCache->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1979 rc = VERR_NOT_SUPPORTED;
1980 else
1981 rc = VERR_VD_IMAGE_READ_ONLY;
1982 }
1983 else
1984 rc = VERR_VD_NOT_OPENED;
1985
1986 LogFlowFunc(("returns %Rrc\n", rc));
1987 return rc;
1988}
1989
1990/** @copydoc VDCACHEBACKEND::pfnGetModificationUuid */
1991static int vciGetModificationUuid(void *pBackendData, PRTUUID pUuid)
1992{
1993 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1994 PVCICACHE pCache = (PVCICACHE)pBackendData;
1995 int rc;
1996
1997 AssertPtr(pCache);
1998
1999 if (pCache)
2000 rc = VERR_NOT_SUPPORTED;
2001 else
2002 rc = VERR_VD_NOT_OPENED;
2003
2004 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
2005 return rc;
2006}
2007
2008/** @copydoc VDCACHEBACKEND::pfnSetModificationUuid */
2009static int vciSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
2010{
2011 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
2012 PVCICACHE pCache = (PVCICACHE)pBackendData;
2013 int rc;
2014
2015 AssertPtr(pCache);
2016
2017 if (pCache)
2018 {
2019 if (!(pCache->uOpenFlags & VD_OPEN_FLAGS_READONLY))
2020 rc = VERR_NOT_SUPPORTED;
2021 else
2022 rc = VERR_VD_IMAGE_READ_ONLY;
2023 }
2024 else
2025 rc = VERR_VD_NOT_OPENED;
2026
2027 LogFlowFunc(("returns %Rrc\n", rc));
2028 return rc;
2029}
2030
2031/** @copydoc VDCACHEBACKEND::pfnDump */
2032static void vciDump(void *pBackendData)
2033{
2034 NOREF(pBackendData);
2035}
2036
2037/** @copydoc VDCACHEBACKEND::pfnAsyncRead */
2038static int vciAsyncRead(void *pBackendData, uint64_t uOffset, size_t cbRead,
2039 PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
2040{
2041 int rc = VERR_NOT_SUPPORTED;
2042 PVCICACHE pCache = (PVCICACHE)pBackendData;
2043
2044 return rc;
2045}
2046
2047/** @copydoc VDCACHEBACKEND::pfnAsyncWrite */
2048static int vciAsyncWrite(void *pBackendData, uint64_t uOffset, size_t cbWrite,
2049 PVDIOCTX pIoCtx, size_t *pcbWriteProcess)
2050{
2051 int rc = VERR_NOT_SUPPORTED;
2052 PVCICACHE pCache = (PVCICACHE)pBackendData;
2053
2054 return rc;
2055}
2056
2057/** @copydoc VDCACHEBACKEND::pfnAsyncFlush */
2058static int vciAsyncFlush(void *pBackendData, PVDIOCTX pIoCtx)
2059{
2060 int rc = VERR_NOT_SUPPORTED;
2061 PVCICACHE pCache = (PVCICACHE)pBackendData;
2062
2063 return rc;
2064}
2065
2066
2067VDCACHEBACKEND g_VciCacheBackend =
2068{
2069 /* pszBackendName */
2070 "vci",
2071 /* cbSize */
2072 sizeof(VDCACHEBACKEND),
2073 /* uBackendCaps */
2074 VD_CAP_CREATE_FIXED | VD_CAP_CREATE_DYNAMIC | VD_CAP_FILE | VD_CAP_VFS,
2075 /* papszFileExtensions */
2076 s_apszVciFileExtensions,
2077 /* paConfigInfo */
2078 NULL,
2079 /* hPlugin */
2080 NIL_RTLDRMOD,
2081 /* pfnProbe */
2082 vciProbe,
2083 /* pfnOpen */
2084 vciOpen,
2085 /* pfnCreate */
2086 vciCreate,
2087 /* pfnClose */
2088 vciClose,
2089 /* pfnRead */
2090 vciRead,
2091 /* pfnWrite */
2092 vciWrite,
2093 /* pfnFlush */
2094 vciFlush,
2095 /* pfnGetVersion */
2096 vciGetVersion,
2097 /* pfnGetSize */
2098 vciGetSize,
2099 /* pfnGetFileSize */
2100 vciGetFileSize,
2101 /* pfnGetImageFlags */
2102 vciGetImageFlags,
2103 /* pfnGetOpenFlags */
2104 vciGetOpenFlags,
2105 /* pfnSetOpenFlags */
2106 vciSetOpenFlags,
2107 /* pfnGetComment */
2108 vciGetComment,
2109 /* pfnSetComment */
2110 vciSetComment,
2111 /* pfnGetUuid */
2112 vciGetUuid,
2113 /* pfnSetUuid */
2114 vciSetUuid,
2115 /* pfnGetModificationUuid */
2116 vciGetModificationUuid,
2117 /* pfnSetModificationUuid */
2118 vciSetModificationUuid,
2119 /* pfnDump */
2120 vciDump,
2121 /* pfnAsyncRead */
2122 vciAsyncRead,
2123 /* pfnAsyncWrite */
2124 vciAsyncWrite,
2125 /* pfnAsyncFlush */
2126 vciAsyncFlush,
2127 /* pfnComposeLocation */
2128 NULL,
2129 /* pfnComposeName */
2130 NULL
2131};
2132
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