Changeset 22792 in vbox
- Timestamp:
- Sep 4, 2009 6:38:32 PM (15 years ago)
- Location:
- trunk
- Files:
-
- 4 edited
-
include/VBox/err.h (modified) (2 diffs)
-
include/VBox/ssm.h (modified) (4 diffs)
-
src/VBox/VMM/SSM.cpp (modified) (14 diffs)
-
src/VBox/VMM/VM.cpp (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/err.h
r22609 r22792 567 567 /** Trying to read a 64-bit guest virtual address into a 32-bit variable. */ 568 568 #define VERR_SSM_GCPTR_OVERFLOW (-1850) 569 /** Vote for another pass. */ 570 #define VINF_SSM_VOTE_FOR_ANOTHER_PASS 1851 571 /** Vote for giving up. */ 572 #define VERR_SSM_VOTE_FOR_GIVING_UP (-1852) 569 573 /** @} */ 570 574 … … 1002 1006 #define VERR_PDM_DEVICE_NO_RT_ATTACH (-2853) 1003 1007 /** The driver doesn't support runtime driver attaching. 1004 * The PDMDRVREG::pfnAttach callback function is NULL. */ 1008 * The PDMDRVREG::pfnAttach callback function is NULL. */ 1005 1009 #define VERR_PDM_DRIVER_NO_RT_ATTACH (-2854) 1006 1010 /** Invalid host interface version. */ -
trunk/include/VBox/ssm.h
r22559 r22792 167 167 * being called every time. 168 168 * 169 * @returns true if done, false if there is more that needs to be saved first. 169 * @returns VBox status code. 170 * @retval VINF_SUCCESS if done. 171 * @retval VINF_SSM_VOTE_FOR_ANOTHER_PASS if another pass is needed. 172 * @retval VERR_SSM_VOTE_FOR_GIVING_UP if its time to give up. 173 * 170 174 * @param pDevIns Device instance of the device which registered the data unit. 171 175 * @param pSSM SSM operation handle. … … 288 292 * being called every time. 289 293 * 290 * @returns true if done, false if there is more that needs to be saved first. 294 * @returns VBox status code. 295 * @retval VINF_SUCCESS if done. 296 * @retval VINF_SSM_VOTE_FOR_ANOTHER_PASS if another pass is needed. 297 * @retval VERR_SSM_VOTE_FOR_GIVING_UP if its time to give up. 298 * 291 299 * @param pDrvIns Driver instance of the device which registered the 292 300 * data unit. … … 410 418 * being called every time. 411 419 * 412 * @returns true if done, false if there is more that needs to be saved first. 413 * @param pVM VM Handle. 414 * @param pSSM SSM operation handle. 415 * @thread Any. 416 */ 417 typedef DECLCALLBACK(bool) FNSSMINTLIVEVOTE(PVM pVM, PSSMHANDLE pSSM); 420 * @returns VBox status code. 421 * @retval VINF_SUCCESS if done. 422 * @retval VINF_SSM_VOTE_FOR_ANOTHER_PASS if another pass is needed. 423 * @retval VERR_SSM_VOTE_FOR_GIVING_UP if its time to give up. 424 * 425 * @param pVM VM Handle. 426 * @param pSSM SSM operation handle. 427 * @thread Any. 428 */ 429 typedef DECLCALLBACK(int) FNSSMINTLIVEVOTE(PVM pVM, PSSMHANDLE pSSM); 418 430 /** Pointer to a FNSSMINTLIVEVOTE() function. */ 419 431 typedef FNSSMINTLIVEVOTE *PFNSSMINTLIVEVOTE; … … 632 644 VMMR3DECL(int) SSMR3DeregisterExternal(PVM pVM, const char *pszName); 633 645 VMMR3DECL(int) SSMR3Save(PVM pVM, const char *pszFilename, SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvUser); 646 VMMR3DECL(int) SSMR3LiveToFile(PVM pVM, const char *pszFilename, SSMAFTER enmAfter, 647 PFNVMPROGRESS pfnProgress, void *pvUser, PSSMHANDLE *ppSSM); 648 VMMR3DECL(int) SSMR3LiveDoStep1(PSSMHANDLE pSSM); 649 VMMR3DECL(int) SSMR3LiveDoStep2(PSSMHANDLE pSSM); 650 VMMR3DECL(int) SSMR3LiveDone(PSSMHANDLE pSSM); 634 651 VMMR3DECL(int) SSMR3Load(PVM pVM, const char *pszFilename, SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvUser); 635 652 VMMR3DECL(int) SSMR3ValidateFile(const char *pszFilename, bool fChecksumIt); -
trunk/src/VBox/VMM/SSM.cpp
r22781 r22792 425 425 /** the amount of % we reserve for the 'done' stage */ 426 426 unsigned uPercentDone; 427 /** The filename, NULL if remote stream. */ 428 const char *pszFilename; 427 429 428 430 union … … 2575 2577 int rc = ssmR3DataFlushBuffer(pSSM); 2576 2578 if (RT_SUCCESS(rc)) 2579 { 2580 pSSM->offUnit = UINT64_MAX; 2577 2581 return VINF_SUCCESS; 2582 } 2578 2583 2579 2584 if (RT_SUCCESS(pSSM->rc)) … … 3282 3287 3283 3288 /** 3289 * Worker for SSMR3LiveDone and SSMR3Save that closes the handle and deletes the 3290 * saved state file on failure. 3291 * 3292 * @returns VBox status code (pSSM->rc). 3293 * @param pVM The VM handle. 3294 * @param pSSM The saved state handle. 3295 */ 3296 static int ssmR3SaveDoClose(PVM pVM, PSSMHANDLE pSSM) 3297 { 3298 VM_ASSERT_EMT0(pVM); 3299 3300 /* 3301 * Close the stream and delete the file on failure. 3302 */ 3303 int rc = ssmR3StrmClose(&pSSM->Strm); 3304 if (RT_SUCCESS(rc)) 3305 rc = pSSM->rc; 3306 if (RT_SUCCESS(rc)) 3307 { 3308 if (pSSM->pfnProgress) 3309 pSSM->pfnProgress(pVM, 100, pSSM->pvUser); 3310 LogRel(("SSM: Successfully saved the VM state to '%s'\n", 3311 pSSM->pszFilename ? pSSM->pszFilename : "<remote-machine>")); 3312 } 3313 else 3314 { 3315 if (pSSM->pszFilename) 3316 { 3317 int rc2 = RTFileDelete(pSSM->pszFilename); 3318 AssertRC(rc2); 3319 if (RT_SUCCESS(rc2)) 3320 LogRel(("SSM: Failed to save the VM state to '%s' (file deleted): %Rrc\n", 3321 pSSM->pszFilename, rc)); 3322 else 3323 LogRel(("SSM: Failed to save the VM state to '%s' (file deletion failed, rc2=%Rrc): %Rrc\n", 3324 pSSM->pszFilename, rc2, rc)); 3325 } 3326 else 3327 LogRel(("SSM: Failed to save the VM state.\n")); 3328 } 3329 3330 /* 3331 * Trash the handle before freeing it. 3332 */ 3333 pSSM->pVM = NULL; 3334 pSSM->enmAfter = SSMAFTER_INVALID; 3335 pSSM->enmOp = SSMSTATE_INVALID; 3336 RTMemFree(pSSM); 3337 3338 return rc; 3339 } 3340 3341 3342 /** 3343 * Closes the SSM handle. 3344 * 3345 * This must always be called on a handled returned by SSMR3LiveToFile or 3346 * SSMR3LiveToRemote. 3347 * 3348 * @returns VBox status. 3349 * 3350 * @param pSSM The SSM handle returned by SSMR3LiveToFile or 3351 * SSMR3LiveToRemote. 3352 * 3353 * @thread EMT(0). 3354 */ 3355 VMMR3DECL(int) SSMR3LiveDone(PSSMHANDLE pSSM) 3356 { 3357 LogFlow(("SSMR3LiveDone: pSSM=%p\n", pSSM)); 3358 3359 /* 3360 * Validate input. 3361 */ 3362 AssertPtrReturn(pSSM, VERR_INVALID_POINTER); 3363 PVM pVM = pSSM->pVM; 3364 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); 3365 VM_ASSERT_EMT0(pVM); 3366 AssertMsgReturn( pSSM->enmAfter == SSMAFTER_DESTROY 3367 || pSSM->enmAfter == SSMAFTER_CONTINUE, 3368 ("%d\n", pSSM->enmAfter), 3369 VERR_INVALID_PARAMETER); 3370 AssertMsgReturn( pSSM->enmOp >= SSMSTATE_LIVE_PREP 3371 && pSSM->enmOp <= SSMSTATE_SAVE_DONE, 3372 ("%d\n", pSSM->enmOp), VERR_INVALID_STATE); 3373 3374 /* 3375 * Join paths with SSMR3Save again. 3376 */ 3377 return ssmR3SaveDoClose(pVM, pSSM); 3378 } 3379 3380 3381 /** 3382 * Do the pfnSaveDone run. 3383 * 3384 * @returns VBox status code (pSSM->rc). 3385 * @param pVM The VM handle. 3386 * @param pSSM The saved state handle. 3387 */ 3388 static int ssmR3SaveDoDoneRun(PVM pVM, PSSMHANDLE pSSM) 3389 { 3390 VM_ASSERT_EMT0(pVM); 3391 3392 /* 3393 * Do the done run. 3394 */ 3395 pSSM->enmOp = SSMSTATE_SAVE_DONE; 3396 for (PSSMUNIT pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext) 3397 { 3398 if ( pUnit->u.Common.pfnSaveDone 3399 && ( pUnit->fCalled 3400 || (!pUnit->u.Common.pfnSavePrep && !pUnit->u.Common.pfnSaveExec))) 3401 { 3402 int rcOld = pSSM->rc; 3403 int rc; 3404 switch (pUnit->enmType) 3405 { 3406 case SSMUNITTYPE_DEV: 3407 rc = pUnit->u.Dev.pfnSaveDone(pUnit->u.Dev.pDevIns, pSSM); 3408 break; 3409 case SSMUNITTYPE_DRV: 3410 rc = pUnit->u.Drv.pfnSaveDone(pUnit->u.Drv.pDrvIns, pSSM); 3411 break; 3412 case SSMUNITTYPE_INTERNAL: 3413 rc = pUnit->u.Internal.pfnSaveDone(pVM, pSSM); 3414 break; 3415 case SSMUNITTYPE_EXTERNAL: 3416 rc = pUnit->u.External.pfnSaveDone(pSSM, pUnit->u.External.pvUser); 3417 break; 3418 default: 3419 rc = VERR_INTERNAL_ERROR; 3420 break; 3421 } 3422 if (RT_SUCCESS(rc) && pSSM->rc != rcOld) 3423 rc = pSSM->rc; 3424 if (RT_FAILURE(rc)) 3425 { 3426 LogRel(("SSM: Done save failed with rc=%Rrc for data unit '%s.\n", rc, pUnit->szName)); 3427 if (RT_SUCCESS(pSSM->rc)) 3428 pSSM->rc = rc; 3429 } 3430 } 3431 } 3432 return pSSM->rc; 3433 } 3434 3435 3436 /** 3284 3437 * Writes the directory. 3285 3438 * … … 3291 3444 static int ssmR3WriteDirectory(PVM pVM, PSSMHANDLE pSSM, uint32_t *pcEntries) 3292 3445 { 3446 VM_ASSERT_EMT0(pVM); 3447 3293 3448 /* 3294 3449 * Grab some temporary memory for the dictionary. … … 3333 3488 3334 3489 /** 3490 * Finalize the saved state stream, i.e. add the end unit, directory 3491 * and footer. 3492 * 3493 * @returns VBox status code (pSSM->rc). 3494 * @param pVM The VM handle. 3495 * @param pSSM The saved state handle. 3496 */ 3497 static int ssmR3SaveDoFinalization(PVM pVM, PSSMHANDLE pSSM) 3498 { 3499 VM_ASSERT_EMT0(pVM); 3500 Assert(RT_SUCCESS(pSSM->rc)); 3501 3502 /* 3503 * Write the end unit. 3504 */ 3505 SSMFILEUNITHDRV2 UnitHdr; 3506 memcpy(&UnitHdr.szMagic[0], SSMFILEUNITHDR_END, sizeof(UnitHdr.szMagic)); 3507 UnitHdr.offStream = ssmR3StrmTell(&pSSM->Strm); 3508 UnitHdr.u32CurStreamCRC = ssmR3StrmCurCRC(&pSSM->Strm); 3509 UnitHdr.u32CRC = 0; 3510 UnitHdr.u32Version = 0; 3511 UnitHdr.u32Instance = 0; 3512 UnitHdr.u32Phase = SSM_PHASE_FINAL; 3513 UnitHdr.fFlags = 0; 3514 UnitHdr.cbName = 0; 3515 UnitHdr.u32CRC = RTCrc32(&UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV2, szName[0])); 3516 Log(("SSM: Unit at %#9llx: END UNIT\n", UnitHdr.offStream)); 3517 int rc = ssmR3StrmWrite(&pSSM->Strm, &UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV2, szName[0])); 3518 if (RT_FAILURE(rc)) 3519 { 3520 LogRel(("SSM: Failed writing the end unit: %Rrc\n", rc)); 3521 return pSSM->rc = rc; 3522 } 3523 3524 /* 3525 * Write the directory for the final units and then the footer. 3526 */ 3527 SSMFILEFTR Footer; 3528 rc = ssmR3WriteDirectory(pVM, pSSM, &Footer.cDirEntries); 3529 if (RT_FAILURE(rc)) 3530 { 3531 LogRel(("SSM: Failed writing the directory: %Rrc\n", rc)); 3532 return pSSM->rc = rc; 3533 } 3534 3535 memcpy(Footer.szMagic, SSMFILEFTR_MAGIC, sizeof(Footer.szMagic)); 3536 Footer.offStream = ssmR3StrmTell(&pSSM->Strm); 3537 Footer.u32StreamCRC = ssmR3StrmFinalCRC(&pSSM->Strm); 3538 Footer.u32Reserved = 0; 3539 Footer.u32CRC = 0; 3540 Footer.u32CRC = RTCrc32(&Footer, sizeof(Footer)); 3541 Log(("SSM: Footer at %#9llx: \n", Footer.offStream)); 3542 rc = ssmR3StrmWrite(&pSSM->Strm, &Footer, sizeof(Footer)); 3543 if (RT_SUCCESS(rc)) 3544 rc = ssmR3StrmSetEnd(&pSSM->Strm); 3545 if (RT_FAILURE(rc)) 3546 { 3547 LogRel(("SSM: Failed writing the footer: %Rrc\n", rc)); 3548 return pSSM->rc = rc; 3549 } 3550 3551 LogRel(("SSM: Footer at %#llx (%lld), %u directory entries.\n", 3552 Footer.offStream, Footer.offStream, Footer.cDirEntries)); 3553 return VINF_SUCCESS; 3554 } 3555 3556 3557 /** 3558 * Do the pfnSaveExec run. 3559 * 3560 * @returns VBox status code (pSSM->rc). 3561 * @param pVM The VM handle. 3562 * @param pSSM The saved state handle. 3563 */ 3564 static int ssmR3SaveDoExecRun(PVM pVM, PSSMHANDLE pSSM) 3565 { 3566 VM_ASSERT_EMT0(pVM); 3567 Assert(RT_SUCCESS(pSSM->rc)); 3568 3569 pSSM->enmOp = SSMSTATE_SAVE_EXEC; 3570 for (PSSMUNIT pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext) 3571 { 3572 /* 3573 * Not all unit have a callback. Skip those which don't and 3574 * make sure to keep the progress indicator up to date. 3575 */ 3576 pSSM->offEstUnitEnd += pUnit->cbGuess; 3577 if (!pUnit->u.Common.pfnSaveExec) 3578 { 3579 pUnit->fCalled = true; 3580 if (pUnit->cbGuess) 3581 ssmR3Progress(pSSM, pSSM->offEstUnitEnd - pSSM->offEst); 3582 continue; 3583 } 3584 pUnit->offStream = ssmR3StrmTell(&pSSM->Strm); 3585 3586 /* 3587 * Write data unit header 3588 */ 3589 SSMFILEUNITHDRV2 UnitHdr; 3590 memcpy(&UnitHdr.szMagic[0], SSMFILEUNITHDR_MAGIC, sizeof(UnitHdr.szMagic)); 3591 UnitHdr.offStream = pUnit->offStream; 3592 UnitHdr.u32CurStreamCRC = ssmR3StrmCurCRC(&pSSM->Strm); 3593 UnitHdr.u32CRC = 0; 3594 UnitHdr.u32Version = pUnit->u32Version; 3595 UnitHdr.u32Instance = pUnit->u32Instance; 3596 UnitHdr.u32Phase = SSM_PHASE_FINAL; 3597 UnitHdr.fFlags = 0; 3598 UnitHdr.cbName = (uint32_t)pUnit->cchName + 1; 3599 memcpy(&UnitHdr.szName[0], &pUnit->szName[0], UnitHdr.cbName); 3600 UnitHdr.u32CRC = RTCrc32(&UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV2, szName[UnitHdr.cbName])); 3601 Log(("SSM: Unit at %#9llx: '%s', instance %u, phase %#x, version %u\n", 3602 UnitHdr.offStream, UnitHdr.szName, UnitHdr.u32Instance, UnitHdr.u32Phase, UnitHdr.u32Version)); 3603 int rc = ssmR3StrmWrite(&pSSM->Strm, &UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV2, szName[UnitHdr.cbName])); 3604 if (RT_FAILURE(rc)) 3605 { 3606 LogRel(("SSM: Failed to write unit header. rc=%Rrc\n", rc)); 3607 return pSSM->rc = rc; 3608 } 3609 3610 /* 3611 * Call the execute handler. 3612 */ 3613 ssmR3DataWriteBegin(pSSM); 3614 switch (pUnit->enmType) 3615 { 3616 case SSMUNITTYPE_DEV: 3617 rc = pUnit->u.Dev.pfnSaveExec(pUnit->u.Dev.pDevIns, pSSM); 3618 break; 3619 case SSMUNITTYPE_DRV: 3620 rc = pUnit->u.Drv.pfnSaveExec(pUnit->u.Drv.pDrvIns, pSSM); 3621 break; 3622 case SSMUNITTYPE_INTERNAL: 3623 rc = pUnit->u.Internal.pfnSaveExec(pVM, pSSM); 3624 break; 3625 case SSMUNITTYPE_EXTERNAL: 3626 pUnit->u.External.pfnSaveExec(pSSM, pUnit->u.External.pvUser); 3627 rc = pSSM->rc; 3628 break; 3629 default: 3630 rc = VERR_INTERNAL_ERROR; 3631 break; 3632 } 3633 pUnit->fCalled = true; 3634 if (RT_SUCCESS(rc)) 3635 rc = ssmR3DataFlushBuffer(pSSM); /* will return SSMHANDLE::rc if it is set */ 3636 if (RT_FAILURE(rc)) 3637 { 3638 LogRel(("SSM: Execute save failed with rc=%Rrc for data unit '%s'/#%u.\n", rc, pUnit->szName, pUnit->u32Instance)); 3639 if (RT_SUCCESS(pSSM->rc)) 3640 pSSM->rc = rc; 3641 return rc; 3642 } 3643 3644 /* 3645 * Write the termination record and flush the compression stream. 3646 */ 3647 SSMRECTERM TermRec; 3648 TermRec.u8TypeAndFlags = SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_TERM; 3649 TermRec.cbRec = sizeof(TermRec) - 2; 3650 if (pSSM->Strm.fChecksummed) 3651 { 3652 TermRec.fFlags = SSMRECTERM_FLAGS_CRC32; 3653 TermRec.u32StreamCRC = RTCrc32Finish(RTCrc32Process(ssmR3StrmCurCRC(&pSSM->Strm), &TermRec, 2)); 3654 } 3655 else 3656 { 3657 TermRec.fFlags = 0; 3658 TermRec.u32StreamCRC = 0; 3659 } 3660 TermRec.cbUnit = pSSM->offUnit + sizeof(TermRec); 3661 rc = ssmR3DataWriteRaw(pSSM, &TermRec, sizeof(TermRec)); 3662 if (RT_SUCCESS(rc)) 3663 rc = ssmR3DataWriteFinish(pSSM); 3664 if (RT_FAILURE(rc)) 3665 { 3666 LogRel(("SSM: Failed ending compression stream. rc=%Rrc\n", rc)); 3667 return pSSM->rc = rc; 3668 } 3669 3670 /* 3671 * Advance the progress indicator to the end of the current unit. 3672 */ 3673 ssmR3Progress(pSSM, pSSM->offEstUnitEnd - pSSM->offEst); 3674 } /* for each unit */ 3675 3676 3677 /* (progress should be pending 99% now) */ 3678 AssertMsg(pSSM->uPercent == (101 - pSSM->uPercentDone), ("%d\n", pSSM->uPercent)); 3679 return VINF_SUCCESS; 3680 } 3681 3682 3683 /** 3684 * Do the pfnSavePrep run. 3685 * 3686 * @returns VBox status code (pSSM->rc). 3687 * @param pVM The VM handle. 3688 * @param pSSM The saved state handle. 3689 */ 3690 static int ssmR3SaveDoPrepRun(PVM pVM, PSSMHANDLE pSSM) 3691 { 3692 VM_ASSERT_EMT0(pVM); 3693 Assert(RT_SUCCESS(pSSM->rc)); 3694 3695 /* 3696 * Do the prepare run. 3697 */ 3698 pSSM->enmOp = SSMSTATE_SAVE_PREP; 3699 for (PSSMUNIT pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext) 3700 { 3701 if (pUnit->u.Common.pfnSavePrep) 3702 { 3703 int rc; 3704 switch (pUnit->enmType) 3705 { 3706 case SSMUNITTYPE_DEV: 3707 rc = pUnit->u.Dev.pfnSavePrep(pUnit->u.Dev.pDevIns, pSSM); 3708 break; 3709 case SSMUNITTYPE_DRV: 3710 rc = pUnit->u.Drv.pfnSavePrep(pUnit->u.Drv.pDrvIns, pSSM); 3711 break; 3712 case SSMUNITTYPE_INTERNAL: 3713 rc = pUnit->u.Internal.pfnSavePrep(pVM, pSSM); 3714 break; 3715 case SSMUNITTYPE_EXTERNAL: 3716 rc = pUnit->u.External.pfnSavePrep(pSSM, pUnit->u.External.pvUser); 3717 break; 3718 default: 3719 rc = VERR_INTERNAL_ERROR; 3720 break; 3721 } 3722 pUnit->fCalled = true; 3723 if (RT_SUCCESS(rc)) 3724 rc = pSSM->rc; 3725 if (RT_FAILURE(rc)) 3726 { 3727 LogRel(("SSM: Prepare save failed with rc=%Rrc for data unit '%s.\n", rc, pUnit->szName)); 3728 if (RT_SUCCESS(pSSM->rc)) 3729 pSSM->rc = rc; 3730 return rc; 3731 } 3732 } 3733 3734 pSSM->cbEstTotal += pUnit->cbGuess; 3735 } 3736 3737 /* 3738 * Work the progress indicator if we got one. 3739 */ 3740 if (pSSM->pfnProgress) 3741 pSSM->pfnProgress(pVM, pSSM->uPercentPrepare-1, pSSM->pvUser); 3742 pSSM->uPercent = pSSM->uPercentPrepare; 3743 3744 return VINF_SUCCESS; 3745 } 3746 3747 3748 /** 3749 * Common worker for SSMR3Save and SSMR3Migrate. 3750 * 3751 * @returns VBox status code (no need to check pSSM->rc). 3752 * @param pVM The VM handle. 3753 * @param pSSM The state handle. 3754 * 3755 * @thread EMT(0) 3756 */ 3757 static int ssmR3SaveDoCommon(PVM pVM, PSSMHANDLE pSSM) 3758 { 3759 VM_ASSERT_EMT0(pVM); 3760 3761 /* 3762 * Do the work. 3763 */ 3764 int rc = ssmR3SaveDoPrepRun(pVM, pSSM); 3765 if (RT_SUCCESS(rc)) 3766 { 3767 rc = ssmR3SaveDoExecRun(pVM, pSSM); 3768 if (RT_SUCCESS(rc)) 3769 rc = ssmR3SaveDoFinalization(pVM, pSSM); 3770 } 3771 Assert(pSSM->rc == rc); 3772 int rc2 = ssmR3SaveDoDoneRun(pVM, pSSM); 3773 if (RT_SUCCESS(rc)) 3774 rc = rc2; 3775 3776 return rc; 3777 } 3778 3779 3780 /** 3781 * Saves the rest of the state on EMT0. 3782 * 3783 * @returns VBox status. 3784 * 3785 * @param pSSM The SSM handle returned by SSMR3LiveToFile or 3786 * SSMR3LiveToRemote. 3787 * 3788 * @thread Non-EMT thread. Will involve the EMT at the end of the operation. 3789 */ 3790 VMMR3DECL(int) SSMR3LiveDoStep2(PSSMHANDLE pSSM) 3791 { 3792 LogFlow(("SSMR3LiveDoStep2: pSSM=%p\n", pSSM)); 3793 3794 /* 3795 * Validate input. 3796 */ 3797 AssertPtrReturn(pSSM, VERR_INVALID_POINTER); 3798 PVM pVM = pSSM->pVM; 3799 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); 3800 VM_ASSERT_EMT0(pVM); 3801 AssertMsgReturn( pSSM->enmAfter == SSMAFTER_DESTROY 3802 || pSSM->enmAfter == SSMAFTER_CONTINUE, 3803 ("%d\n", pSSM->enmAfter), 3804 VERR_INVALID_PARAMETER); 3805 AssertMsgReturn(pSSM->enmOp == SSMSTATE_SAVE_PREP, ("%d\n", pSSM->enmOp), VERR_INVALID_STATE); 3806 3807 /* 3808 * Join paths with VMMR3Save. 3809 */ 3810 return ssmR3SaveDoCommon(pVM, pSSM); 3811 } 3812 3813 3814 /** 3815 * Writes the file header and clear the per-unit data. 3816 * 3817 * @returns VBox status code. 3818 * @param pVM The VM handle. 3819 * @param pSSM The SSM handle. 3820 */ 3821 static int ssmR3WriteHeaderAndClearPerUnitData(PVM pVM, PSSMHANDLE pSSM) 3822 { 3823 /* 3824 * Write the header. 3825 */ 3826 SSMFILEHDR FileHdr; 3827 memcpy(&FileHdr.szMagic, SSMFILEHDR_MAGIC_V2_0, sizeof(FileHdr.szMagic)); 3828 FileHdr.u16VerMajor = VBOX_VERSION_MAJOR; 3829 FileHdr.u16VerMinor = VBOX_VERSION_MINOR; 3830 FileHdr.u32VerBuild = VBOX_VERSION_BUILD; 3831 FileHdr.u32SvnRev = VMMGetSvnRev(), 3832 FileHdr.cHostBits = HC_ARCH_BITS; 3833 FileHdr.cbGCPhys = sizeof(RTGCPHYS); 3834 FileHdr.cbGCPtr = sizeof(RTGCPTR); 3835 FileHdr.u8Reserved = 0; 3836 FileHdr.cUnits = pVM->ssm.s.cUnits; 3837 FileHdr.fFlags = SSMFILEHDR_FLAGS_STREAM_CRC32; 3838 FileHdr.cbMaxDecompr = RT_SIZEOFMEMB(SSMHANDLE, u.Read.abDataBuffer); 3839 FileHdr.u32CRC = 0; 3840 FileHdr.u32CRC = RTCrc32(&FileHdr, sizeof(FileHdr)); 3841 int rc = ssmR3StrmWrite(&pSSM->Strm, &FileHdr, sizeof(FileHdr)); 3842 if (RT_SUCCESS(rc)) 3843 return rc; 3844 3845 /* 3846 * Clear the per unit flags and offsets. 3847 */ 3848 for (PSSMUNIT pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext) 3849 { 3850 pUnit->fCalled = false; 3851 pUnit->offStream = RTFOFF_MIN; 3852 } 3853 3854 return VINF_SUCCESS; 3855 } 3856 3857 3858 /** 3859 * Creates a new saved state file. 3860 * 3861 * @returns VBox status code. 3862 * @param pVM The VM handle. 3863 * @param pszFilename The name of the file. 3864 * @param enmAfter What to do afterwards. 3865 * @param pfnProgress The progress callback. 3866 * @param pvUser The progress callback user argument. 3867 * @param ppSSM Where to return the pointer to the saved state 3868 * handle upon successful return. Free it using 3869 * RTMemFree after closing the stream. 3870 */ 3871 static int ssmR3SaveDoCreateFile(PVM pVM, const char *pszFilename, SSMAFTER enmAfter, 3872 PFNVMPROGRESS pfnProgress, void *pvUser, PSSMHANDLE *ppSSM) 3873 { 3874 PSSMHANDLE pSSM = (PSSMHANDLE)RTMemAllocZ(sizeof(*pSSM)); 3875 if (!pSSM) 3876 return VERR_NO_MEMORY; 3877 3878 pSSM->pVM = pVM; 3879 pSSM->enmOp = SSMSTATE_INVALID; 3880 pSSM->enmAfter = enmAfter; 3881 pSSM->rc = VINF_SUCCESS; 3882 pSSM->cbUnitLeftV1 = 0; 3883 pSSM->offUnit = UINT64_MAX; 3884 pSSM->pfnProgress = pfnProgress; 3885 pSSM->pvUser = pvUser; 3886 pSSM->uPercent = 0; 3887 pSSM->offEstProgress = 0; 3888 pSSM->cbEstTotal = 0; 3889 pSSM->offEst = 0; 3890 pSSM->offEstUnitEnd = 0; 3891 pSSM->uPercentPrepare = 0; 3892 pSSM->uPercentDone = 0; 3893 pSSM->pszFilename = pszFilename; 3894 pSSM->u.Write.offDataBuffer = 0; 3895 3896 int rc = ssmR3StrmOpenFile(&pSSM->Strm, pszFilename, true /*fWrite*/, true /*fChecksummed*/, 8 /*cBuffers*/); 3897 if (RT_FAILURE(rc)) 3898 { 3899 LogRel(("SSM: Failed to create save state file '%s', rc=%Rrc.\n", pszFilename, rc)); 3900 RTMemFree(pSSM); 3901 return rc; 3902 } 3903 3904 *ppSSM = pSSM; 3905 return VINF_SUCCESS; 3906 } 3907 3908 3909 /** 3335 3910 * Start VM save operation. 3336 3911 * … … 3348 3923 { 3349 3924 LogFlow(("SSMR3Save: pszFilename=%p:{%s} enmAfter=%d pfnProgress=%p pvUser=%p\n", pszFilename, pszFilename, enmAfter, pfnProgress, pvUser)); 3350 VM_ASSERT_EMT (pVM);3925 VM_ASSERT_EMT0(pVM); 3351 3926 3352 3927 /* … … 3354 3929 */ 3355 3930 AssertMsgReturn( enmAfter == SSMAFTER_DESTROY 3356 || enmAfter == SSMAFTER_CONTINUE 3357 || enmAfter == SSMAFTER_MIGRATE, 3931 || enmAfter == SSMAFTER_CONTINUE, 3358 3932 ("%d\n", enmAfter), 3359 3933 VERR_INVALID_PARAMETER); 3360 3934 3361 3935 /* 3362 * Create the handle and try open the file.3936 * Create the saved state file and handle. 3363 3937 * 3364 3938 * Note that there might be quite some work to do after executing the saving, 3365 * so we reserve 20% for the 'Done' period. The checksumming and closing of 3366 * the saved state file might take a long time. 3367 */ 3368 SSMHANDLE Handle; 3369 RT_ZERO(Handle); 3370 Handle.pVM = pVM; 3371 Handle.enmOp = SSMSTATE_INVALID; 3372 Handle.enmAfter = enmAfter; 3373 Handle.rc = VINF_SUCCESS; 3374 Handle.cbUnitLeftV1 = 0; 3375 Handle.offUnit = UINT64_MAX; 3376 Handle.pfnProgress = pfnProgress; 3377 Handle.pvUser = pvUser; 3378 Handle.uPercent = 0; 3379 Handle.offEstProgress = 0; 3380 Handle.cbEstTotal = 0; 3381 Handle.offEst = 0; 3382 Handle.offEstUnitEnd = 0; 3383 Handle.uPercentPrepare = 20; 3384 Handle.uPercentDone = 2; 3385 Handle.u.Write.offDataBuffer = 0; 3386 3387 int rc = ssmR3StrmOpenFile(&Handle.Strm, pszFilename, true /*fWrite*/, true /*fChecksummed*/, 8 /*cBuffers*/); 3939 * so we reserve 20% for the 'Done' period. 3940 */ 3941 PSSMHANDLE pSSM; 3942 int rc = ssmR3SaveDoCreateFile(pVM, pszFilename, enmAfter, pfnProgress, pvUser, &pSSM); 3388 3943 if (RT_FAILURE(rc)) 3389 {3390 LogRel(("SSM: Failed to create save state file '%s', rc=%Rrc.\n", pszFilename, rc));3391 3944 return rc; 3392 } 3393 3945 pSSM->uPercentPrepare = 20; 3946 pSSM->uPercentDone = 2; 3947 3948 /* 3949 * Write the saved state stream header and join paths with 3950 * the other save methods for the rest of the job. 3951 */ 3394 3952 Log(("SSM: Starting state save to file '%s'...\n", pszFilename)); 3395 ssmR3StrmStartIoThread(&Handle.Strm); 3396 3397 /* 3398 * Write header. 3399 */ 3400 union 3401 { 3402 SSMFILEHDR FileHdr; 3403 SSMFILEUNITHDRV2 UnitHdr; 3404 SSMFILEFTR Footer; 3405 } u; 3406 3407 memcpy(&u.FileHdr.szMagic, SSMFILEHDR_MAGIC_V2_0, sizeof(u.FileHdr.szMagic)); 3408 u.FileHdr.u16VerMajor = VBOX_VERSION_MAJOR; 3409 u.FileHdr.u16VerMinor = VBOX_VERSION_MINOR; 3410 u.FileHdr.u32VerBuild = VBOX_VERSION_BUILD; 3411 u.FileHdr.u32SvnRev = VMMGetSvnRev(), 3412 u.FileHdr.cHostBits = HC_ARCH_BITS; 3413 u.FileHdr.cbGCPhys = sizeof(RTGCPHYS); 3414 u.FileHdr.cbGCPtr = sizeof(RTGCPTR); 3415 u.FileHdr.u8Reserved = 0; 3416 u.FileHdr.cUnits = pVM->ssm.s.cUnits; 3417 u.FileHdr.fFlags = SSMFILEHDR_FLAGS_STREAM_CRC32; 3418 u.FileHdr.cbMaxDecompr = RT_SIZEOFMEMB(SSMHANDLE, u.Read.abDataBuffer); 3419 u.FileHdr.u32CRC = 0; 3420 u.FileHdr.u32CRC = RTCrc32(&u.FileHdr, sizeof(u.FileHdr)); 3421 rc = ssmR3StrmWrite(&Handle.Strm, &u.FileHdr, sizeof(u.FileHdr)); 3953 ssmR3StrmStartIoThread(&pSSM->Strm); 3954 rc = ssmR3WriteHeaderAndClearPerUnitData(pVM, pSSM); 3422 3955 if (RT_SUCCESS(rc)) 3423 { 3424 /* 3425 * Clear the per unit flags and offsets. 3426 */ 3427 PSSMUNIT pUnit; 3428 for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext) 3429 { 3430 pUnit->fCalled = false; 3431 pUnit->offStream = RTFOFF_MIN; 3432 } 3433 3434 /* 3435 * Do the prepare run. 3436 */ 3437 Handle.rc = VINF_SUCCESS; 3438 Handle.enmOp = SSMSTATE_SAVE_PREP; 3439 for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext) 3440 { 3441 if (pUnit->u.Common.pfnSavePrep) 3956 ssmR3SaveDoCommon(pVM, pSSM); 3957 return ssmR3SaveDoClose(pVM, pSSM); 3958 } 3959 3960 3961 /** 3962 * Calls pfnLiveVote for all units. 3963 * 3964 * @returns VBox status code (no need to check pSSM->rc). 3965 * @param pVM The VM handle. 3966 * @param pSSM The saved state handle. 3967 */ 3968 static int ssmR3DoLiveVoteRun(PVM pVM, PSSMHANDLE pSSM) 3969 { 3970 /* 3971 * Do the prepare run. 3972 */ 3973 AssertRCReturn(pSSM->rc, pSSM->rc); 3974 pSSM->rc = VINF_SUCCESS; 3975 pSSM->enmOp = SSMSTATE_LIVE_VOTE; 3976 for (PSSMUNIT pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext) 3977 { 3978 if (pUnit->u.Common.pfnLiveVote) 3979 { 3980 int rc; 3981 switch (pUnit->enmType) 3442 3982 { 3443 switch (pUnit->enmType) 3983 case SSMUNITTYPE_DEV: 3984 rc = pUnit->u.Dev.pfnLiveVote(pUnit->u.Dev.pDevIns, pSSM); 3985 break; 3986 case SSMUNITTYPE_DRV: 3987 rc = pUnit->u.Drv.pfnLiveVote(pUnit->u.Drv.pDrvIns, pSSM); 3988 break; 3989 case SSMUNITTYPE_INTERNAL: 3990 rc = pUnit->u.Internal.pfnLiveVote(pVM, pSSM); 3991 break; 3992 case SSMUNITTYPE_EXTERNAL: 3993 rc = pUnit->u.External.pfnLiveVote(pSSM, pUnit->u.External.pvUser); 3994 break; 3995 default: 3996 rc = VERR_INTERNAL_ERROR; 3997 break; 3998 } 3999 Assert(pSSM->rc == VINF_SUCCESS); 4000 4001 pUnit->fCalled = true; 4002 if (rc != VINF_SUCCESS) 4003 { 4004 if (rc == VINF_SSM_VOTE_FOR_ANOTHER_PASS) 3444 4005 { 3445 case SSMUNITTYPE_DEV: 3446 rc = pUnit->u.Dev.pfnSavePrep(pUnit->u.Dev.pDevIns, &Handle); 3447 break; 3448 case SSMUNITTYPE_DRV: 3449 rc = pUnit->u.Drv.pfnSavePrep(pUnit->u.Drv.pDrvIns, &Handle); 3450 break; 3451 case SSMUNITTYPE_INTERNAL: 3452 rc = pUnit->u.Internal.pfnSavePrep(pVM, &Handle); 3453 break; 3454 case SSMUNITTYPE_EXTERNAL: 3455 rc = pUnit->u.External.pfnSavePrep(&Handle, pUnit->u.External.pvUser); 3456 break; 4006 Log(("ssmR3DoLiveVoteRun: '%s'/#%u -> VINF_SSM_VOTE_FOR_ANOTHER_PASS\n", pUnit, pUnit->u32Instance)); 4007 return VINF_SSM_VOTE_FOR_ANOTHER_PASS; 3457 4008 } 3458 pUnit->fCalled = true; 3459 if (RT_FAILURE(rc)) 3460 { 3461 LogRel(("SSM: Prepare save failed with rc=%Rrc for data unit '%s.\n", rc, pUnit->szName)); 4009 Log(("ssmR3DoLiveVoteRun: '%s'/#%u -> %Rrc!!\n", pUnit, pUnit->u32Instance, rc)); 4010 AssertMsgReturn(RT_FAILURE(rc), ("%Rrc; '%s'\n", rc, pUnit->szName), pSSM->rc = VERR_IPE_UNEXPECTED_INFO_STATUS); 4011 return rc; 4012 } 4013 } 4014 } 4015 return VINF_SUCCESS; 4016 } 4017 4018 4019 /** 4020 * Continue a live state saving operation on the worker thread. 4021 * 4022 * The 4023 * 4024 * @returns VBox status. 4025 * 4026 * @param pSSM The SSM handle returned by SSMR3LiveToFile or 4027 * SSMR3LiveToRemote. 4028 * 4029 * @thread Non-EMT thread. Will involve the EMT at the end of the operation. 4030 */ 4031 VMMR3DECL(int) SSMR3LiveDoStep1(PSSMHANDLE pSSM) 4032 { 4033 LogFlow(("SSMR3LiveDoStep1: pSSM=%p\n", pSSM)); 4034 4035 /* 4036 * Validate input. 4037 */ 4038 AssertPtrReturn(pSSM, VERR_INVALID_POINTER); 4039 PVM pVM = pSSM->pVM; 4040 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); 4041 VM_ASSERT_OTHER_THREAD(pVM); 4042 AssertMsgReturn( pSSM->enmAfter == SSMAFTER_DESTROY 4043 || pSSM->enmAfter == SSMAFTER_CONTINUE, 4044 ("%d\n", pSSM->enmAfter), 4045 VERR_INVALID_PARAMETER); 4046 AssertMsgReturn(pSSM->enmOp == SSMSTATE_LIVE_EXEC, ("%d\n", pSSM->enmOp), VERR_INVALID_STATE); 4047 4048 /* 4049 * ... 4050 */ 4051 4052 return VERR_NOT_IMPLEMENTED; 4053 } 4054 4055 4056 /** 4057 * Calls pfnLivePrep for all units. 4058 * 4059 * @returns VBox status code (no need to check pSSM->rc). 4060 * @param pVM The VM handle. 4061 * @param pSSM The saved state handle. 4062 */ 4063 static int ssmR3DoLivePrepRun(PVM pVM, PSSMHANDLE pSSM) 4064 { 4065 /* 4066 * Do the prepare run. 4067 */ 4068 pSSM->rc = VINF_SUCCESS; 4069 pSSM->enmOp = SSMSTATE_SAVE_PREP; 4070 for (PSSMUNIT pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext) 4071 { 4072 if (pUnit->u.Common.pfnLivePrep) 4073 { 4074 int rc; 4075 switch (pUnit->enmType) 4076 { 4077 case SSMUNITTYPE_DEV: 4078 rc = pUnit->u.Dev.pfnLivePrep(pUnit->u.Dev.pDevIns, pSSM); 3462 4079 break; 3463 } 4080 case SSMUNITTYPE_DRV: 4081 rc = pUnit->u.Drv.pfnLivePrep(pUnit->u.Drv.pDrvIns, pSSM); 4082 break; 4083 case SSMUNITTYPE_INTERNAL: 4084 rc = pUnit->u.Internal.pfnLivePrep(pVM, pSSM); 4085 break; 4086 case SSMUNITTYPE_EXTERNAL: 4087 rc = pUnit->u.External.pfnLivePrep(pSSM, pUnit->u.External.pvUser); 4088 break; 4089 default: 4090 rc = VERR_INTERNAL_ERROR; 4091 break; 3464 4092 } 3465 3466 Handle.cbEstTotal += pUnit->cbGuess; 3467 } 3468 3469 /* Progress. */ 3470 if (pfnProgress) 3471 pfnProgress(pVM, Handle.uPercentPrepare-1, pvUser); 3472 Handle.uPercent = Handle.uPercentPrepare; 3473 3474 /* 3475 * Do the execute run. 3476 */ 4093 pUnit->fCalled = true; 4094 if (RT_SUCCESS(rc)) 4095 rc = pSSM->rc; 4096 if (RT_FAILURE(rc)) 4097 { 4098 LogRel(("SSM: Prepare save failed with rc=%Rrc for data unit '%s.\n", rc, pUnit->szName)); 4099 if (RT_SUCCESS(pSSM->rc)) 4100 pSSM->rc = rc; 4101 return rc; 4102 } 4103 } 4104 4105 pSSM->cbEstTotal += pUnit->cbGuess; 4106 } 4107 4108 /* 4109 * Work the progress indicator if we got one. 4110 */ 4111 if (pSSM->pfnProgress) 4112 pSSM->pfnProgress(pVM, 2, pSSM->pvUser); 4113 pSSM->uPercent = 2; 4114 4115 return VINF_SUCCESS; 4116 } 4117 4118 4119 /** 4120 * Start saving the live state to a file. 4121 * 4122 * The live saving sequence is something like this: 4123 * 4124 * -# SSMR3LiveToFile is called on EMT0. It returns a saved state 4125 * handle. 4126 * -# SSMR3LiveDoStep1 is called on a non-EMT. This will save the major 4127 * parts of the state while the VM may still be running. 4128 * -# The VM is suspended. 4129 * -# SSMR3LiveDoStep2 is called on EMT0 to save the remainder of the state 4130 * in the normal way. 4131 * -# The client does any necessary reconfiguration of harddisks and 4132 * similar. 4133 * -# SSMR3LiveDone is called on EMT0 to close the handle. 4134 * -# The VM is resumed or powered off and destroyed. 4135 * 4136 * SSMR3LiveDone should be called even if SSMR3LiveDoStep1 or SSMR3LiveDoStep2 4137 * fails. 4138 * 4139 * @returns VBox status. 4140 * 4141 * @param pVM The VM handle. 4142 * @param pszFilename Name of the file to save the state in. This string 4143 * must remain valid until SSMR3LiveDone is called. 4144 * @param enmAfter What is planned after a successful save operation. 4145 * @param pfnProgress Progress callback. Optional. 4146 * @param pvUser User argument for the progress callback. 4147 * 4148 * @thread EMT0 4149 */ 4150 VMMR3DECL(int) SSMR3LiveToFile(PVM pVM, const char *pszFilename, SSMAFTER enmAfter, 4151 PFNVMPROGRESS pfnProgress, void *pvUser, PSSMHANDLE *ppSSM) 4152 { 4153 LogFlow(("SSMR3LiveToFile: pszFilename=%p:{%s} enmAfter=%d pfnProgress=%p pvUser=%p\n", pszFilename, pszFilename, enmAfter, pfnProgress, pvUser)); 4154 VM_ASSERT_EMT0(pVM); 4155 4156 /* 4157 * Validate input. 4158 */ 4159 AssertMsgReturn( enmAfter == SSMAFTER_DESTROY 4160 || enmAfter == SSMAFTER_CONTINUE, 4161 ("%d\n", enmAfter), 4162 VERR_INVALID_PARAMETER); 4163 4164 /* 4165 * Create the saved state file and handle. 4166 * 4167 * Note that there might be quite some work to do after executing the saving, 4168 * so we reserve 20% for the 'Done' period. 4169 */ 4170 PSSMHANDLE pSSM; 4171 int rc = ssmR3SaveDoCreateFile(pVM, pszFilename, enmAfter, pfnProgress, pvUser, &pSSM); 4172 if (RT_FAILURE(rc)) 4173 return rc; 4174 pSSM->uPercentPrepare = 20; /** @todo fix these. */ 4175 pSSM->uPercentDone = 2; 4176 4177 /* 4178 * Write the saved state stream header and do the prep run for live saving. 4179 */ 4180 Log(("SSM: Starting state save to file '%s'...\n", pszFilename)); 4181 ssmR3StrmStartIoThread(&pSSM->Strm); 4182 rc = ssmR3WriteHeaderAndClearPerUnitData(pVM, pSSM); 4183 if (RT_SUCCESS(rc)) 4184 { 4185 /** @todo If it turns out we don't need to do ssmR3DoLivePrepRun on EMT0, 4186 * simply move the code to SSMR3LiveDoStep1. */ 4187 rc = ssmR3DoLivePrepRun(pVM, pSSM); 3477 4188 if (RT_SUCCESS(rc)) 3478 4189 { 3479 Handle.enmOp = SSMSTATE_SAVE_EXEC; 3480 for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext) 3481 { 3482 /* 3483 * Estimate. 3484 */ 3485 ssmR3Progress(&Handle, Handle.offEstUnitEnd - Handle.offEst); 3486 Handle.offEstUnitEnd += pUnit->cbGuess; 3487 3488 /* 3489 * Does this unit have a callback? If, not skip it. 3490 */ 3491 if (!pUnit->u.Common.pfnSaveExec) 3492 { 3493 pUnit->fCalled = true; 3494 continue; 3495 } 3496 pUnit->offStream = ssmR3StrmTell(&Handle.Strm); 3497 3498 /* 3499 * Write data unit header 3500 */ 3501 memcpy(&u.UnitHdr.szMagic[0], SSMFILEUNITHDR_MAGIC, sizeof(u.UnitHdr.szMagic)); 3502 u.UnitHdr.offStream = pUnit->offStream; 3503 u.UnitHdr.u32CurStreamCRC = ssmR3StrmCurCRC(&Handle.Strm); 3504 u.UnitHdr.u32CRC = 0; 3505 u.UnitHdr.u32Version = pUnit->u32Version; 3506 u.UnitHdr.u32Instance = pUnit->u32Instance; 3507 u.UnitHdr.u32Phase = SSM_PHASE_FINAL; 3508 u.UnitHdr.fFlags = 0; 3509 u.UnitHdr.cbName = (uint32_t)pUnit->cchName + 1; 3510 memcpy(&u.UnitHdr.szName[0], &pUnit->szName[0], u.UnitHdr.cbName); 3511 u.UnitHdr.u32CRC = RTCrc32(&u.UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV2, szName[u.UnitHdr.cbName])); 3512 Log(("SSM: Unit at %#9llx: '%s', instance %u, phase %#x, version %u\n", 3513 u.UnitHdr.offStream, u.UnitHdr.szName, u.UnitHdr.u32Instance, u.UnitHdr.u32Phase, u.UnitHdr.u32Version)); 3514 rc = ssmR3StrmWrite(&Handle.Strm, &u.UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV2, szName[u.UnitHdr.cbName])); 3515 if (RT_SUCCESS(rc)) 3516 { 3517 /* 3518 * Call the execute handler. 3519 */ 3520 ssmR3DataWriteBegin(&Handle); 3521 switch (pUnit->enmType) 3522 { 3523 case SSMUNITTYPE_DEV: 3524 rc = pUnit->u.Dev.pfnSaveExec(pUnit->u.Dev.pDevIns, &Handle); 3525 break; 3526 case SSMUNITTYPE_DRV: 3527 rc = pUnit->u.Drv.pfnSaveExec(pUnit->u.Drv.pDrvIns, &Handle); 3528 break; 3529 case SSMUNITTYPE_INTERNAL: 3530 rc = pUnit->u.Internal.pfnSaveExec(pVM, &Handle); 3531 break; 3532 case SSMUNITTYPE_EXTERNAL: 3533 pUnit->u.External.pfnSaveExec(&Handle, pUnit->u.External.pvUser); 3534 rc = Handle.rc; 3535 break; 3536 } 3537 pUnit->fCalled = true; 3538 if (RT_SUCCESS(rc)) 3539 rc = ssmR3DataFlushBuffer(&Handle); /* will return SSMHANDLE::rc if its set */ 3540 if (RT_SUCCESS(rc)) 3541 { 3542 /* 3543 * Write the termination record and flush the compression stream. 3544 */ 3545 SSMRECTERM TermRec; 3546 TermRec.u8TypeAndFlags = SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_TERM; 3547 TermRec.cbRec = sizeof(TermRec) - 2; 3548 if (Handle.Strm.fChecksummed) 3549 { 3550 TermRec.fFlags = SSMRECTERM_FLAGS_CRC32; 3551 TermRec.u32StreamCRC = RTCrc32Finish(RTCrc32Process(ssmR3StrmCurCRC(&Handle.Strm), &TermRec, 2)); 3552 } 3553 else 3554 { 3555 TermRec.fFlags = 0; 3556 TermRec.u32StreamCRC = 0; 3557 } 3558 TermRec.cbUnit = Handle.offUnit + sizeof(TermRec); 3559 rc = ssmR3DataWriteRaw(&Handle, &TermRec, sizeof(TermRec)); 3560 if (RT_SUCCESS(rc)) 3561 rc = ssmR3DataWriteFinish(&Handle); 3562 if (RT_SUCCESS(rc)) 3563 Handle.offUnit = UINT64_MAX; 3564 else 3565 { 3566 LogRel(("SSM: Failed ending compression stream. rc=%Rrc\n", rc)); 3567 break; 3568 } 3569 } 3570 else 3571 { 3572 LogRel(("SSM: Execute save failed with rc=%Rrc for data unit '%s.\n", rc, pUnit->szName)); 3573 break; 3574 } 3575 } 3576 if (RT_FAILURE(rc)) 3577 { 3578 LogRel(("SSM: Failed to write unit header. rc=%Rrc\n", rc)); 3579 break; 3580 } 3581 } /* for each unit */ 3582 3583 /* finish the progress. */ 3584 if (RT_SUCCESS(rc)) 3585 ssmR3Progress(&Handle, Handle.offEstUnitEnd - Handle.offEst); 3586 } 3587 /* (progress should be pending 99% now) */ 3588 AssertMsg(RT_FAILURE(rc) || Handle.uPercent == (101-Handle.uPercentDone), ("%d\n", Handle.uPercent)); 3589 3590 /* 3591 * Finalize the file if successfully saved. 3592 */ 3593 if (RT_SUCCESS(rc)) 3594 { 3595 /* Write the end unit. */ 3596 memcpy(&u.UnitHdr.szMagic[0], SSMFILEUNITHDR_END, sizeof(u.UnitHdr.szMagic)); 3597 u.UnitHdr.offStream = ssmR3StrmTell(&Handle.Strm); 3598 u.UnitHdr.u32CurStreamCRC = ssmR3StrmCurCRC(&Handle.Strm); 3599 u.UnitHdr.u32CRC = 0; 3600 u.UnitHdr.u32Version = 0; 3601 u.UnitHdr.u32Instance = 0; 3602 u.UnitHdr.u32Phase = SSM_PHASE_FINAL; 3603 u.UnitHdr.fFlags = 0; 3604 u.UnitHdr.cbName = 0; 3605 u.UnitHdr.u32CRC = RTCrc32(&u.UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV2, szName[0])); 3606 Log(("SSM: Unit at %#9llx: END UNIT\n", u.UnitHdr.offStream)); 3607 rc = ssmR3StrmWrite(&Handle.Strm, &u.UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV2, szName[0])); 3608 if (RT_SUCCESS(rc)) 3609 { 3610 /* Write the directory for the final units and then the footer. */ 3611 rc = ssmR3WriteDirectory(pVM, &Handle, &u.Footer.cDirEntries); 3612 if (RT_SUCCESS(rc)) 3613 { 3614 memcpy(u.Footer.szMagic, SSMFILEFTR_MAGIC, sizeof(u.Footer.szMagic)); 3615 u.Footer.offStream = ssmR3StrmTell(&Handle.Strm); 3616 u.Footer.u32StreamCRC = ssmR3StrmFinalCRC(&Handle.Strm); 3617 u.Footer.u32Reserved = 0; 3618 u.Footer.u32CRC = 0; 3619 u.Footer.u32CRC = RTCrc32(&u.Footer, sizeof(u.Footer)); 3620 Log(("SSM: Footer at %#9llx: \n", u.Footer.offStream)); 3621 rc = ssmR3StrmWrite(&Handle.Strm, &u.Footer, sizeof(u.Footer)); 3622 if (RT_SUCCESS(rc)) 3623 rc = ssmR3StrmSetEnd(&Handle.Strm); 3624 } 3625 } 3626 if (RT_FAILURE(rc)) 3627 LogRel(("SSM: Failed to finalize state file! rc=%Rrc\n", rc)); 3628 } 3629 3630 /* 3631 * Do the done run. 3632 */ 3633 Handle.rc = rc; 3634 Handle.enmOp = SSMSTATE_SAVE_DONE; 3635 for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext) 3636 { 3637 if ( pUnit->u.Common.pfnSaveDone 3638 && ( pUnit->fCalled 3639 || (!pUnit->u.Common.pfnSavePrep && !pUnit->u.Common.pfnSaveExec))) 3640 { 3641 switch (pUnit->enmType) 3642 { 3643 case SSMUNITTYPE_DEV: 3644 rc = pUnit->u.Dev.pfnSaveDone(pUnit->u.Dev.pDevIns, &Handle); 3645 break; 3646 case SSMUNITTYPE_DRV: 3647 rc = pUnit->u.Drv.pfnSaveDone(pUnit->u.Drv.pDrvIns, &Handle); 3648 break; 3649 case SSMUNITTYPE_INTERNAL: 3650 rc = pUnit->u.Internal.pfnSaveDone(pVM, &Handle); 3651 break; 3652 case SSMUNITTYPE_EXTERNAL: 3653 rc = pUnit->u.External.pfnSaveDone(&Handle, pUnit->u.External.pvUser); 3654 break; 3655 } 3656 if (RT_FAILURE(rc)) 3657 { 3658 LogRel(("SSM: Done save failed with rc=%Rrc for data unit '%s.\n", rc, pUnit->szName)); 3659 if (RT_SUCCESS(Handle.rc)) 3660 Handle.rc = rc; 3661 } 3662 } 3663 } 3664 rc = Handle.rc; 3665 3666 /* 3667 * Close the file and return if we've succeeded. 3668 */ 3669 if (RT_SUCCESS(rc)) 3670 rc = ssmR3StrmClose(&Handle.Strm); 3671 if (RT_SUCCESS(rc)) 3672 { 3673 if (pfnProgress) 3674 pfnProgress(pVM, 100, pvUser); 3675 LogRel(("SSM: Successfully saved the VM state to '%s'\n" 3676 "SSM: Footer at %#llx (%lld), %u directory entries.\n", 3677 pszFilename, u.Footer.offStream, u.Footer.offStream, u.Footer.cDirEntries)); 4190 /* 4191 * Return and let the requstor thread do the pfnLiveExec/Vote part 4192 * via SSMR3SaveFinishLive 4193 */ 4194 *ppSSM = pSSM; 3678 4195 return VINF_SUCCESS; 3679 4196 } 3680 4197 } 3681 3682 /* 3683 * Delete the file on failure. 3684 */ 3685 ssmR3StrmClose(&Handle.Strm); 3686 int rc2 = RTFileDelete(pszFilename); 4198 /* bail out. */ 4199 int rc2 = ssmR3StrmClose(&pSSM->Strm); 4200 RTMemFree(pSSM); 4201 rc2 = RTFileDelete(pszFilename); 3687 4202 AssertRC(rc2); 3688 3689 4203 return rc; 4204 } 4205 4206 4207 VMMR3DECL(int) SSMR3LiveToRemote(PVM pVM, PFNVMPROGRESS pfnProgress, void *pvUser /*, 4208 invent stream interface and stuff */) 4209 { 4210 return VERR_NOT_IMPLEMENTED; 3690 4211 } 3691 4212 … … 5453 5974 pSSM->uPercentPrepare = 5; 5454 5975 pSSM->uPercentDone = 2; 5976 pSSM->pszFilename = pszFilename; 5455 5977 5456 5978 pSSM->u.Read.pZipDecompV1 = NULL; … … 5612 6134 rc = pUnit->u.External.pfnLoadExec(pSSM, pUnit->u.External.pvUser, UnitHdr.u32Version, SSM_PHASE_FINAL); 5613 6135 break; 6136 default: 6137 rc = VERR_INTERNAL_ERROR; 6138 break; 5614 6139 } 5615 6140 … … 5791 6316 rc = pUnit->u.External.pfnLoadExec(pSSM, pUnit->u.External.pvUser, UnitHdr.u32Version, UnitHdr.u32Phase); 5792 6317 break; 6318 default: 6319 rc = VERR_INTERNAL_ERROR; 6320 break; 5793 6321 } 5794 6322 ssmR3DataReadFinishV2(pSSM); … … 5841 6369 { 5842 6370 LogFlow(("SSMR3Load: pszFilename=%p:{%s} enmAfter=%d pfnProgress=%p pvUser=%p\n", pszFilename, pszFilename, enmAfter, pfnProgress, pvUser)); 5843 VM_ASSERT_EMT (pVM);6371 VM_ASSERT_EMT0(pVM); 5844 6372 5845 6373 /* … … 5908 6436 case SSMUNITTYPE_EXTERNAL: 5909 6437 rc = pUnit->u.External.pfnLoadPrep(&Handle, pUnit->u.External.pvUser); 6438 break; 6439 default: 6440 rc = VERR_INTERNAL_ERROR; 5910 6441 break; 5911 6442 } … … 5964 6495 rc = pUnit->u.External.pfnLoadDone(&Handle, pUnit->u.External.pvUser); 5965 6496 break; 6497 default: 6498 rc = VERR_INTERNAL_ERROR; 6499 break; 5966 6500 } 5967 6501 if (RT_FAILURE(rc)) … … 6399 6933 VMMR3DECL(int) SSMR3HandleSetStatus(PSSMHANDLE pSSM, int iStatus) 6400 6934 { 6935 Assert(pSSM->enmOp != SSMSTATE_LIVE_VOTE); 6401 6936 if (RT_FAILURE(iStatus)) 6402 6937 { -
trunk/src/VBox/VMM/VM.cpp
r22784 r22792 1473 1473 * Change the state and perform the save. 1474 1474 */ 1475 bool fLive = pVM->enmVMState == VMSTATE_RUNNING; 1475 1476 vmR3SetState(pVM, VMSTATE_SAVING); /** @todo Should probably use a different state for live snapshots and/or live migration. Will fix the state machine later. */ 1476 int rc = SSMR3Save(pVM, pszFilename, enmAfter, pfnProgress, pvUser);1477 int rc = SSMR3Save(pVM, pszFilename, enmAfter, pfnProgress, pvUser); 1477 1478 vmR3SetState(pVM, VMSTATE_SUSPENDED); 1478 1479
Note:
See TracChangeset
for help on using the changeset viewer.

