Changeset 9262 in vbox for trunk/src/VBox
- Timestamp:
- May 30, 2008 5:32:54 PM (17 years ago)
- Location:
- trunk/src/VBox/Devices/Storage
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Storage/VBoxHDD-new.cpp
r8594 r9262 2216 2216 * @returns VERR_VDI_NOT_OPENED if no image is opened in HDD container. 2217 2217 * @param pDisk Pointer to HDD container. 2218 * @param uOffset Offset of first reading byte from start of disk. 2218 * @param uOffset Offset of the first byte being 2219 * written from start of disk. 2219 2220 * @param pvBuf Pointer to buffer for writing data. 2220 2221 * @param cbWrite Number of bytes to write. -
trunk/src/VBox/Devices/Storage/testcase/tstVD.cpp
r8248 r9262 27 27 #include <iprt/mem.h> 28 28 #include <iprt/initterm.h> 29 #include <iprt/rand.h> 30 #include "stdio.h" 31 #include "stdlib.h" 29 32 30 33 /******************************************************************************* … … 80 83 } 81 84 82 85 #if 0 83 86 static int tstVDOpenCreateWriteMerge(const char *pszBackend, 84 87 const char *pszBaseFilename, … … 175 178 return 0; 176 179 } 177 178 179 int main() 180 #else 181 182 #undef RTDECL 183 #define RTDECL(x) static x 184 185 /* Start of IPRT code */ 186 187 /** 188 * The following code is based on the work of George Marsaglia 189 * taken from 190 * http://groups.google.ws/group/comp.sys.sun.admin/msg/7c667186f6cbf354 191 * and 192 * http://groups.google.ws/group/comp.lang.c/msg/0e170777c6e79e8d 193 */ 194 195 /* 196 A C version of a very very good 64-bit RNG is given below. 197 You should be able to adapt it to your particular needs. 198 199 It is based on the complimentary-multiple-with-carry 200 sequence 201 x(n)=a*x(n-4)+carry mod 2^64-1, 202 which works as follows: 203 Assume a certain multiplier 'a' and a base 'b'. 204 Given a current x value and a current carry 'c', 205 form: t=a*x+c 206 Then the new carry is c=floor(t/b) 207 and the new x value is x = b-1-(t mod b). 208 209 210 Ordinarily, for 32-bit mwc or cmwc sequences, the 211 value t=a*x+c can be formed in 64 bits, then the new c 212 is the top and the new x the bottom 32 bits (with a little 213 fiddling when b=2^32-1 and cmwc rather than mwc.) 214 215 216 To generate 64-bit x's, it is difficult to form 217 t=a*x+c in 128 bits then get the new c and new x 218 from the the top and bottom halves. 219 But if 'a' has a special form, for example, 220 a=2^62+2^47+2 and b=2^64-1, then the new c and 221 the new x can be formed with shifts, tests and +/-'s, 222 again with a little fiddling because b=2^64-1 rather 223 than 2^64. (The latter is not an optimal choice because, 224 being a square, it cannot be a primitive root of the 225 prime a*b^k+1, where 'k' is the 'lag': 226 x(n)=a*x(n-k)+carry mod b.) 227 But the multiplier a=2^62+2^47+2 makes a*b^4+1 a prime for 228 which b=2^64-1 is a primitive root, and getting the new x and 229 new c can be done with arithmetic on integers the size of x. 230 */ 231 232 struct RndCtx 233 { 234 uint64_t x; 235 uint64_t y; 236 uint64_t z; 237 uint64_t w; 238 uint64_t c; 239 uint32_t u32x; 240 uint32_t u32y; 241 }; 242 typedef struct RndCtx RNDCTX; 243 typedef RNDCTX *PRNDCTX; 244 245 /** 246 * @todo I failed to make Windows' sscanf to process %llx format 247 * specification properly. If someone knows how to do it 248 * please re-write the format spec the way it stays the 249 * same on all platforms. We probably need RTStrScanf() 250 * anyway. 251 */ 252 253 #define RT_PRND_SEED_FSPEC_OUT "%016llx#%016llx#%016llx#%016llx#%016llx#%08x#%08x" 254 #ifdef RT_OS_WINDOWS 255 # define RT_PRND_SEED_FSPEC_IN "%I64x#%I64x#%I64x#%I64x#%I64x#%x#%x" 256 #else 257 # define RT_PRND_SEED_FSPEC_IN "%llx#%llx#%llx#%llx#%llx#%x#%x" 258 #endif 259 260 /** 261 * Initialize seeds. 262 * 263 * @remarks You should choose ANY 4 random 64-bit 264 * seeds x,y,z,w < 2^64-1 and a random seed c in 265 * 0<= c < a = 2^62+2^47+2. 266 * There are P=(2^62+2^46+2)*(2^64-1)^4 > 2^318 possible choices 267 * for seeds, the period of the RNG. 268 */ 269 RTDECL(int) RTPRandInit(PRNDCTX pCtx, const char *pszSeedInfo) 270 { 271 if (pszSeedInfo) 272 { 273 int nFieldsRead = sscanf(pszSeedInfo, RT_PRND_SEED_FSPEC_IN, 274 &pCtx->x, &pCtx->y, &pCtx->z, &pCtx->w, &pCtx->c, &pCtx->u32x, &pCtx->u32y); 275 if (nFieldsRead != 7 || pCtx->x > UINT64_MAX-1 || pCtx->y > UINT64_MAX-1 || 276 pCtx->z > UINT64_MAX-1 || pCtx->w > UINT64_MAX-1 || 277 pCtx->c > ((1ull << 62) + (1ull << 47) + 1) || pCtx->u32y == 0) 278 return VERR_INVALID_PARAMETER; 279 } 280 else 281 { 282 pCtx->x = RTRandU64Ex(0, UINT64_MAX-1); 283 pCtx->y = RTRandU64Ex(0, UINT64_MAX-1); 284 pCtx->z = RTRandU64Ex(0, UINT64_MAX-1); 285 pCtx->w = RTRandU64Ex(0, UINT64_MAX-1); 286 pCtx->c = RTRandU64Ex(0, (1ull << 62) + (1ull << 47) + 1); 287 pCtx->u32x = RTRandU32(); 288 pCtx->u32y = RTRandU32Ex(1, UINT32_MAX); 289 } 290 return VINF_SUCCESS; 291 } 292 293 RTDECL(int) RTPRandGetSeedInfo(PRNDCTX pCtx, char **ppszSeedInfo) 294 { 295 return RTStrAPrintf(ppszSeedInfo, RT_PRND_SEED_FSPEC_OUT, 296 pCtx->x, pCtx->y, pCtx->z, pCtx->w, pCtx->c, pCtx->u32x, pCtx->u32y); 297 } 298 299 /** 300 * Generate a 64-bit unsigned random number. 301 * 302 * @returns The pseudo random number. 303 */ 304 RTDECL(uint64_t) RTPRandU64(PRNDCTX pCtx) 305 { 306 uint64_t t; 307 t = (pCtx->x<<47) + (pCtx->x<<62) + (pCtx->x<<1); 308 t += pCtx->c; t+= (t < pCtx->c); 309 pCtx->c = (t<pCtx->c) + (pCtx->x>>17) + (pCtx->x>>2) + (pCtx->x>>63); 310 pCtx->x = pCtx->y; pCtx->y = pCtx->z ; pCtx->z = pCtx->w; 311 return (pCtx->w = ~(t + pCtx->c)-1); 312 } 313 314 /** 315 * Generate a 64-bit unsigned pseudo random number in the set 316 * [u64First..u64Last]. 317 * 318 * @returns The pseudo random number. 319 * @param u64First First number in the set. 320 * @param u64Last Last number in the set. 321 */ 322 RTDECL(uint64_t) RTPRandU64Ex(PRNDCTX pCtx, uint64_t u64First, uint64_t u64Last) 323 { 324 if (u64First == 0 && u64Last == UINT64_MAX) 325 return RTPRandU64(pCtx); 326 327 uint64_t u64Tmp; 328 uint64_t u64Range = u64Last - u64First + 1; 329 uint64_t u64Scale = UINT64_MAX / u64Range; 330 331 do 332 { 333 u64Tmp = RTPRandU64(pCtx) / u64Scale; 334 } while (u64Tmp >= u64Range); 335 return u64First + u64Tmp; 336 } 337 338 /** 339 * Generate a 32-bit unsigned random number. 340 * 341 * @returns The pseudo random number. 342 */ 343 RTDECL(uint32_t) RTPRandU32(PRNDCTX pCtx) 344 { 345 return ( pCtx->u32x = 69069 * pCtx->u32x + 123, 346 pCtx->u32y ^= pCtx->u32y<<13, 347 pCtx->u32y ^= pCtx->u32y>>17, 348 pCtx->u32y ^= pCtx->u32y<<5, 349 pCtx->u32x + pCtx->u32y ); 350 } 351 352 /** 353 * Generate a 32-bit unsigned pseudo random number in the set 354 * [u32First..u32Last]. 355 * 356 * @returns The pseudo random number. 357 * @param u32First First number in the set. 358 * @param u32Last Last number in the set. 359 */ 360 RTDECL(uint32_t) RTPRandU32Ex(PRNDCTX pCtx, uint32_t u32First, uint32_t u32Last) 361 { 362 if (u32First == 0 && u32Last == UINT32_MAX) 363 return RTPRandU32(pCtx); 364 365 uint32_t u32Tmp; 366 uint32_t u32Range = u32Last - u32First + 1; 367 uint32_t u32Scale = UINT32_MAX / u32Range; 368 369 do 370 { 371 u32Tmp = RTPRandU32(pCtx) / u32Scale; 372 } while (u32Tmp >= u32Range); 373 return u32First + u32Tmp; 374 } 375 376 /* End of IPRT code */ 377 378 struct Segment 379 { 380 uint64_t u64Offset; 381 uint32_t u32Length; 382 uint32_t u8Value; 383 }; 384 typedef struct Segment *PSEGMENT; 385 386 static void initializeRandomGenerator(PRNDCTX pCtx, const char *pszSeedInfo) 387 { 388 int rc = RTPRandInit(pCtx, pszSeedInfo); 389 if (VBOX_FAILURE(rc)) 390 { 391 RTPrintf("ERROR: Failed to initialize random generator. RC=%Vrc\n", rc); 392 } 393 else 394 { 395 char *pszNewSeedInfo = NULL; 396 rc = RTPRandGetSeedInfo(pCtx, &pszNewSeedInfo); 397 if (VBOX_FAILURE(rc)) 398 { 399 RTPrintf("ERROR: Failed to get seed values. RC=%Vrc\n", rc); 400 } 401 else 402 { 403 RTPrintf("INFO: Random generator seed used: %s\n", pszNewSeedInfo); 404 RTMemFree(pszNewSeedInfo); 405 } 406 } 407 408 } 409 410 static int compareSegments(const void *left, const void *right) 411 { 412 /* Note that no duplicates are allowed in the array being sorted. */ 413 return ((PSEGMENT)left)->u64Offset < ((PSEGMENT)right)->u64Offset ? -1 : 1; 414 } 415 416 static void generateRandomSegments(PRNDCTX pCtx, PSEGMENT pSegment, uint32_t nSegments, uint32_t u32MaxSegmentSize, uint64_t u64DiskSize, uint32_t u32SectorSize, uint8_t u8ValueLow, uint8_t u8ValueHigh) 417 { 418 uint32_t i; 419 /* Generate segment offsets. */ 420 for (i = 0; i < nSegments; i++) 421 { 422 bool fDuplicateFound = false; 423 do 424 { 425 pSegment[i].u64Offset = RTPRandU64Ex(pCtx, 0, u64DiskSize / u32SectorSize - 1) * u32SectorSize; 426 for (uint32_t j = 0; j < i; j++) 427 if (pSegment[i].u64Offset == pSegment[j].u64Offset) 428 fDuplicateFound = true; 429 } while (fDuplicateFound); 430 } 431 /* Sort in offset-ascending order. */ 432 qsort(pSegment, nSegments, sizeof(*pSegment), compareSegments); 433 /* Put a sentinel at the end. */ 434 pSegment[nSegments].u64Offset = u64DiskSize; 435 pSegment[nSegments].u32Length = 0; 436 /* Generate segment lengths and values. */ 437 for (i = 0; i < nSegments; i++) 438 { 439 pSegment[i].u32Length = RTPRandU32Ex(pCtx, 1, RT_MIN(pSegment[i+1].u64Offset - pSegment[i].u64Offset, 440 u32MaxSegmentSize) / u32SectorSize) * u32SectorSize; 441 pSegment[i].u8Value = RTPRandU32Ex(pCtx, (uint32_t)u8ValueLow, (uint32_t)u8ValueHigh); 442 } 443 } 444 445 static void mergeSegments(PSEGMENT pBaseSegment, PSEGMENT pDiffSegment, PSEGMENT pMergeSegment) 446 { 447 while (pBaseSegment->u32Length > 0 || pDiffSegment->u32Length > 0) 448 { 449 if (pBaseSegment->u64Offset < pDiffSegment->u64Offset) 450 { 451 *pMergeSegment = *pBaseSegment; 452 if (pMergeSegment->u64Offset + pMergeSegment->u32Length <= pDiffSegment->u64Offset) 453 pBaseSegment++; 454 else 455 { 456 pMergeSegment->u32Length = pDiffSegment->u64Offset - pMergeSegment->u64Offset; 457 if (pBaseSegment->u64Offset + pBaseSegment->u32Length > 458 pDiffSegment->u64Offset + pDiffSegment->u32Length) 459 { 460 pBaseSegment->u32Length -= pBaseSegment->u64Offset -pDiffSegment->u64Offset - pDiffSegment->u32Length; 461 pBaseSegment->u64Offset = pDiffSegment->u64Offset + pDiffSegment->u32Length; 462 } 463 else 464 pBaseSegment++; 465 } 466 pMergeSegment++; 467 } 468 else 469 { 470 *pMergeSegment = *pDiffSegment; 471 if (pMergeSegment->u64Offset + pMergeSegment->u32Length <= pBaseSegment->u64Offset) 472 { 473 pDiffSegment++; 474 pMergeSegment++; 475 } 476 else 477 { 478 if (pBaseSegment->u64Offset + pBaseSegment->u32Length > pDiffSegment->u64Offset + pDiffSegment->u32Length) 479 { 480 pBaseSegment->u32Length -= pDiffSegment->u64Offset + pDiffSegment->u32Length - pBaseSegment->u64Offset; 481 pBaseSegment->u64Offset = pDiffSegment->u64Offset + pDiffSegment->u32Length; 482 pDiffSegment++; 483 pMergeSegment++; 484 } 485 else 486 pBaseSegment++; 487 } 488 } 489 } 490 } 491 492 static void writeSegmentsToDisk(PVBOXHDD pVD, void *pvBuf, PSEGMENT pSegment) 493 { 494 while (pSegment->u32Length) 495 { 496 //memset((uint8_t*)pvBuf + pSegment->u64Offset, pSegment->u8Value, pSegment->u32Length); 497 memset(pvBuf, pSegment->u8Value, pSegment->u32Length); 498 VDWrite(pVD, pSegment->u64Offset, pvBuf, pSegment->u32Length); 499 pSegment++; 500 } 501 } 502 503 static int readAndCompareSegments(PVBOXHDD pVD, void *pvBuf, PSEGMENT pSegment) 504 { 505 while (pSegment->u32Length) 506 { 507 int rc = VDRead(pVD, pSegment->u64Offset, pvBuf, pSegment->u32Length); 508 if (VBOX_FAILURE(rc)) 509 { 510 RTPrintf("ERROR: Failed to read from virtual disk\n"); 511 return rc; 512 } 513 else 514 { 515 for (unsigned i = 0; i < pSegment->u32Length; i++) 516 if (((uint8_t*)pvBuf)[i] != pSegment->u8Value) 517 { 518 RTPrintf("ERROR: Segment at %Lx of %d bytes is corrupt at offset %x (found %x instead of %x)\n", 519 pSegment->u64Offset, pSegment->u32Length, i, ((uint8_t*)pvBuf)[i], 520 pSegment->u8Value); 521 return VERR_INTERNAL_ERROR; 522 } 523 } 524 pSegment++; 525 } 526 527 return VINF_SUCCESS; 528 } 529 530 static int tstVDOpenCreateWriteMerge(const char *pszBackend, 531 const char *pszBaseFilename, 532 const char *pszDiffFilename, 533 const char *pszSeedInfo) 180 534 { 181 535 int rc; 536 PVBOXHDD pVD = NULL; 537 char *pszFormat; 538 PDMMEDIAGEOMETRY PCHS = { 0, 0, 0 }; 539 PDMMEDIAGEOMETRY LCHS = { 0, 0, 0 }; 540 uint64_t u64DiskSize = 1000 * _1M; 541 uint32_t u32SectorSize = 512; 542 543 #define CHECK(str) \ 544 do \ 545 { \ 546 RTPrintf("%s rc=%Vrc\n", str, rc); \ 547 if (VBOX_FAILURE(rc)) \ 548 { \ 549 VDCloseAll(pVD); \ 550 return rc; \ 551 } \ 552 } while (0) 553 554 rc = VDCreate(tstVDError, NULL, &pVD); 555 CHECK("VDCreate()"); 556 557 RTFILE File; 558 rc = RTFileOpen(&File, pszBaseFilename, RTFILE_O_READ); 559 if (VBOX_SUCCESS(rc)) 560 { 561 RTFileClose(File); 562 rc = VDGetFormat(pszBaseFilename, &pszFormat); 563 RTPrintf("VDGetFormat() pszFormat=%s rc=%Vrc\n", pszFormat, rc); 564 if (VBOX_SUCCESS(rc) && strcmp(pszFormat, pszBackend)) 565 { 566 rc = VERR_GENERAL_FAILURE; 567 RTPrintf("VDGetFormat() returned incorrect backend name\n"); 568 } 569 RTStrFree(pszFormat); 570 CHECK("VDGetFormat()"); 571 572 rc = VDOpen(pVD, pszBackend, pszBaseFilename, VD_OPEN_FLAGS_NORMAL); 573 CHECK("VDOpen()"); 574 } 575 else 576 { 577 rc = VDCreateBase(pVD, pszBackend, pszBaseFilename, 578 VD_IMAGE_TYPE_NORMAL, u64DiskSize, 579 VD_IMAGE_FLAGS_NONE, "Test image", 580 &PCHS, &LCHS, VD_OPEN_FLAGS_NORMAL, 581 NULL, NULL); 582 CHECK("VDCreateBase()"); 583 } 584 585 int nSegments = 10; 586 /* Allocate one extra element for a sentinel. */ 587 PSEGMENT paBaseSegments = (PSEGMENT)RTMemAllocZ(sizeof(struct Segment) * (nSegments + 1)); 588 PSEGMENT paDiffSegments = (PSEGMENT)RTMemAllocZ(sizeof(struct Segment) * (nSegments + 1)); 589 PSEGMENT paMergeSegments = (PSEGMENT)RTMemAllocZ(sizeof(struct Segment) * (nSegments + 1) * 3); 590 591 void *pvBuf = RTMemAlloc(_1M); 592 593 RNDCTX ctx; 594 initializeRandomGenerator(&ctx, pszSeedInfo); 595 generateRandomSegments(&ctx, paBaseSegments, nSegments, _1M, u64DiskSize, u32SectorSize, 0u, 127u); 596 generateRandomSegments(&ctx, paDiffSegments, nSegments, _1M, u64DiskSize, u32SectorSize, 128u, 255u); 597 598 PSEGMENT pSegment; 599 /*RTPrintf("Base segments:\n"); 600 for (pSegment = paBaseSegments; pSegment->u32Length; pSegment++) 601 RTPrintf("off: %08Lx len: %04x val: %02x\n", pSegment->u64Offset, pSegment->u32Length, pSegment->u8Value);*/ 602 writeSegmentsToDisk(pVD, pvBuf, paBaseSegments); 603 604 rc = VDCreateDiff(pVD, pszBackend, pszDiffFilename, 605 VD_IMAGE_FLAGS_NONE, "Test diff image", 606 VD_OPEN_FLAGS_NORMAL, NULL, NULL); 607 CHECK("VDCreateDiff()"); 608 609 /*RTPrintf("\nDiff segments:\n"); 610 for (pSegment = paDiffSegments; pSegment->u32Length; pSegment++) 611 RTPrintf("off: %08Lx len: %04x val: %02x\n", pSegment->u64Offset, pSegment->u32Length, pSegment->u8Value);*/ 612 writeSegmentsToDisk(pVD, pvBuf, paDiffSegments); 613 614 VDDumpImages(pVD); 615 616 RTPrintf("Merging diff into base..\n"); 617 rc = VDMerge(pVD, -1, 0, NULL, NULL); 618 CHECK("VDMerge()"); 619 620 mergeSegments(paBaseSegments, paDiffSegments, paMergeSegments); 621 /*RTPrintf("\nMerged segments:\n"); 622 for (pSegment = paMergeSegments; pSegment->u32Length; pSegment++) 623 RTPrintf("off: %08Lx len: %04x val: %02x\n", pSegment->u64Offset, pSegment->u32Length, pSegment->u8Value);*/ 624 rc = readAndCompareSegments(pVD, pvBuf, paMergeSegments); 625 CHECK("readAndCompareSegments()"); 626 627 RTMemFree(paMergeSegments); 628 RTMemFree(paDiffSegments); 629 RTMemFree(paBaseSegments); 630 631 VDDumpImages(pVD); 632 633 VDCloseAll(pVD); 634 #undef CHECK 635 return 0; 636 } 637 #endif 638 639 int main(int argc, char *argv[]) 640 { 641 int rc; 642 643 const char *pszSeedInfo = NULL; 644 645 if (argc > 1) 646 pszSeedInfo = argv[1]; 182 647 183 648 RTR3Init(); … … 243 708 } 244 709 245 rc = tstVDOpenCreateWriteMerge("VDI", "tmpVDBase.vdi", "tmpVDDiff.vdi" );710 rc = tstVDOpenCreateWriteMerge("VDI", "tmpVDBase.vdi", "tmpVDDiff.vdi", pszSeedInfo); 246 711 if (VBOX_FAILURE(rc)) 247 712 { … … 249 714 g_cErrors++; 250 715 } 251 rc = tstVDOpenCreateWriteMerge("VDI", "tmpVDBase.vdi", "tmpVDDiff.vdi" );716 rc = tstVDOpenCreateWriteMerge("VDI", "tmpVDBase.vdi", "tmpVDDiff.vdi", pszSeedInfo); 252 717 if (VBOX_FAILURE(rc)) 253 718 { … … 255 720 g_cErrors++; 256 721 } 257 rc = tstVDOpenCreateWriteMerge("VMDK", "tmpVDBase.vmdk", "tmpVDDiff.vmdk" );722 rc = tstVDOpenCreateWriteMerge("VMDK", "tmpVDBase.vmdk", "tmpVDDiff.vmdk", pszSeedInfo); 258 723 if (VBOX_FAILURE(rc)) 259 724 { … … 261 726 g_cErrors++; 262 727 } 263 rc = tstVDOpenCreateWriteMerge("VMDK", "tmpVDBase.vmdk", "tmpVDDiff.vmdk" );728 rc = tstVDOpenCreateWriteMerge("VMDK", "tmpVDBase.vmdk", "tmpVDDiff.vmdk", pszSeedInfo); 264 729 if (VBOX_FAILURE(rc)) 265 730 { … … 277 742 RTFileDelete("tmpVDBase.vmdk"); 278 743 RTFileDelete("tmpVDDiff.vmdk"); 744 #if 0 745 rc = tstVDOpenCreateWriteMerge("VDI", "tmpVDBase.vdi", "tmpVDDiff.vdi", pszSeedInfo); 746 if (VBOX_FAILURE(rc)) 747 { 748 RTPrintf("tstVD: VHD test failed (existing image)! rc=%Vrc\n", rc); 749 g_cErrors++; 750 } 751 RTFileDelete("tmpVDBase.vdi"); 752 RTFileDelete("tmpVDDiff.vdi"); 753 //RTFileDelete("tmpVDDiff.vhd"); 754 #endif 279 755 280 756 /*
Note:
See TracChangeset
for help on using the changeset viewer.