[77232] | 1 | /* $Id: tstVDSnap.cpp 103522 2024-02-22 11:15:20Z vboxsync $ */
|
---|
[27135] | 2 | /** @file
|
---|
| 3 | * Snapshot VBox HDD container test utility.
|
---|
| 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[98103] | 7 | * Copyright (C) 2010-2023 Oracle and/or its affiliates.
|
---|
[27135] | 8 | *
|
---|
[96407] | 9 | * This file is part of VirtualBox base platform packages, as
|
---|
| 10 | * available from https://www.virtualbox.org.
|
---|
| 11 | *
|
---|
| 12 | * This program is free software; you can redistribute it and/or
|
---|
| 13 | * modify it under the terms of the GNU General Public License
|
---|
| 14 | * as published by the Free Software Foundation, in version 3 of the
|
---|
| 15 | * License.
|
---|
| 16 | *
|
---|
| 17 | * This program is distributed in the hope that it will be useful, but
|
---|
| 18 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
| 20 | * General Public License for more details.
|
---|
| 21 | *
|
---|
| 22 | * You should have received a copy of the GNU General Public License
|
---|
| 23 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
| 24 | *
|
---|
| 25 | * SPDX-License-Identifier: GPL-3.0-only
|
---|
[27135] | 26 | */
|
---|
| 27 |
|
---|
[33567] | 28 | #include <VBox/vd.h>
|
---|
[76474] | 29 | #include <iprt/errcore.h>
|
---|
[27135] | 30 | #include <VBox/log.h>
|
---|
| 31 | #include <iprt/asm.h>
|
---|
| 32 | #include <iprt/dir.h>
|
---|
| 33 | #include <iprt/string.h>
|
---|
| 34 | #include <iprt/stream.h>
|
---|
| 35 | #include <iprt/file.h>
|
---|
| 36 | #include <iprt/mem.h>
|
---|
| 37 | #include <iprt/initterm.h>
|
---|
| 38 | #include <iprt/rand.h>
|
---|
| 39 |
|
---|
| 40 | /**
|
---|
| 41 | * A VD snapshot test.
|
---|
| 42 | */
|
---|
| 43 | typedef struct VDSNAPTEST
|
---|
| 44 | {
|
---|
| 45 | /** Backend to use */
|
---|
| 46 | const char *pcszBackend;
|
---|
| 47 | /** Base image name */
|
---|
| 48 | const char *pcszBaseImage;
|
---|
| 49 | /** Diff image ending */
|
---|
| 50 | const char *pcszDiffSuff;
|
---|
| 51 | /** Number of iterations before the test exits */
|
---|
| 52 | uint32_t cIterations;
|
---|
| 53 | /** Test pattern size */
|
---|
| 54 | size_t cbTestPattern;
|
---|
| 55 | /** Minimum number of disk segments */
|
---|
| 56 | uint32_t cDiskSegsMin;
|
---|
| 57 | /** Miaximum number of disk segments */
|
---|
| 58 | uint32_t cDiskSegsMax;
|
---|
| 59 | /** Minimum number of diffs needed before a merge
|
---|
| 60 | * operation can occur */
|
---|
| 61 | unsigned cDiffsMinBeforeMerge;
|
---|
| 62 | /** Chance to get create instead of a merge operation */
|
---|
| 63 | uint32_t uCreateDiffChance;
|
---|
| 64 | /** Chance to change a segment after a diff was created */
|
---|
| 65 | uint32_t uChangeSegChance;
|
---|
[27137] | 66 | /** Numer of allocated blocks in the base image in percent */
|
---|
| 67 | uint32_t uAllocatedBlocks;
|
---|
[27655] | 68 | /** Merge direction */
|
---|
| 69 | bool fForward;
|
---|
[27135] | 70 | } VDSNAPTEST, *PVDSNAPTEST;
|
---|
| 71 |
|
---|
| 72 | /**
|
---|
| 73 | * Structure defining a disk segment.
|
---|
| 74 | */
|
---|
| 75 | typedef struct VDDISKSEG
|
---|
| 76 | {
|
---|
| 77 | /** Start offset in the disk. */
|
---|
| 78 | uint64_t off;
|
---|
| 79 | /** Size of the segment. */
|
---|
| 80 | uint64_t cbSeg;
|
---|
| 81 | /** Pointer to the start of the data in the test pattern used for the segment. */
|
---|
| 82 | uint8_t *pbData;
|
---|
| 83 | /** Pointer to the data for a diff write */
|
---|
| 84 | uint8_t *pbDataDiff;
|
---|
| 85 | } VDDISKSEG, *PVDDISKSEG;
|
---|
| 86 |
|
---|
[57358] | 87 |
|
---|
| 88 | /*********************************************************************************************************************************
|
---|
| 89 | * Global Variables *
|
---|
| 90 | *********************************************************************************************************************************/
|
---|
[27135] | 91 | /** The error count. */
|
---|
| 92 | unsigned g_cErrors = 0;
|
---|
[27186] | 93 | /** Global RNG state. */
|
---|
| 94 | RTRAND g_hRand;
|
---|
[27135] | 95 |
|
---|
[57415] | 96 | static DECLCALLBACK(void) tstVDError(void *pvUser, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)
|
---|
[27135] | 97 | {
|
---|
[62729] | 98 | RT_NOREF1(pvUser);
|
---|
[27135] | 99 | g_cErrors++;
|
---|
[57415] | 100 | RTPrintf("tstVDSnap: Error %Rrc at %s:%u (%s): ", rc, RT_SRC_POS_ARGS);
|
---|
[27135] | 101 | RTPrintfV(pszFormat, va);
|
---|
| 102 | RTPrintf("\n");
|
---|
| 103 | }
|
---|
| 104 |
|
---|
[57415] | 105 | static DECLCALLBACK(int) tstVDMessage(void *pvUser, const char *pszFormat, va_list va)
|
---|
[27135] | 106 | {
|
---|
[62729] | 107 | RT_NOREF1(pvUser);
|
---|
[57415] | 108 | RTPrintf("tstVDSnap: ");
|
---|
[27135] | 109 | RTPrintfV(pszFormat, va);
|
---|
| 110 | return VINF_SUCCESS;
|
---|
| 111 | }
|
---|
| 112 |
|
---|
| 113 | /**
|
---|
| 114 | * Returns true with the given chance in percent.
|
---|
| 115 | *
|
---|
| 116 | * @returns true or false
|
---|
| 117 | * @param iPercentage The percentage of the chance to return true.
|
---|
| 118 | */
|
---|
| 119 | static bool tstVDSnapIsTrue(int iPercentage)
|
---|
| 120 | {
|
---|
[27186] | 121 | int uRnd = RTRandAdvU32Ex(g_hRand, 0, 100);
|
---|
[27135] | 122 |
|
---|
| 123 | return (uRnd <= iPercentage); /* This should be enough for our purpose */
|
---|
| 124 | }
|
---|
| 125 |
|
---|
| 126 | static void tstVDSnapSegmentsDice(PVDSNAPTEST pTest, PVDDISKSEG paDiskSeg, uint32_t cDiskSegments,
|
---|
| 127 | uint8_t *pbTestPattern, size_t cbTestPattern)
|
---|
| 128 | {
|
---|
| 129 | for (uint32_t i = 0; i < cDiskSegments; i++)
|
---|
| 130 | {
|
---|
| 131 | /* Do we want to change the current segment? */
|
---|
| 132 | if (tstVDSnapIsTrue(pTest->uChangeSegChance))
|
---|
[27186] | 133 | paDiskSeg[i].pbDataDiff = pbTestPattern + RT_ALIGN_64(RTRandAdvU64Ex(g_hRand, 0, cbTestPattern - paDiskSeg[i].cbSeg - 512), 512);
|
---|
[27135] | 134 | }
|
---|
| 135 | }
|
---|
| 136 |
|
---|
[66250] | 137 | static int tstVDSnapWrite(PVDISK pVD, PVDDISKSEG paDiskSegments, uint32_t cDiskSegments, uint64_t cbDisk, bool fInit)
|
---|
[27135] | 138 | {
|
---|
[62729] | 139 | RT_NOREF1(cbDisk);
|
---|
[27135] | 140 | int rc = VINF_SUCCESS;
|
---|
| 141 |
|
---|
| 142 | for (uint32_t i = 0; i < cDiskSegments; i++)
|
---|
| 143 | {
|
---|
| 144 | if (fInit || paDiskSegments[i].pbDataDiff)
|
---|
| 145 | {
|
---|
| 146 | size_t cbWrite = paDiskSegments[i].cbSeg;
|
---|
| 147 | uint64_t off = paDiskSegments[i].off;
|
---|
[27137] | 148 | uint8_t *pbData = fInit
|
---|
| 149 | ? paDiskSegments[i].pbData
|
---|
| 150 | : paDiskSegments[i].pbDataDiff;
|
---|
[27135] | 151 |
|
---|
[27137] | 152 | if (pbData)
|
---|
| 153 | {
|
---|
| 154 | rc = VDWrite(pVD, off, pbData, cbWrite);
|
---|
| 155 | if (RT_FAILURE(rc))
|
---|
| 156 | return rc;
|
---|
| 157 | }
|
---|
[27135] | 158 | }
|
---|
| 159 | }
|
---|
| 160 |
|
---|
| 161 | return rc;
|
---|
| 162 | }
|
---|
| 163 |
|
---|
[66250] | 164 | static int tstVDSnapReadVerify(PVDISK pVD, PVDDISKSEG paDiskSegments, uint32_t cDiskSegments, uint64_t cbDisk)
|
---|
[27135] | 165 | {
|
---|
[62729] | 166 | RT_NOREF1(cbDisk);
|
---|
[27135] | 167 | int rc = VINF_SUCCESS;
|
---|
| 168 | uint8_t *pbBuf = (uint8_t *)RTMemAlloc(_1M);
|
---|
| 169 |
|
---|
| 170 | for (uint32_t i = 0; i < cDiskSegments; i++)
|
---|
| 171 | {
|
---|
| 172 | size_t cbRead = paDiskSegments[i].cbSeg;
|
---|
| 173 | uint64_t off = paDiskSegments[i].off;
|
---|
| 174 | uint8_t *pbCmp = paDiskSegments[i].pbData;
|
---|
| 175 |
|
---|
| 176 | Assert(!paDiskSegments[i].pbDataDiff);
|
---|
| 177 |
|
---|
| 178 | while (cbRead)
|
---|
| 179 | {
|
---|
| 180 | size_t cbToRead = RT_MIN(cbRead, _1M);
|
---|
| 181 |
|
---|
| 182 | rc = VDRead(pVD, off, pbBuf, cbToRead);
|
---|
| 183 | if (RT_FAILURE(rc))
|
---|
| 184 | return rc;
|
---|
| 185 |
|
---|
[27137] | 186 | if (pbCmp)
|
---|
[27135] | 187 | {
|
---|
[27137] | 188 | if (memcmp(pbCmp, pbBuf, cbToRead))
|
---|
| 189 | {
|
---|
| 190 | for (unsigned iCmp = 0; iCmp < cbToRead; iCmp++)
|
---|
| 191 | {
|
---|
| 192 | if (pbCmp[iCmp] != pbBuf[iCmp])
|
---|
| 193 | {
|
---|
| 194 | RTPrintf("Unexpected data at %llu expected %#x got %#x\n", off+iCmp, pbCmp[iCmp], pbBuf[iCmp]);
|
---|
| 195 | break;
|
---|
| 196 | }
|
---|
| 197 | }
|
---|
| 198 | return VERR_INTERNAL_ERROR;
|
---|
| 199 | }
|
---|
| 200 | }
|
---|
| 201 | else
|
---|
| 202 | {
|
---|
| 203 | /* Verify that the block is 0 */
|
---|
[27135] | 204 | for (unsigned iCmp = 0; iCmp < cbToRead; iCmp++)
|
---|
| 205 | {
|
---|
[27137] | 206 | if (pbBuf[iCmp] != 0)
|
---|
[27135] | 207 | {
|
---|
[27137] | 208 | RTPrintf("Zero block contains data at %llu\n", off+iCmp);
|
---|
| 209 | return VERR_INTERNAL_ERROR;
|
---|
[27135] | 210 | }
|
---|
| 211 | }
|
---|
| 212 | }
|
---|
| 213 |
|
---|
| 214 | cbRead -= cbToRead;
|
---|
| 215 | off += cbToRead;
|
---|
[27137] | 216 |
|
---|
| 217 | if (pbCmp)
|
---|
| 218 | pbCmp += cbToRead;
|
---|
[27135] | 219 | }
|
---|
| 220 | }
|
---|
| 221 |
|
---|
| 222 | RTMemFree(pbBuf);
|
---|
| 223 |
|
---|
| 224 | return rc;
|
---|
| 225 | }
|
---|
| 226 |
|
---|
| 227 | static int tstVDOpenCreateWriteMerge(PVDSNAPTEST pTest)
|
---|
| 228 | {
|
---|
| 229 | int rc;
|
---|
[66250] | 230 | PVDISK pVD = NULL;
|
---|
[32536] | 231 | VDGEOMETRY PCHS = { 0, 0, 0 };
|
---|
| 232 | VDGEOMETRY LCHS = { 0, 0, 0 };
|
---|
[27135] | 233 | PVDINTERFACE pVDIfs = NULL;
|
---|
[38469] | 234 | VDINTERFACEERROR VDIfError;
|
---|
| 235 |
|
---|
[27135] | 236 | /** Buffer storing the random test pattern. */
|
---|
| 237 | uint8_t *pbTestPattern = NULL;
|
---|
| 238 | /** Number of disk segments */
|
---|
| 239 | uint32_t cDiskSegments;
|
---|
| 240 | /** Array of disk segments */
|
---|
| 241 | PVDDISKSEG paDiskSeg = NULL;
|
---|
| 242 | unsigned cDiffs = 0;
|
---|
| 243 | unsigned idDiff = 0; /* Diff ID counter for the filename */
|
---|
| 244 |
|
---|
[45199] | 245 | /* Delete all images from a previous run. */
|
---|
| 246 | RTFileDelete(pTest->pcszBaseImage);
|
---|
| 247 | for (unsigned i = 0; i < pTest->cIterations; i++)
|
---|
| 248 | {
|
---|
| 249 | char *pszDiffFilename = NULL;
|
---|
| 250 |
|
---|
| 251 | rc = RTStrAPrintf(&pszDiffFilename, "tstVDSnapDiff%u.%s", i, pTest->pcszDiffSuff);
|
---|
| 252 | if (RT_SUCCESS(rc))
|
---|
| 253 | {
|
---|
| 254 | if (RTFileExists(pszDiffFilename))
|
---|
| 255 | RTFileDelete(pszDiffFilename);
|
---|
| 256 | RTStrFree(pszDiffFilename);
|
---|
| 257 | }
|
---|
| 258 | }
|
---|
| 259 |
|
---|
[27135] | 260 | /* Create the virtual disk test data */
|
---|
| 261 | pbTestPattern = (uint8_t *)RTMemAlloc(pTest->cbTestPattern);
|
---|
[103522] | 262 | if (!pbTestPattern)
|
---|
| 263 | {
|
---|
| 264 | RTPrintf("Failed to allocate memory for test pattern\n");
|
---|
| 265 | g_cErrors++;
|
---|
| 266 | return VERR_NO_MEMORY;
|
---|
| 267 | }
|
---|
[27135] | 268 |
|
---|
[27186] | 269 | RTRandAdvBytes(g_hRand, pbTestPattern, pTest->cbTestPattern);
|
---|
| 270 | cDiskSegments = RTRandAdvU32Ex(g_hRand, pTest->cDiskSegsMin, pTest->cDiskSegsMax);
|
---|
[27135] | 271 |
|
---|
| 272 | uint64_t cbDisk = 0;
|
---|
| 273 |
|
---|
| 274 | paDiskSeg = (PVDDISKSEG)RTMemAllocZ(cDiskSegments * sizeof(VDDISKSEG));
|
---|
[56754] | 275 | if (!paDiskSeg)
|
---|
| 276 | {
|
---|
| 277 | RTPrintf("Failed to allocate memory for random disk segments\n");
|
---|
| 278 | g_cErrors++;
|
---|
| 279 | return VERR_NO_MEMORY;
|
---|
| 280 | }
|
---|
| 281 |
|
---|
[27135] | 282 | for (unsigned i = 0; i < cDiskSegments; i++)
|
---|
| 283 | {
|
---|
| 284 | paDiskSeg[i].off = cbDisk;
|
---|
[27186] | 285 | paDiskSeg[i].cbSeg = RT_ALIGN_64(RTRandAdvU64Ex(g_hRand, 512, pTest->cbTestPattern), 512);
|
---|
[27137] | 286 | if (tstVDSnapIsTrue(pTest->uAllocatedBlocks))
|
---|
[27186] | 287 | paDiskSeg[i].pbData = pbTestPattern + RT_ALIGN_64(RTRandAdvU64Ex(g_hRand, 0, pTest->cbTestPattern - paDiskSeg[i].cbSeg - 512), 512);
|
---|
[27137] | 288 | else
|
---|
| 289 | paDiskSeg[i].pbData = NULL; /* Not allocated initially */
|
---|
[27135] | 290 | cbDisk += paDiskSeg[i].cbSeg;
|
---|
| 291 | }
|
---|
| 292 |
|
---|
| 293 | RTPrintf("Disk size is %llu bytes\n", cbDisk);
|
---|
| 294 |
|
---|
| 295 | #define CHECK(str) \
|
---|
| 296 | do \
|
---|
| 297 | { \
|
---|
| 298 | RTPrintf("%s rc=%Rrc\n", str, rc); \
|
---|
| 299 | if (RT_FAILURE(rc)) \
|
---|
| 300 | { \
|
---|
| 301 | if (pbTestPattern) \
|
---|
| 302 | RTMemFree(pbTestPattern); \
|
---|
[56754] | 303 | if (paDiskSeg) \
|
---|
| 304 | RTMemFree(paDiskSeg); \
|
---|
[27135] | 305 | VDDestroy(pVD); \
|
---|
[46614] | 306 | g_cErrors++; \
|
---|
[27135] | 307 | return rc; \
|
---|
| 308 | } \
|
---|
| 309 | } while (0)
|
---|
| 310 |
|
---|
[45200] | 311 | #define CHECK_BREAK(str) \
|
---|
| 312 | do \
|
---|
| 313 | { \
|
---|
| 314 | RTPrintf("%s rc=%Rrc\n", str, rc); \
|
---|
| 315 | if (RT_FAILURE(rc)) \
|
---|
| 316 | { \
|
---|
[46614] | 317 | g_cErrors++; \
|
---|
[45200] | 318 | break; \
|
---|
| 319 | } \
|
---|
| 320 | } while (0)
|
---|
| 321 |
|
---|
[27135] | 322 | /* Create error interface. */
|
---|
[38469] | 323 | /* Create error interface. */
|
---|
| 324 | VDIfError.pfnError = tstVDError;
|
---|
| 325 | VDIfError.pfnMessage = tstVDMessage;
|
---|
[27135] | 326 |
|
---|
[38469] | 327 | rc = VDInterfaceAdd(&VDIfError.Core, "tstVD_Error", VDINTERFACETYPE_ERROR,
|
---|
| 328 | NULL, sizeof(VDINTERFACEERROR), &pVDIfs);
|
---|
[27135] | 329 | AssertRC(rc);
|
---|
| 330 |
|
---|
| 331 |
|
---|
[33524] | 332 | rc = VDCreate(pVDIfs, VDTYPE_HDD, &pVD);
|
---|
[27135] | 333 | CHECK("VDCreate()");
|
---|
| 334 |
|
---|
| 335 | rc = VDCreateBase(pVD, pTest->pcszBackend, pTest->pcszBaseImage, cbDisk,
|
---|
| 336 | VD_IMAGE_FLAGS_NONE, "Test image",
|
---|
| 337 | &PCHS, &LCHS, NULL, VD_OPEN_FLAGS_NORMAL,
|
---|
| 338 | NULL, NULL);
|
---|
| 339 | CHECK("VDCreateBase()");
|
---|
| 340 |
|
---|
| 341 | bool fInit = true;
|
---|
| 342 | uint32_t cIteration = 0;
|
---|
| 343 |
|
---|
| 344 | /* Do the real work now */
|
---|
| 345 | while ( RT_SUCCESS(rc)
|
---|
| 346 | && cIteration < pTest->cIterations)
|
---|
| 347 | {
|
---|
| 348 | /* Write */
|
---|
| 349 | rc = tstVDSnapWrite(pVD, paDiskSeg, cDiskSegments, cbDisk, fInit);
|
---|
[45200] | 350 | CHECK_BREAK("tstVDSnapWrite()");
|
---|
[27135] | 351 |
|
---|
| 352 | fInit = false;
|
---|
| 353 |
|
---|
| 354 | /* Write returned, do we want to create a new diff or merge them? */
|
---|
| 355 | bool fCreate = cDiffs < pTest->cDiffsMinBeforeMerge
|
---|
| 356 | ? true
|
---|
| 357 | : tstVDSnapIsTrue(pTest->uCreateDiffChance);
|
---|
| 358 |
|
---|
| 359 | if (fCreate)
|
---|
| 360 | {
|
---|
| 361 | char *pszDiffFilename = NULL;
|
---|
| 362 |
|
---|
| 363 | RTStrAPrintf(&pszDiffFilename, "tstVDSnapDiff%u.%s", idDiff, pTest->pcszDiffSuff);
|
---|
| 364 | CHECK("RTStrAPrintf()");
|
---|
| 365 | idDiff++;
|
---|
| 366 | cDiffs++;
|
---|
| 367 |
|
---|
| 368 | rc = VDCreateDiff(pVD, pTest->pcszBackend, pszDiffFilename,
|
---|
| 369 | VD_IMAGE_FLAGS_NONE, "Test diff image", NULL, NULL,
|
---|
| 370 | VD_OPEN_FLAGS_NORMAL, NULL, NULL);
|
---|
[45200] | 371 | CHECK_BREAK("VDCreateDiff()");
|
---|
[27135] | 372 |
|
---|
| 373 | RTStrFree(pszDiffFilename);
|
---|
| 374 | VDDumpImages(pVD);
|
---|
| 375 |
|
---|
| 376 | /* Change data */
|
---|
| 377 | tstVDSnapSegmentsDice(pTest, paDiskSeg, cDiskSegments, pbTestPattern, pTest->cbTestPattern);
|
---|
| 378 | }
|
---|
| 379 | else
|
---|
| 380 | {
|
---|
[27186] | 381 | uint32_t uStartMerge = RTRandAdvU32Ex(g_hRand, 1, cDiffs - 1);
|
---|
| 382 | uint32_t uEndMerge = RTRandAdvU32Ex(g_hRand, uStartMerge + 1, cDiffs);
|
---|
[27135] | 383 | RTPrintf("Merging %u diffs from %u to %u...\n",
|
---|
| 384 | uEndMerge - uStartMerge,
|
---|
| 385 | uStartMerge,
|
---|
| 386 | uEndMerge);
|
---|
[27655] | 387 | if (pTest->fForward)
|
---|
| 388 | rc = VDMerge(pVD, uStartMerge, uEndMerge, NULL);
|
---|
| 389 | else
|
---|
| 390 | rc = VDMerge(pVD, uEndMerge, uStartMerge, NULL);
|
---|
[45200] | 391 | CHECK_BREAK("VDMerge()");
|
---|
[27135] | 392 |
|
---|
| 393 | cDiffs -= uEndMerge - uStartMerge;
|
---|
| 394 |
|
---|
| 395 | VDDumpImages(pVD);
|
---|
| 396 |
|
---|
| 397 | /* Go through the disk segments and reset pointers. */
|
---|
| 398 | for (uint32_t i = 0; i < cDiskSegments; i++)
|
---|
| 399 | {
|
---|
| 400 | if (paDiskSeg[i].pbDataDiff)
|
---|
| 401 | {
|
---|
| 402 | paDiskSeg[i].pbData = paDiskSeg[i].pbDataDiff;
|
---|
| 403 | paDiskSeg[i].pbDataDiff = NULL;
|
---|
| 404 | }
|
---|
| 405 | }
|
---|
| 406 |
|
---|
| 407 | /* Now compare the result with our test pattern */
|
---|
| 408 | rc = tstVDSnapReadVerify(pVD, paDiskSeg, cDiskSegments, cbDisk);
|
---|
[45200] | 409 | CHECK_BREAK("tstVDSnapReadVerify()");
|
---|
[27135] | 410 | }
|
---|
| 411 | cIteration++;
|
---|
| 412 | }
|
---|
| 413 |
|
---|
| 414 | VDDumpImages(pVD);
|
---|
| 415 |
|
---|
| 416 | VDDestroy(pVD);
|
---|
[103522] | 417 | RTMemFree(paDiskSeg);
|
---|
| 418 | RTMemFree(pbTestPattern);
|
---|
[27135] | 419 |
|
---|
| 420 | RTFileDelete(pTest->pcszBaseImage);
|
---|
| 421 | for (unsigned i = 0; i < idDiff; i++)
|
---|
| 422 | {
|
---|
| 423 | char *pszDiffFilename = NULL;
|
---|
| 424 |
|
---|
| 425 | RTStrAPrintf(&pszDiffFilename, "tstVDSnapDiff%u.%s", i, pTest->pcszDiffSuff);
|
---|
| 426 | RTFileDelete(pszDiffFilename);
|
---|
| 427 | RTStrFree(pszDiffFilename);
|
---|
| 428 | }
|
---|
| 429 | #undef CHECK
|
---|
[45200] | 430 | return rc;
|
---|
[27135] | 431 | }
|
---|
| 432 |
|
---|
| 433 | int main(int argc, char *argv[])
|
---|
| 434 | {
|
---|
[38636] | 435 | RTR3InitExe(argc, &argv, 0);
|
---|
[27135] | 436 | int rc;
|
---|
| 437 | VDSNAPTEST Test;
|
---|
| 438 |
|
---|
| 439 | RTPrintf("tstVDSnap: TESTING...\n");
|
---|
| 440 |
|
---|
[27186] | 441 | rc = RTRandAdvCreateParkMiller(&g_hRand);
|
---|
| 442 | if (RT_FAILURE(rc))
|
---|
| 443 | {
|
---|
| 444 | RTPrintf("tstVDSnap: Creating RNG failed rc=%Rrc\n", rc);
|
---|
| 445 | return 1;
|
---|
| 446 | }
|
---|
| 447 |
|
---|
[27187] | 448 | RTRandAdvSeed(g_hRand, 0x12345678);
|
---|
[27186] | 449 |
|
---|
| 450 | Test.pcszBackend = "vmdk";
|
---|
| 451 | Test.pcszBaseImage = "tstVDSnapBase.vmdk";
|
---|
| 452 | Test.pcszDiffSuff = "vmdk";
|
---|
| 453 | Test.cIterations = 30;
|
---|
[27135] | 454 | Test.cbTestPattern = 10 * _1M;
|
---|
[27186] | 455 | Test.cDiskSegsMin = 10;
|
---|
| 456 | Test.cDiskSegsMax = 50;
|
---|
| 457 | Test.cDiffsMinBeforeMerge = 5;
|
---|
[27135] | 458 | Test.uCreateDiffChance = 50; /* % */
|
---|
[27186] | 459 | Test.uChangeSegChance = 50; /* % */
|
---|
[27137] | 460 | Test.uAllocatedBlocks = 50; /* 50% allocated */
|
---|
[27655] | 461 | Test.fForward = true;
|
---|
[27135] | 462 | tstVDOpenCreateWriteMerge(&Test);
|
---|
| 463 |
|
---|
[27655] | 464 | /* Same test with backwards merge */
|
---|
| 465 | Test.fForward = false;
|
---|
| 466 | tstVDOpenCreateWriteMerge(&Test);
|
---|
| 467 |
|
---|
[27135] | 468 | rc = VDShutdown();
|
---|
| 469 | if (RT_FAILURE(rc))
|
---|
| 470 | {
|
---|
| 471 | RTPrintf("tstVDSnap: unloading backends failed! rc=%Rrc\n", rc);
|
---|
| 472 | g_cErrors++;
|
---|
| 473 | }
|
---|
| 474 | /*
|
---|
| 475 | * Summary
|
---|
| 476 | */
|
---|
| 477 | if (!g_cErrors)
|
---|
| 478 | RTPrintf("tstVDSnap: SUCCESS\n");
|
---|
| 479 | else
|
---|
| 480 | RTPrintf("tstVDSnap: FAILURE - %d errors\n", g_cErrors);
|
---|
| 481 |
|
---|
[27186] | 482 | RTRandAdvDestroy(g_hRand);
|
---|
| 483 |
|
---|
[27135] | 484 | return !!g_cErrors;
|
---|
| 485 | }
|
---|
| 486 |
|
---|