VirtualBox

Changeset 106211 in vbox for trunk


Ignore:
Timestamp:
Oct 3, 2024 2:35:14 AM (2 months ago)
Author:
vboxsync
Message:

VMM/SSM: Added SSM_OPEN_F_FOR_WRITING to SSMR3Open together with SSMR3WriteFileHeader, SSMR3WriteUnitBegin, SSMR3WriteUnitComplete and SSMR3WriteFileFooter. This is for use with saving & loading TBs for code profiling purposes. bugref:10720

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/vmm/ssm.h

    r106061 r106211  
    12241224VMMR3DECL(int)          SSMR3ValidateFile(const char *pszFilename, PCSSMSTRMOPS pStreamOps, void *pvStreamOps,
    12251225                                          bool fChecksumIt);
     1226
     1227/** Flag for SSMR3Open to create a new file for writing. */
     1228#define SSM_OPEN_F_FOR_WRITING      RT_BIT_32(0)
    12261229VMMR3DECL(int)          SSMR3Open(const char *pszFilename, PCSSMSTRMOPS pStreamOps, void *pvStreamOps,
    1227                                   unsigned fFlags, PSSMHANDLE *ppSSM);
     1230                                  uint32_t fFlags, PSSMHANDLE *ppSSM);
    12281231VMMR3DECL(int)          SSMR3Close(PSSMHANDLE pSSM);
    12291232VMMR3DECL(int)          SSMR3Seek(PSSMHANDLE pSSM, const char *pszUnit, uint32_t iInstance, uint32_t *piVersion);
     1233VMMR3DECL(int)          SSMR3WriteFileHeader(PSSMHANDLE pSSM, uint32_t cUnits);
     1234VMMR3DECL(int)          SSMR3WriteUnitBegin(PSSMHANDLE pSSM, const char *pszName, uint32_t uVersion, uint32_t uInstance);
     1235VMMR3DECL(int)          SSMR3WriteUnitComplete(PSSMHANDLE pSSM);
     1236VMMR3DECL(int)          SSMR3WriteFileFooter(PSSMHANDLE pSSM);
     1237
    12301238VMMR3DECL(int)          SSMR3HandleGetStatus(PSSMHANDLE pSSM);
    12311239VMMR3DECL(int)          SSMR3HandleSetStatus(PSSMHANDLE pSSM, int iStatus);
  • trunk/src/VBox/VMM/VMMR3/SSM.cpp

    r106061 r106211  
    304304#define SSM_ASSERT_WRITEABLE_RET(pSSM) \
    305305    AssertMsgReturn(   pSSM->enmOp == SSMSTATE_SAVE_EXEC \
    306                     || pSSM->enmOp == SSMSTATE_LIVE_EXEC,\
     306                    || pSSM->enmOp == SSMSTATE_LIVE_EXEC \
     307                    || pSSM->enmOp == SSMSTATE_OPEN_WRITE,\
    307308                    ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
    308309
     
    372373    SSMSTATE_LOAD_DONE,
    373374    SSMSTATE_OPEN_READ,
     375    SSMSTATE_OPEN_WRITE,
    374376    SSMSTATE_END
    375377} SSMSTATE;
     
    526528            /** The maximum downtime given as milliseconds. */
    527529            uint32_t        cMsMaxDowntime;
     530
     531            /** SSMSTATE_OPEN_WRITE: Number of allocated directory entries. */
     532            uint32_t        cDirEntriesAlloced;
     533            /** SSMSTATE_OPEN_WRITE: The directory. */
     534            struct SSMFILEDIR *pDir;
    528535        } Write;
    529536
     
    47354742
    47364743/**
    4737  * Finalize the saved state stream, i.e. add the end unit, directory
    4738  * and footer.
    4739  *
    4740  * @returns VBox status code (pSSM->rc).
    4741  * @param   pVM                 The cross context VM structure.
    4742  * @param   pSSM                The saved state handle.
    4743  */
    4744 static int ssmR3SaveDoFinalization(PVM pVM, PSSMHANDLE pSSM)
    4745 {
    4746     VM_ASSERT_EMT0(pVM);
    4747     Assert(RT_SUCCESS(pSSM->rc));
    4748 
    4749     /*
    4750      * Write the end unit.
    4751      */
     4744 * Writes out the END unit.
     4745 */
     4746static int ssmR3WriteEndUnit(PSSMHANDLE pSSM)
     4747{
     4748    AssertRC(pSSM->rc);
    47524749    SSMFILEUNITHDRV2 UnitHdr;
    47534750    memcpy(&UnitHdr.szMagic[0], SSMFILEUNITHDR_END, sizeof(UnitHdr.szMagic));
     
    47664763    {
    47674764        LogRel(("SSM: Failed writing the end unit: %Rrc\n", rc));
    4768         return pSSM->rc = rc;
    4769     }
    4770 
    4771     /*
    4772      * Write the directory for the final units and then the footer.
    4773      */
     4765        pSSM->rc = rc;
     4766    }
     4767    return rc;
     4768}
     4769
     4770
     4771/**
     4772 * Writes out the file footer and sets the end of the stream.
     4773 */
     4774static int ssmR3WriteFileFooter(PSSMHANDLE pSSM, uint32_t cDirEntries)
     4775{
    47744776    SSMFILEFTR Footer;
    4775     rc = ssmR3WriteDirectory(pVM, pSSM, &Footer.cDirEntries);
    4776     if (RT_FAILURE(rc))
    4777     {
    4778         LogRel(("SSM: Failed writing the directory: %Rrc\n", rc));
    4779         return pSSM->rc = rc;
    4780     }
    4781 
    47824777    memcpy(Footer.szMagic, SSMFILEFTR_MAGIC, sizeof(Footer.szMagic));
    47834778    Footer.offStream    = ssmR3StrmTell(&pSSM->Strm);
    47844779    Footer.u32StreamCRC = ssmR3StrmFinalCRC(&pSSM->Strm);
     4780    Footer.cDirEntries  = cDirEntries;
    47854781    Footer.u32Reserved  = 0;
    47864782    Footer.u32CRC       = 0;
    47874783    Footer.u32CRC       = RTCrc32(&Footer, sizeof(Footer));
    47884784    Log(("SSM: Footer at %#9llx: \n", Footer.offStream));
    4789     rc = ssmR3StrmWrite(&pSSM->Strm, &Footer, sizeof(Footer));
     4785    int rc = ssmR3StrmWrite(&pSSM->Strm, &Footer, sizeof(Footer));
    47904786    if (RT_SUCCESS(rc))
    47914787        rc = ssmR3StrmSetEnd(&pSSM->Strm);
     4788    if (RT_SUCCESS(rc))
     4789        LogRel(("SSM: Footer at %#llx (%lld), %u directory entries.\n", Footer.offStream, Footer.offStream, Footer.cDirEntries));
     4790    else
     4791    {
     4792        LogRel(("SSM: Failed writing the footer: %Rrc\n", rc));
     4793        pSSM->rc = rc;
     4794    }
     4795    return rc;
     4796}
     4797
     4798
     4799/**
     4800 * Finalize the saved state stream, i.e. add the end unit, directory
     4801 * and footer.
     4802 *
     4803 * @returns VBox status code (pSSM->rc).
     4804 * @param   pVM                 The cross context VM structure.
     4805 * @param   pSSM                The saved state handle.
     4806 */
     4807static int ssmR3SaveDoFinalization(PVM pVM, PSSMHANDLE pSSM)
     4808{
     4809    VM_ASSERT_EMT0(pVM);
     4810    Assert(RT_SUCCESS(pSSM->rc));
     4811
     4812    /*
     4813     * Write the end unit.
     4814     */
     4815    int rc = ssmR3WriteEndUnit(pSSM);
     4816    if (RT_SUCCESS(rc))
     4817    {
     4818        /*
     4819         * Write the directory for the final units and then the footer.
     4820         */
     4821        uint32_t cDirEntries = 0;
     4822        rc = ssmR3WriteDirectory(pVM, pSSM, &cDirEntries);
     4823        if (RT_SUCCESS(rc))
     4824        {
     4825            /*
     4826             * Write the footer.
     4827             */
     4828            rc = ssmR3WriteFileFooter(pSSM, cDirEntries);
     4829        }
     4830        else
     4831        {
     4832            LogRel(("SSM: Failed writing the directory: %Rrc\n", rc));
     4833            pSSM->rc = rc;
     4834        }
     4835    }
     4836    return rc;
     4837}
     4838
     4839
     4840/**
     4841 * Writes the file directory and footer.
     4842 *
     4843 * @returns VBox status code.
     4844 * @param   pSSM                The SSM handle.
     4845 */
     4846VMMR3DECL(int) SSMR3WriteFileFooter(PSSMHANDLE pSSM)
     4847{
     4848    AssertPtrReturn(pSSM, VERR_INVALID_POINTER);
     4849    AssertMsgReturn(pSSM->enmOp == SSMSTATE_OPEN_WRITE, ("%d\n", pSSM->enmOp), VERR_INVALID_PARAMETER);
     4850    AssertMsgReturn(pSSM->enmAfter == SSMAFTER_OPENED, ("%d\n", pSSM->enmAfter),VERR_INVALID_PARAMETER);
     4851    Assert(pSSM->fCancelled == SSMHANDLE_OK);
     4852
     4853    /*
     4854     * Write the directory.
     4855     */
     4856    PSSMFILEDIR pDir = pSSM->u.Write.pDir;
     4857    if (!pDir)
     4858    {
     4859        /* Allocate an empty directory as a placeholder. (Don't know we can
     4860           read this back, but whatever) */
     4861        pSSM->u.Write.pDir = pDir = (PSSMFILEDIR)RTMemAllocZ(RT_UOFFSETOF(SSMFILEDIR, aEntries[1]));
     4862        AssertReturn(pDir, VERR_NO_MEMORY);
     4863        pSSM->u.Write.cDirEntriesAlloced = 1;
     4864    }
     4865    memcpy(pDir->szMagic, SSMFILEDIR_MAGIC, sizeof(pDir->szMagic));
     4866    pDir->u32CRC = 0;
     4867    uint32_t const cbDir = RT_UOFFSETOF_DYN(SSMFILEDIR, aEntries[pDir->cEntries]);
     4868    pDir->u32CRC = RTCrc32(pDir, cbDir);
     4869    int rc = ssmR3StrmWrite(&pSSM->Strm, pDir, cbDir);
    47924870    if (RT_FAILURE(rc))
    4793     {
    4794         LogRel(("SSM: Failed writing the footer: %Rrc\n", rc));
    4795         return pSSM->rc = rc;
    4796     }
    4797 
    4798     LogRel(("SSM: Footer at %#llx (%lld), %u directory entries.\n",
    4799             Footer.offStream, Footer.offStream, Footer.cDirEntries));
    4800     return VINF_SUCCESS;
     4871        return rc;
     4872
     4873    /*
     4874     * Write the footer.
     4875     */
     4876    return ssmR3WriteFileFooter(pSSM, pDir->cEntries);
    48014877}
    48024878
     
    48234899        }
    48244900    }
     4901}
     4902
     4903
     4904/**
     4905 * Head code for saving a unit shared by ssmR3SaveDoExecRun() and
     4906 * SSMR3WriteUnitBegin().
     4907 */
     4908static int ssmR3SaveDoExecRunOneUnitBegin(PSSMHANDLE pSSM, PSSMUNIT pUnit, unsigned iUnit)
     4909{
     4910    /*
     4911     * Not all unit have a callback. Skip those which don't and
     4912     * make sure to keep the progress indicator up to date.
     4913     */
     4914    ssmR3ProgressByUnit(pSSM, iUnit);
     4915    pSSM->offEstUnitEnd += pUnit->cbGuess;
     4916    if (!pUnit->u.Common.pfnSaveExec)
     4917    {
     4918        pUnit->fCalled = true;
     4919        if (pUnit->cbGuess)
     4920            ssmR3ProgressByByte(pSSM, pSSM->offEstUnitEnd - pSSM->offEst);
     4921        return VINF_NO_CHANGE;
     4922    }
     4923    pUnit->offStream = ssmR3StrmTell(&pSSM->Strm);
     4924
     4925    /*
     4926     * Check for cancellation.
     4927     */
     4928    if (RT_UNLIKELY(ASMAtomicUoReadU32(&(pSSM)->fCancelled) == SSMHANDLE_CANCELLED))
     4929    {
     4930        LogRel(("SSM: Cancelled!\n"));
     4931        AssertRC(pSSM->rc);
     4932        return pSSM->rc = VERR_SSM_CANCELLED;
     4933    }
     4934
     4935    /*
     4936     * Write data unit header
     4937     */
     4938    SSMFILEUNITHDRV2 UnitHdr;
     4939    memcpy(&UnitHdr.szMagic[0], SSMFILEUNITHDR_MAGIC, sizeof(UnitHdr.szMagic));
     4940    UnitHdr.offStream       = pUnit->offStream;
     4941    UnitHdr.u32CurStreamCRC = ssmR3StrmCurCRC(&pSSM->Strm);
     4942    UnitHdr.u32CRC          = 0;
     4943    UnitHdr.u32Version      = pUnit->u32Version;
     4944    UnitHdr.u32Instance     = pUnit->u32Instance;
     4945    UnitHdr.u32Pass         = SSM_PASS_FINAL;
     4946    UnitHdr.fFlags          = 0;
     4947    UnitHdr.cbName          = (uint32_t)pUnit->cchName + 1;
     4948    memcpy(&UnitHdr.szName[0], &pUnit->szName[0], UnitHdr.cbName);
     4949    UnitHdr.u32CRC          = RTCrc32(&UnitHdr, RT_UOFFSETOF_DYN(SSMFILEUNITHDRV2, szName[UnitHdr.cbName]));
     4950    Log(("SSM: Unit at %#9llx: '%s', instance %u, pass %#x, version %u\n",
     4951         UnitHdr.offStream, UnitHdr.szName, UnitHdr.u32Instance, UnitHdr.u32Pass, UnitHdr.u32Version));
     4952    int rc = ssmR3StrmWrite(&pSSM->Strm, &UnitHdr, RT_UOFFSETOF_DYN(SSMFILEUNITHDRV2, szName[UnitHdr.cbName]));
     4953    if (RT_FAILURE(rc))
     4954    {
     4955        LogRel(("SSM: Failed to write unit header. rc=%Rrc\n", rc));
     4956        return pSSM->rc = rc;
     4957    }
     4958
     4959    ssmR3DataWriteBegin(pSSM);
     4960    return VINF_SUCCESS;
     4961}
     4962
     4963
     4964/**
     4965 * Tail code for saving a unit shared by ssmR3SaveDoExecRun() and
     4966 * SSMR3WriteUnitComplete().
     4967 */
     4968static int ssmR3SaveDoExecRunOneUnitComplete(PSSMHANDLE pSSM)
     4969{
     4970    /*
     4971     * Write the termination record and flush the compression stream.
     4972     */
     4973    SSMRECTERM TermRec;
     4974    TermRec.u8TypeAndFlags   = SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_TERM;
     4975    TermRec.cbRec            = sizeof(TermRec) - 2;
     4976    if (pSSM->Strm.fChecksummed)
     4977    {
     4978        TermRec.fFlags       = SSMRECTERM_FLAGS_CRC32;
     4979        TermRec.u32StreamCRC = RTCrc32Finish(RTCrc32Process(ssmR3StrmCurCRC(&pSSM->Strm), &TermRec, 2));
     4980    }
     4981    else
     4982    {
     4983        TermRec.fFlags       = 0;
     4984        TermRec.u32StreamCRC = 0;
     4985    }
     4986    TermRec.cbUnit           = pSSM->offUnit + sizeof(TermRec);
     4987    int rc = ssmR3DataWriteRaw(pSSM, &TermRec, sizeof(TermRec));
     4988    if (RT_SUCCESS(rc))
     4989        rc = ssmR3DataWriteFinish(pSSM);
     4990    if (RT_FAILURE(rc))
     4991    {
     4992        LogRel(("SSM: Failed terminating unit: %Rrc\n", rc));
     4993        return pSSM->rc = rc;
     4994    }
     4995
     4996    /*
     4997     * Advance the progress indicator to the end of the current unit.
     4998     */
     4999    ssmR3ProgressByByte(pSSM, pSSM->offEstUnitEnd - pSSM->offEst);
     5000
     5001    return VINF_SUCCESS;
    48255002}
    48265003
     
    48435020    {
    48445021        /*
    4845          * Not all unit have a callback. Skip those which don't and
    4846          * make sure to keep the progress indicator up to date.
     5022         * Begin unit saving.
    48475023         */
    4848         ssmR3ProgressByUnit(pSSM, iUnit);
    4849         pSSM->offEstUnitEnd += pUnit->cbGuess;
    4850         if (!pUnit->u.Common.pfnSaveExec)
    4851         {
    4852             pUnit->fCalled = true;
    4853             if (pUnit->cbGuess)
    4854                 ssmR3ProgressByByte(pSSM, pSSM->offEstUnitEnd - pSSM->offEst);
    4855             continue;
    4856         }
    4857         pUnit->offStream = ssmR3StrmTell(&pSSM->Strm);
    4858 
    4859         /*
    4860          * Check for cancellation.
    4861          */
    4862         if (RT_UNLIKELY(ASMAtomicUoReadU32(&(pSSM)->fCancelled) == SSMHANDLE_CANCELLED))
    4863         {
    4864             LogRel(("SSM: Cancelled!\n"));
    4865             AssertRC(pSSM->rc);
    4866             return pSSM->rc = VERR_SSM_CANCELLED;
    4867         }
    4868 
    4869         /*
    4870          * Write data unit header
    4871          */
    4872         SSMFILEUNITHDRV2 UnitHdr;
    4873         memcpy(&UnitHdr.szMagic[0], SSMFILEUNITHDR_MAGIC, sizeof(UnitHdr.szMagic));
    4874         UnitHdr.offStream       = pUnit->offStream;
    4875         UnitHdr.u32CurStreamCRC = ssmR3StrmCurCRC(&pSSM->Strm);
    4876         UnitHdr.u32CRC          = 0;
    4877         UnitHdr.u32Version      = pUnit->u32Version;
    4878         UnitHdr.u32Instance     = pUnit->u32Instance;
    4879         UnitHdr.u32Pass         = SSM_PASS_FINAL;
    4880         UnitHdr.fFlags          = 0;
    4881         UnitHdr.cbName          = (uint32_t)pUnit->cchName + 1;
    4882         memcpy(&UnitHdr.szName[0], &pUnit->szName[0], UnitHdr.cbName);
    4883         UnitHdr.u32CRC          = RTCrc32(&UnitHdr, RT_UOFFSETOF_DYN(SSMFILEUNITHDRV2, szName[UnitHdr.cbName]));
    4884         Log(("SSM: Unit at %#9llx: '%s', instance %u, pass %#x, version %u\n",
    4885              UnitHdr.offStream, UnitHdr.szName, UnitHdr.u32Instance, UnitHdr.u32Pass, UnitHdr.u32Version));
    4886         int rc = ssmR3StrmWrite(&pSSM->Strm, &UnitHdr, RT_UOFFSETOF_DYN(SSMFILEUNITHDRV2, szName[UnitHdr.cbName]));
    4887         if (RT_FAILURE(rc))
    4888         {
    4889             LogRel(("SSM: Failed to write unit header. rc=%Rrc\n", rc));
    4890             return pSSM->rc = rc;
     5024        int rc = ssmR3SaveDoExecRunOneUnitBegin(pSSM, pUnit, iUnit);
     5025        if (rc != VINF_SUCCESS)
     5026        {
     5027            Assert(RT_FAILURE_NP(rc) || (!pUnit->u.Common.pfnSaveExec && rc == VINF_NO_CHANGE));
     5028            if (RT_SUCCESS(rc))
     5029                continue;
     5030            return rc;
    48915031        }
    48925032
     
    48945034         * Call the execute handler.
    48955035         */
    4896         ssmR3DataWriteBegin(pSSM);
    48975036        ssmR3UnitCritSectEnter(pVM, pUnit);
    48985037        switch (pUnit->enmType)
     
    49305069
    49315070        /*
    4932          * Write the termination record and flush the compression stream.
     5071         * Finish the unit.
    49335072         */
    4934         SSMRECTERM TermRec;
    4935         TermRec.u8TypeAndFlags   = SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_TERM;
    4936         TermRec.cbRec            = sizeof(TermRec) - 2;
    4937         if (pSSM->Strm.fChecksummed)
    4938         {
    4939             TermRec.fFlags       = SSMRECTERM_FLAGS_CRC32;
    4940             TermRec.u32StreamCRC = RTCrc32Finish(RTCrc32Process(ssmR3StrmCurCRC(&pSSM->Strm), &TermRec, 2));
    4941         }
    4942         else
    4943         {
    4944             TermRec.fFlags       = 0;
    4945             TermRec.u32StreamCRC = 0;
    4946         }
    4947         TermRec.cbUnit           = pSSM->offUnit + sizeof(TermRec);
    4948         rc = ssmR3DataWriteRaw(pSSM, &TermRec, sizeof(TermRec));
    4949         if (RT_SUCCESS(rc))
    4950             rc = ssmR3DataWriteFinish(pSSM);
     5073        rc = ssmR3SaveDoExecRunOneUnitComplete(pSSM);
    49515074        if (RT_FAILURE(rc))
    49525075        {
    4953             LogRel(("SSM: Failed terminating unit: %Rrc\n", rc));
    4954             return pSSM->rc = rc;
    4955         }
    4956 
    4957         /*
    4958          * Advance the progress indicator to the end of the current unit.
    4959          */
    4960         ssmR3ProgressByByte(pSSM, pSSM->offEstUnitEnd - pSSM->offEst);
     5076            Assert(RT_FAILURE_NP(pSSM->rc));
     5077            return rc;
     5078        }
    49615079    } /* for each unit */
    49625080    ssmR3ProgressByUnit(pSSM, pVM->ssm.s.cUnits);
     
    49675085              ("%d\n", pSSM->uPercent));
    49685086    return VINF_SUCCESS;
     5087}
     5088
     5089
     5090/**
     5091 * Begins saving a unit to a SSM file/stream opened via SSMR3Open.
     5092 *
     5093 * @returns VBox status code.
     5094 * @param   pSSM            The saved state handle.
     5095 * @param   pszName         The unit name.
     5096 * @param   uVersion        The unit version.
     5097 * @param   uInstance       The unit instance number.
     5098 */
     5099VMMR3DECL(int) SSMR3WriteUnitBegin(PSSMHANDLE pSSM, const char *pszName, uint32_t uVersion, uint32_t uInstance)
     5100{
     5101    /*
     5102     * Validate input and state.
     5103     */
     5104    AssertPtrReturn(pSSM, VERR_INVALID_POINTER);
     5105    AssertMsgReturn(pSSM->enmOp == SSMSTATE_OPEN_WRITE, ("%d\n", pSSM->enmOp), VERR_INVALID_PARAMETER);
     5106    AssertMsgReturn(pSSM->enmAfter == SSMAFTER_OPENED, ("%d\n", pSSM->enmAfter),VERR_INVALID_PARAMETER);
     5107
     5108    AssertPtrReturn(pszName, VERR_INVALID_PARAMETER);
     5109    size_t const cchName = strlen(pszName);
     5110    AssertReturn(cchName > 0 && cchName < SSM_MAX_NAME_SIZE, VERR_INVALID_NAME);
     5111
     5112
     5113    /*
     5114     * We abuse u32CRC to indicate whether we've started a unit.
     5115     */
     5116    AssertRCReturn(pSSM->rc, pSSM->rc);
     5117    AssertReturn(!pSSM->u.Write.pDir || pSSM->u.Write.pDir->u32CRC == 0, pSSM->rc = VERR_INVALID_STATE);
     5118
     5119    /*
     5120     * Add the unit to the directory.
     5121     */
     5122    PSSMFILEDIR pDir     = pSSM->u.Write.pDir;
     5123    uint32_t    cAlloced = pSSM->u.Write.cDirEntriesAlloced;
     5124    if (!pDir || pDir->cEntries + 1 > cAlloced)
     5125    {
     5126        pDir = (PSSMFILEDIR)RTMemReallocZ(pDir, cAlloced ? RT_UOFFSETOF_DYN(SSMFILEDIR, aEntries[cAlloced]) : 0,
     5127                                          RT_UOFFSETOF_DYN(SSMFILEDIR, aEntries[cAlloced + 16]));
     5128        AssertReturn(pDir, pSSM->rc = VERR_NO_MEMORY);
     5129        pSSM->u.Write.cDirEntriesAlloced = cAlloced + 16;
     5130        pSSM->u.Write.pDir               = pDir;
     5131    }
     5132    pDir->aEntries[pDir->cEntries].off         = ssmR3StrmTell(&pSSM->Strm);
     5133    pDir->aEntries[pDir->cEntries].u32Instance = uInstance;
     5134    pDir->aEntries[pDir->cEntries].u32NameCRC  = RTCrc32(pszName, cchName);
     5135    pDir->cEntries++;
     5136
     5137    /*
     5138     * Create a unit structure and join paths with ssmR3SaveDoExecRun.
     5139     */
     5140    union
     5141    {
     5142        SSMUNIT Unit;
     5143        uint8_t abPadding[RT_UOFFSETOF(SSMUNIT, szName) + SSM_MAX_NAME_SIZE];
     5144    } u;
     5145    RT_ZERO(u);
     5146    u.Unit.enmType              = SSMUNITTYPE_EXTERNAL;
     5147    u.Unit.u32Version           = uVersion;
     5148    u.Unit.u32Instance          = uInstance;
     5149    u.Unit.offStream            = 0;
     5150    u.Unit.pCritSect            = NULL;
     5151    u.Unit.u.Common.pfnSaveExec = (PFNRT)~(uintptr_t)1; /* must be non-zero */
     5152    u.Unit.cbGuess              = 64; /* whatever */
     5153    u.Unit.cchName              = cchName;
     5154    memcpy(u.Unit.szName, pszName, cchName + 1);
     5155
     5156    int rc = ssmR3SaveDoExecRunOneUnitBegin(pSSM, &u.Unit, pDir->cEntries - 1);
     5157    if (rc == VINF_SUCCESS)
     5158        pSSM->u.Write.pDir->u32CRC = 1; /* See above. */
     5159    else
     5160        Assert(RT_FAILURE_NP(rc));
     5161    return rc;
     5162}
     5163
     5164
     5165/**
     5166 * Completes a unit started by SSMR3WriteUnitBegin().
     5167 *
     5168 * @returns VBox status code.
     5169 * @param   pSSM            The saved state handle.
     5170 */
     5171VMMR3DECL(int) SSMR3WriteUnitComplete(PSSMHANDLE pSSM)
     5172{
     5173    /*
     5174     * Validate input and state.
     5175     */
     5176    AssertPtrReturn(pSSM, VERR_INVALID_POINTER);
     5177    AssertMsgReturn(pSSM->enmOp == SSMSTATE_OPEN_WRITE, ("%d\n", pSSM->enmOp), VERR_INVALID_PARAMETER);
     5178    AssertMsgReturn(pSSM->enmAfter == SSMAFTER_OPENED, ("%d\n", pSSM->enmAfter),VERR_INVALID_PARAMETER);
     5179
     5180    AssertReturn(pSSM->u.Write.pDir, VERR_INVALID_STATE);
     5181    AssertReturn(pSSM->u.Write.pDir->cEntries > 0, VERR_INVALID_STATE);
     5182    AssertReturn(pSSM->u.Write.pDir->u32CRC == 1, VERR_INVALID_STATE);
     5183
     5184    AssertRCReturn(pSSM->rc, pSSM->rc);
     5185    pSSM->u.Write.pDir->u32CRC = 0;
     5186
     5187    /*
     5188     * Finish the unit.
     5189     */
     5190    int rc = ssmR3DataFlushBuffer(pSSM); /* will return SSMHANDLE::rc if it is set */
     5191    if (RT_SUCCESS(rc))
     5192        rc = ssmR3SaveDoExecRunOneUnitComplete(pSSM);
     5193    return rc;
    49695194}
    49705195
     
    51045329
    51055330/**
    5106  * Writes the file header and clear the per-unit data.
    5107  *
    5108  * @returns VBox status code.
    5109  * @param   pVM                 The cross context VM structure.
     5331 * Writes the file header.
     5332 *
     5333 * @returns VBox status code.
    51105334 * @param   pSSM                The SSM handle.
    5111  */
    5112 static int ssmR3WriteHeaderAndClearPerUnitData(PVM pVM, PSSMHANDLE pSSM)
    5113 {
    5114     /*
    5115      * Write the header.
    5116      */
     5335 * @param   cUnits              Copy of pVM->ssm.s.cUnits, typically.
     5336 */
     5337static int ssmR3WriteFileHeader(PSSMHANDLE pSSM, uint32_t cUnits)
     5338{
    51175339    SSMFILEHDR FileHdr;
    51185340    memcpy(&FileHdr.szMagic, SSMFILEHDR_MAGIC_V2_0, sizeof(FileHdr.szMagic));
     
    51255347    FileHdr.cbGCPtr      = sizeof(RTGCPTR);
    51265348    FileHdr.u8Reserved   = 0;
    5127     FileHdr.cUnits       = pVM->ssm.s.cUnits;
     5349    FileHdr.cUnits       = cUnits;
    51285350    FileHdr.fFlags       = SSMFILEHDR_FLAGS_STREAM_CRC32;
    51295351    if (pSSM->fLiveSave)
     
    51325354    FileHdr.u32CRC       = 0;
    51335355    FileHdr.u32CRC       = RTCrc32(&FileHdr, sizeof(FileHdr));
    5134     int rc = ssmR3StrmWrite(&pSSM->Strm, &FileHdr, sizeof(FileHdr));
    5135     if (RT_FAILURE(rc))
    5136         return rc;
    5137 
    5138     /*
    5139      * Clear the per unit flags and offsets.
    5140      */
    5141     for (PSSMUNIT pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
    5142     {
    5143         pUnit->fCalled   = false;
    5144         pUnit->offStream = RTFOFF_MIN;
    5145     }
    5146 
    5147     return VINF_SUCCESS;
     5356    return ssmR3StrmWrite(&pSSM->Strm, &FileHdr, sizeof(FileHdr));
     5357}
     5358
     5359
     5360/**
     5361 * Writes the file header.
     5362 *
     5363 * @returns VBox status code.
     5364 * @param   pSSM                The SSM handle.
     5365 * @param   cUnits              Number of units to advertise in the header.
     5366 */
     5367VMMR3DECL(int) SSMR3WriteFileHeader(PSSMHANDLE pSSM, uint32_t cUnits)
     5368{
     5369    AssertPtrReturn(pSSM, VERR_INVALID_POINTER);
     5370    AssertMsgReturn(pSSM->enmOp == SSMSTATE_OPEN_WRITE, ("%d\n", pSSM->enmOp), VERR_INVALID_PARAMETER);
     5371    AssertMsgReturn(pSSM->enmAfter == SSMAFTER_OPENED, ("%d\n", pSSM->enmAfter),VERR_INVALID_PARAMETER);
     5372    AssertMsgReturn(cUnits > 0 && cUnits < _4K, ("%d\n", cUnits),VERR_INVALID_PARAMETER);
     5373    Assert(pSSM->fCancelled == SSMHANDLE_OK);
     5374
     5375    return ssmR3WriteFileHeader(pSSM, cUnits);
     5376}
     5377
     5378
     5379/**
     5380 * Writes the file header and clear the per-unit data.
     5381 *
     5382 * @returns VBox status code.
     5383 * @param   pVM                 The cross context VM structure.
     5384 * @param   pSSM                The SSM handle.
     5385 */
     5386static int ssmR3WriteHeaderAndClearPerUnitData(PVM pVM, PSSMHANDLE pSSM)
     5387{
     5388    /*
     5389     * Write the header.
     5390     */
     5391    int rc = ssmR3WriteFileHeader(pSSM, pVM->ssm.s.cUnits);
     5392    if (RT_SUCCESS(rc))
     5393    {
     5394        /*
     5395         * Clear the per unit flags and offsets.
     5396         */
     5397        for (PSSMUNIT pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
     5398        {
     5399            pUnit->fCalled   = false;
     5400            pUnit->offStream = RTFOFF_MIN;
     5401        }
     5402    }
     5403    return rc;
    51485404}
    51495405
     
    93709626 *                          used.
    93719627 * @param   pvStreamOps     The user argument to the stream methods.
    9372  * @param   fFlags          Open flags. Reserved, must be 0.
     9628 * @param   fFlags          Open flags, SSM_OPEN_F_XXXX.
    93739629 * @param   ppSSM           Where to store the SSM handle.
    93749630 *
     
    93849640     */
    93859641    AssertReturn(!pszFilename != !pStreamOps, VERR_INVALID_POINTER);
    9386     AssertMsgReturn(!fFlags, ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
     9642#ifndef SSM_STANDALONE
     9643    AssertMsgReturn(!(fFlags & ~SSM_OPEN_F_FOR_WRITING), ("%#x\n", fFlags), VERR_INVALID_FLAGS);
     9644#else
     9645    AssertMsgReturn(!fFlags, ("%#x\n", fFlags), VERR_INVALID_FLAGS);
     9646#endif
    93879647    AssertPtrReturn(ppSSM, VERR_INVALID_POINTER);
    93889648
    9389     /*
    9390      * Allocate a handle.
    9391      */
    9392     PSSMHANDLE pSSM = (PSSMHANDLE)RTMemAllocZ(sizeof(*pSSM));
    9393     AssertReturn(pSSM, VERR_NO_MEMORY);
    9394 
    9395     /*
    9396      * Try open the file and validate it.
    9397      */
    9398     int rc = ssmR3OpenFile(NULL, pszFilename, pStreamOps, pvStreamOps, false /*fChecksumIt*/,
    9399                            true /*fChecksumOnRead*/, 1 /*cBuffers*/, pSSM);
    9400     if (RT_SUCCESS(rc))
    9401     {
    9402         pSSM->enmAfter = SSMAFTER_OPENED;
    9403         pSSM->enmOp    = SSMSTATE_OPEN_READ;
    9404         *ppSSM = pSSM;
    9405         LogFlow(("SSMR3Open: returns VINF_SUCCESS *ppSSM=%p\n", *ppSSM));
    9406         return VINF_SUCCESS;
    9407     }
    9408 
    9409     Log(("SSMR3Open: Failed to open saved state file '%s', rc=%Rrc.\n",  pszFilename, rc));
    9410     RTMemFree(pSSM);
     9649    int rc;
     9650#ifndef SSM_STANDALONE
     9651    if (fFlags & SSM_OPEN_F_FOR_WRITING)
     9652    {
     9653        /*
     9654         * Try create a new file.
     9655         */
     9656        PSSMHANDLE pSSM;
     9657        rc = ssmR3SaveDoCreateFile(NULL, pszFilename, pStreamOps, pvStreamOps, SSMAFTER_OPENED, NULL, NULL, &pSSM);
     9658        if (RT_SUCCESS(rc))
     9659        {
     9660            Log(("SSM: Starting state save to file '%s'...\n", pszFilename));
     9661            ssmR3StrmStartIoThread(&pSSM->Strm);
     9662            pSSM->enmOp = SSMSTATE_OPEN_WRITE;
     9663            *ppSSM = pSSM;
     9664            return VINF_SUCCESS;
     9665        }
     9666        Log(("SSMR3Open: Failed to open saved state file '%s' for writing: rc=%Rrc.\n",  pszFilename, rc));
     9667    }
     9668    else
     9669#endif /* !SSM_STANDALONE */
     9670    {
     9671        /*
     9672         * Allocate a handle.
     9673         */
     9674        PSSMHANDLE pSSM = (PSSMHANDLE)RTMemAllocZ(sizeof(*pSSM));
     9675        AssertReturn(pSSM, VERR_NO_MEMORY);
     9676
     9677        /*
     9678         * Try open the file and validate the header and stuff.
     9679         */
     9680        rc = ssmR3OpenFile(NULL, pszFilename, pStreamOps, pvStreamOps, false /*fChecksumIt*/,
     9681                               true /*fChecksumOnRead*/, 1 /*cBuffers*/, pSSM);
     9682        if (RT_SUCCESS(rc))
     9683        {
     9684            pSSM->enmAfter = SSMAFTER_OPENED;
     9685            pSSM->enmOp    = SSMSTATE_OPEN_READ;
     9686            *ppSSM = pSSM;
     9687            LogFlow(("SSMR3Open: returns VINF_SUCCESS *ppSSM=%p\n", *ppSSM));
     9688            return VINF_SUCCESS;
     9689        }
     9690
     9691        Log(("SSMR3Open: Failed to open saved state file '%s', rc=%Rrc.\n",  pszFilename, rc));
     9692        RTMemFree(pSSM);
     9693    }
     9694
    94119695    return rc;
    9412 
    94139696}
    94149697
     
    94329715    AssertPtrReturn(pSSM, VERR_INVALID_POINTER);
    94339716    AssertMsgReturn(pSSM->enmAfter == SSMAFTER_OPENED, ("%d\n", pSSM->enmAfter),VERR_INVALID_PARAMETER);
    9434     AssertMsgReturn(pSSM->enmOp == SSMSTATE_OPEN_READ, ("%d\n", pSSM->enmOp), VERR_INVALID_PARAMETER);
     9717    AssertMsgReturn(pSSM->enmOp == SSMSTATE_OPEN_READ || pSSM->enmOp == SSMSTATE_OPEN_WRITE,
     9718                    ("%d\n", pSSM->enmOp), VERR_INVALID_PARAMETER);
    94359719    Assert(pSSM->fCancelled == SSMHANDLE_OK);
    94369720
     
    94399723     */
    94409724    int rc = ssmR3StrmClose(&pSSM->Strm, pSSM->rc == VERR_SSM_CANCELLED);
    9441     if (pSSM->u.Read.pZipDecompV1)
     9725    if (pSSM->enmOp == SSMSTATE_OPEN_READ && pSSM->u.Read.pZipDecompV1)
    94429726    {
    94439727        RTZipDecompDestroy(pSSM->u.Read.pZipDecompV1);
    94449728        pSSM->u.Read.pZipDecompV1 = NULL;
     9729    }
     9730    if (pSSM->enmOp == SSMSTATE_OPEN_WRITE && pSSM->u.Write.pDir)
     9731    {
     9732        RTMemFree(pSSM->u.Write.pDir);
     9733        pSSM->u.Write.pDir = NULL;
    94459734    }
    94469735    RTMemFree(pSSM);
Note: See TracChangeset for help on using the changeset viewer.

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