VirtualBox

source: vbox/trunk/src/VBox/Storage/testcase/tstVDSnap.cpp@ 38469

最後變更 在這個檔案從38469是 38469,由 vboxsync 提交於 14 年 前

VD: Interface cleanup. Merge the two involved structures (generic interface descriptor and callback table) into one, remove the duplicated interface wrappers in the backends and move the interface definitions into separate headers separating public and private interfaces.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 12.9 KB
 
1/** @file
2 *
3 * Snapshot VBox HDD container test utility.
4 */
5
6/*
7 * Copyright (C) 2010 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.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#include <VBox/vd.h>
19#include <VBox/err.h>
20#include <VBox/log.h>
21#include <iprt/asm.h>
22#include <iprt/dir.h>
23#include <iprt/string.h>
24#include <iprt/stream.h>
25#include <iprt/file.h>
26#include <iprt/mem.h>
27#include <iprt/initterm.h>
28#include <iprt/rand.h>
29
30/**
31 * A VD snapshot test.
32 */
33typedef struct VDSNAPTEST
34{
35 /** Backend to use */
36 const char *pcszBackend;
37 /** Base image name */
38 const char *pcszBaseImage;
39 /** Diff image ending */
40 const char *pcszDiffSuff;
41 /** Number of iterations before the test exits */
42 uint32_t cIterations;
43 /** Test pattern size */
44 size_t cbTestPattern;
45 /** Minimum number of disk segments */
46 uint32_t cDiskSegsMin;
47 /** Miaximum number of disk segments */
48 uint32_t cDiskSegsMax;
49 /** Minimum number of diffs needed before a merge
50 * operation can occur */
51 unsigned cDiffsMinBeforeMerge;
52 /** Chance to get create instead of a merge operation */
53 uint32_t uCreateDiffChance;
54 /** Chance to change a segment after a diff was created */
55 uint32_t uChangeSegChance;
56 /** Numer of allocated blocks in the base image in percent */
57 uint32_t uAllocatedBlocks;
58 /** Merge direction */
59 bool fForward;
60} VDSNAPTEST, *PVDSNAPTEST;
61
62/**
63 * Structure defining a disk segment.
64 */
65typedef struct VDDISKSEG
66{
67 /** Start offset in the disk. */
68 uint64_t off;
69 /** Size of the segment. */
70 uint64_t cbSeg;
71 /** Pointer to the start of the data in the test pattern used for the segment. */
72 uint8_t *pbData;
73 /** Pointer to the data for a diff write */
74 uint8_t *pbDataDiff;
75} VDDISKSEG, *PVDDISKSEG;
76
77/*******************************************************************************
78* Global Variables *
79*******************************************************************************/
80/** The error count. */
81unsigned g_cErrors = 0;
82/** Global RNG state. */
83RTRAND g_hRand;
84
85static void tstVDError(void *pvUser, int rc, RT_SRC_POS_DECL,
86 const char *pszFormat, va_list va)
87{
88 g_cErrors++;
89 RTPrintf("tstVD: Error %Rrc at %s:%u (%s): ", rc, RT_SRC_POS_ARGS);
90 RTPrintfV(pszFormat, va);
91 RTPrintf("\n");
92}
93
94static int tstVDMessage(void *pvUser, const char *pszFormat, va_list va)
95{
96 RTPrintf("tstVD: ");
97 RTPrintfV(pszFormat, va);
98 return VINF_SUCCESS;
99}
100
101/**
102 * Returns true with the given chance in percent.
103 *
104 * @returns true or false
105 * @param iPercentage The percentage of the chance to return true.
106 */
107static bool tstVDSnapIsTrue(int iPercentage)
108{
109 int uRnd = RTRandAdvU32Ex(g_hRand, 0, 100);
110
111 return (uRnd <= iPercentage); /* This should be enough for our purpose */
112}
113
114static void tstVDSnapSegmentsDice(PVDSNAPTEST pTest, PVDDISKSEG paDiskSeg, uint32_t cDiskSegments,
115 uint8_t *pbTestPattern, size_t cbTestPattern)
116{
117 for (uint32_t i = 0; i < cDiskSegments; i++)
118 {
119 /* Do we want to change the current segment? */
120 if (tstVDSnapIsTrue(pTest->uChangeSegChance))
121 paDiskSeg[i].pbDataDiff = pbTestPattern + RT_ALIGN_64(RTRandAdvU64Ex(g_hRand, 0, cbTestPattern - paDiskSeg[i].cbSeg - 512), 512);
122 }
123}
124
125static int tstVDSnapWrite(PVBOXHDD pVD, PVDDISKSEG paDiskSegments,
126 uint32_t cDiskSegments, uint64_t cbDisk, bool fInit)
127{
128 int rc = VINF_SUCCESS;
129
130 for (uint32_t i = 0; i < cDiskSegments; i++)
131 {
132 if (fInit || paDiskSegments[i].pbDataDiff)
133 {
134 size_t cbWrite = paDiskSegments[i].cbSeg;
135 uint64_t off = paDiskSegments[i].off;
136 uint8_t *pbData = fInit
137 ? paDiskSegments[i].pbData
138 : paDiskSegments[i].pbDataDiff;
139
140 if (pbData)
141 {
142 rc = VDWrite(pVD, off, pbData, cbWrite);
143 if (RT_FAILURE(rc))
144 return rc;
145 }
146 }
147 }
148
149 return rc;
150}
151
152static int tstVDSnapReadVerify(PVBOXHDD pVD, PVDDISKSEG paDiskSegments, uint32_t cDiskSegments, uint64_t cbDisk)
153{
154 int rc = VINF_SUCCESS;
155 uint8_t *pbBuf = (uint8_t *)RTMemAlloc(_1M);
156
157 for (uint32_t i = 0; i < cDiskSegments; i++)
158 {
159 size_t cbRead = paDiskSegments[i].cbSeg;
160 uint64_t off = paDiskSegments[i].off;
161 uint8_t *pbCmp = paDiskSegments[i].pbData;
162
163 Assert(!paDiskSegments[i].pbDataDiff);
164
165 while (cbRead)
166 {
167 size_t cbToRead = RT_MIN(cbRead, _1M);
168
169 rc = VDRead(pVD, off, pbBuf, cbToRead);
170 if (RT_FAILURE(rc))
171 return rc;
172
173 if (pbCmp)
174 {
175 if (memcmp(pbCmp, pbBuf, cbToRead))
176 {
177 for (unsigned iCmp = 0; iCmp < cbToRead; iCmp++)
178 {
179 if (pbCmp[iCmp] != pbBuf[iCmp])
180 {
181 RTPrintf("Unexpected data at %llu expected %#x got %#x\n", off+iCmp, pbCmp[iCmp], pbBuf[iCmp]);
182 break;
183 }
184 }
185 return VERR_INTERNAL_ERROR;
186 }
187 }
188 else
189 {
190 /* Verify that the block is 0 */
191 for (unsigned iCmp = 0; iCmp < cbToRead; iCmp++)
192 {
193 if (pbBuf[iCmp] != 0)
194 {
195 RTPrintf("Zero block contains data at %llu\n", off+iCmp);
196 return VERR_INTERNAL_ERROR;
197 }
198 }
199 }
200
201 cbRead -= cbToRead;
202 off += cbToRead;
203
204 if (pbCmp)
205 pbCmp += cbToRead;
206 }
207 }
208
209 RTMemFree(pbBuf);
210
211 return rc;
212}
213
214static int tstVDOpenCreateWriteMerge(PVDSNAPTEST pTest)
215{
216 int rc;
217 PVBOXHDD pVD = NULL;
218 VDGEOMETRY PCHS = { 0, 0, 0 };
219 VDGEOMETRY LCHS = { 0, 0, 0 };
220 PVDINTERFACE pVDIfs = NULL;
221 VDINTERFACEERROR VDIfError;
222
223 /** Buffer storing the random test pattern. */
224 uint8_t *pbTestPattern = NULL;
225 /** Number of disk segments */
226 uint32_t cDiskSegments;
227 /** Array of disk segments */
228 PVDDISKSEG paDiskSeg = NULL;
229 unsigned cDiffs = 0;
230 unsigned idDiff = 0; /* Diff ID counter for the filename */
231
232 /* Create the virtual disk test data */
233 pbTestPattern = (uint8_t *)RTMemAlloc(pTest->cbTestPattern);
234
235 RTRandAdvBytes(g_hRand, pbTestPattern, pTest->cbTestPattern);
236 cDiskSegments = RTRandAdvU32Ex(g_hRand, pTest->cDiskSegsMin, pTest->cDiskSegsMax);
237
238 uint64_t cbDisk = 0;
239
240 paDiskSeg = (PVDDISKSEG)RTMemAllocZ(cDiskSegments * sizeof(VDDISKSEG));
241 for (unsigned i = 0; i < cDiskSegments; i++)
242 {
243 paDiskSeg[i].off = cbDisk;
244 paDiskSeg[i].cbSeg = RT_ALIGN_64(RTRandAdvU64Ex(g_hRand, 512, pTest->cbTestPattern), 512);
245 if (tstVDSnapIsTrue(pTest->uAllocatedBlocks))
246 paDiskSeg[i].pbData = pbTestPattern + RT_ALIGN_64(RTRandAdvU64Ex(g_hRand, 0, pTest->cbTestPattern - paDiskSeg[i].cbSeg - 512), 512);
247 else
248 paDiskSeg[i].pbData = NULL; /* Not allocated initially */
249 cbDisk += paDiskSeg[i].cbSeg;
250 }
251
252 RTPrintf("Disk size is %llu bytes\n", cbDisk);
253
254#define CHECK(str) \
255 do \
256 { \
257 RTPrintf("%s rc=%Rrc\n", str, rc); \
258 if (RT_FAILURE(rc)) \
259 { \
260 if (pbTestPattern) \
261 RTMemFree(pbTestPattern); \
262 VDDestroy(pVD); \
263 return rc; \
264 } \
265 } while (0)
266
267 /* Create error interface. */
268 /* Create error interface. */
269 VDIfError.pfnError = tstVDError;
270 VDIfError.pfnMessage = tstVDMessage;
271
272 rc = VDInterfaceAdd(&VDIfError.Core, "tstVD_Error", VDINTERFACETYPE_ERROR,
273 NULL, sizeof(VDINTERFACEERROR), &pVDIfs);
274 AssertRC(rc);
275
276
277 rc = VDCreate(pVDIfs, VDTYPE_HDD, &pVD);
278 CHECK("VDCreate()");
279
280 rc = VDCreateBase(pVD, pTest->pcszBackend, pTest->pcszBaseImage, cbDisk,
281 VD_IMAGE_FLAGS_NONE, "Test image",
282 &PCHS, &LCHS, NULL, VD_OPEN_FLAGS_NORMAL,
283 NULL, NULL);
284 CHECK("VDCreateBase()");
285
286 bool fInit = true;
287 uint32_t cIteration = 0;
288
289 /* Do the real work now */
290 while ( RT_SUCCESS(rc)
291 && cIteration < pTest->cIterations)
292 {
293 /* Write */
294 rc = tstVDSnapWrite(pVD, paDiskSeg, cDiskSegments, cbDisk, fInit);
295 CHECK("tstVDSnapWrite()");
296
297 fInit = false;
298
299 /* Write returned, do we want to create a new diff or merge them? */
300 bool fCreate = cDiffs < pTest->cDiffsMinBeforeMerge
301 ? true
302 : tstVDSnapIsTrue(pTest->uCreateDiffChance);
303
304 if (fCreate)
305 {
306 char *pszDiffFilename = NULL;
307
308 RTStrAPrintf(&pszDiffFilename, "tstVDSnapDiff%u.%s", idDiff, pTest->pcszDiffSuff);
309 CHECK("RTStrAPrintf()");
310 idDiff++;
311 cDiffs++;
312
313 rc = VDCreateDiff(pVD, pTest->pcszBackend, pszDiffFilename,
314 VD_IMAGE_FLAGS_NONE, "Test diff image", NULL, NULL,
315 VD_OPEN_FLAGS_NORMAL, NULL, NULL);
316 CHECK("VDCreateDiff()");
317
318 RTStrFree(pszDiffFilename);
319 VDDumpImages(pVD);
320
321 /* Change data */
322 tstVDSnapSegmentsDice(pTest, paDiskSeg, cDiskSegments, pbTestPattern, pTest->cbTestPattern);
323 }
324 else
325 {
326 uint32_t uStartMerge = RTRandAdvU32Ex(g_hRand, 1, cDiffs - 1);
327 uint32_t uEndMerge = RTRandAdvU32Ex(g_hRand, uStartMerge + 1, cDiffs);
328 RTPrintf("Merging %u diffs from %u to %u...\n",
329 uEndMerge - uStartMerge,
330 uStartMerge,
331 uEndMerge);
332 if (pTest->fForward)
333 rc = VDMerge(pVD, uStartMerge, uEndMerge, NULL);
334 else
335 rc = VDMerge(pVD, uEndMerge, uStartMerge, NULL);
336 CHECK("VDMerge()");
337
338 cDiffs -= uEndMerge - uStartMerge;
339
340 VDDumpImages(pVD);
341
342 /* Go through the disk segments and reset pointers. */
343 for (uint32_t i = 0; i < cDiskSegments; i++)
344 {
345 if (paDiskSeg[i].pbDataDiff)
346 {
347 paDiskSeg[i].pbData = paDiskSeg[i].pbDataDiff;
348 paDiskSeg[i].pbDataDiff = NULL;
349 }
350 }
351
352 /* Now compare the result with our test pattern */
353 rc = tstVDSnapReadVerify(pVD, paDiskSeg, cDiskSegments, cbDisk);
354 CHECK("tstVDSnapReadVerify()");
355 }
356 cIteration++;
357 }
358
359 VDDumpImages(pVD);
360
361 VDDestroy(pVD);
362 if (pbTestPattern)
363 RTMemFree(pbTestPattern);
364
365 RTFileDelete(pTest->pcszBaseImage);
366 for (unsigned i = 0; i < idDiff; i++)
367 {
368 char *pszDiffFilename = NULL;
369
370 RTStrAPrintf(&pszDiffFilename, "tstVDSnapDiff%u.%s", i, pTest->pcszDiffSuff);
371 RTFileDelete(pszDiffFilename);
372 RTStrFree(pszDiffFilename);
373 }
374#undef CHECK
375 return 0;
376}
377
378int main(int argc, char *argv[])
379{
380 RTR3Init();
381 int rc;
382 VDSNAPTEST Test;
383
384 RTPrintf("tstVDSnap: TESTING...\n");
385
386 rc = RTRandAdvCreateParkMiller(&g_hRand);
387 if (RT_FAILURE(rc))
388 {
389 RTPrintf("tstVDSnap: Creating RNG failed rc=%Rrc\n", rc);
390 return 1;
391 }
392
393 RTRandAdvSeed(g_hRand, 0x12345678);
394
395 Test.pcszBackend = "vmdk";
396 Test.pcszBaseImage = "tstVDSnapBase.vmdk";
397 Test.pcszDiffSuff = "vmdk";
398 Test.cIterations = 30;
399 Test.cbTestPattern = 10 * _1M;
400 Test.cDiskSegsMin = 10;
401 Test.cDiskSegsMax = 50;
402 Test.cDiffsMinBeforeMerge = 5;
403 Test.uCreateDiffChance = 50; /* % */
404 Test.uChangeSegChance = 50; /* % */
405 Test.uAllocatedBlocks = 50; /* 50% allocated */
406 Test.fForward = true;
407 tstVDOpenCreateWriteMerge(&Test);
408
409 /* Same test with backwards merge */
410 Test.fForward = false;
411 tstVDOpenCreateWriteMerge(&Test);
412
413 rc = VDShutdown();
414 if (RT_FAILURE(rc))
415 {
416 RTPrintf("tstVDSnap: unloading backends failed! rc=%Rrc\n", rc);
417 g_cErrors++;
418 }
419 /*
420 * Summary
421 */
422 if (!g_cErrors)
423 RTPrintf("tstVDSnap: SUCCESS\n");
424 else
425 RTPrintf("tstVDSnap: FAILURE - %d errors\n", g_cErrors);
426
427 RTRandAdvDestroy(g_hRand);
428
429 return !!g_cErrors;
430}
431
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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