VirtualBox

Changeset 24612 in vbox for trunk/src


Ignore:
Timestamp:
Nov 12, 2009 5:03:47 PM (15 years ago)
Author:
vboxsync
Message:

DrvVD: Added a LoadDone hook for implementing better handling of TempReadOnly errors (for teleportation).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Storage/DrvVD.cpp

    r24583 r24612  
    5858*******************************************************************************/
    5959
    60 /** Converts a pointer to VDIDISK::IMedia to a PVBOXDISK. */
     60/** Converts a pointer to VBOXDISK::IMedia to a PVBOXDISK. */
    6161#define PDMIMEDIA_2_VBOXDISK(pInterface) \
    6262    ( (PVBOXDISK)((uintptr_t)pInterface - RT_OFFSETOF(VBOXDISK, IMedia)) )
     
    146146} VBOXDISK, *PVBOXDISK;
    147147
     148
     149/*******************************************************************************
     150*   Internal Functions                                                         *
     151*******************************************************************************/
     152
     153/**
     154 * Internal: allocate new image descriptor and put it in the list
     155 */
     156static PVBOXIMAGE drvvdNewImage(PVBOXDISK pThis)
     157{
     158    AssertPtr(pThis);
     159    PVBOXIMAGE pImage = (PVBOXIMAGE)RTMemAllocZ(sizeof(VBOXIMAGE));
     160    if (pImage)
     161    {
     162        pImage->pVDIfsImage = NULL;
     163        PVBOXIMAGE *pp = &pThis->pImages;
     164        while (*pp != NULL)
     165            pp = &(*pp)->pNext;
     166        *pp = pImage;
     167        pImage->pNext = NULL;
     168    }
     169
     170    return pImage;
     171}
     172
     173/**
     174 * Internal: free the list of images descriptors.
     175 */
     176static void drvvdFreeImages(PVBOXDISK pThis)
     177{
     178    while (pThis->pImages != NULL)
     179    {
     180        PVBOXIMAGE p = pThis->pImages;
     181        pThis->pImages = pThis->pImages->pNext;
     182        RTMemFree(p);
     183    }
     184}
     185
     186
     187/**
     188 * Undo the temporary read-only status of the image.
     189 *
     190 * @returns VBox status code.
     191 * @param   pThis               The driver instance data.
     192 */
     193static int drvvdSetWritable(PVBOXDISK pThis)
     194{
     195    int rc = VINF_SUCCESS;
     196    if (pThis->fTempReadOnly)
     197    {
     198        unsigned uOpenFlags;
     199        rc = VDGetOpenFlags(pThis->pDisk, VD_LAST_IMAGE, &uOpenFlags);
     200        AssertRC(rc);
     201        uOpenFlags &= ~VD_OPEN_FLAGS_READONLY;
     202        rc = VDSetOpenFlags(pThis->pDisk, VD_LAST_IMAGE, uOpenFlags);
     203        if (RT_SUCCESS(rc))
     204            pThis->fTempReadOnly = false;
     205        else
     206            AssertRC(rc);
     207    }
     208    return rc;
     209}
     210
     211
    148212/*******************************************************************************
    149213*   Error reporting callback                                                   *
     
    163227    else
    164228        pDrvIns->pDrvHlp->pfnVMSetErrorV(pDrvIns, rc, RT_SRC_POS_ARGS, pszFormat, va);
    165 }
    166 
    167 
    168 /**
    169  * Internal: allocate new image descriptor and put it in the list
    170  */
    171 static PVBOXIMAGE drvvdNewImage(PVBOXDISK pThis)
    172 {
    173     AssertPtr(pThis);
    174     PVBOXIMAGE pImage = (PVBOXIMAGE)RTMemAllocZ(sizeof(VBOXIMAGE));
    175     if (pImage)
    176     {
    177         pImage->pVDIfsImage = NULL;
    178         PVBOXIMAGE *pp = &pThis->pImages;
    179         while (*pp != NULL)
    180             pp = &(*pp)->pNext;
    181         *pp = pImage;
    182         pImage->pNext = NULL;
    183     }
    184 
    185     return pImage;
    186 }
    187 
    188 /**
    189  * Internal: free the list of images descriptors.
    190  */
    191 static void drvvdFreeImages(PVBOXDISK pThis)
    192 {
    193     while (pThis->pImages != NULL)
    194     {
    195         PVBOXIMAGE p = pThis->pImages;
    196         pThis->pImages = pThis->pImages->pNext;
    197         RTMemFree(p);
    198     }
    199229}
    200230
     
    794824
    795825/*******************************************************************************
     826*   Saved state notification methods                                           *
     827*******************************************************************************/
     828
     829/**
     830 * Load done callback for re-opening the image writable during teleportation.
     831 *
     832 * This is called both for successful and failed load runs, we only care about
     833 * successfull ones.
     834 *
     835 * @returns VBox status code.
     836 * @param   pDrvIns         The driver instance.
     837 * @param   pSSM            The saved state handle.
     838 */
     839static DECLCALLBACK(int) drvvdLoadDone(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM)
     840{
     841    PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
     842    Assert(!pThis->fErrorUseRuntime);
     843
     844    /* Drop out if we don't have any work to do or if it's a failed load. */
     845    if (   !pThis->fTempReadOnly
     846        || RT_FAILURE(SSMR3HandleGetStatus(pSSM)))
     847        return VINF_SUCCESS;
     848
     849    int rc = drvvdSetWritable(pThis);
     850    if (RT_FAILURE(rc)) /** @todo does the bugger set any errors? */
     851        return SSMR3SetLoadError(pSSM, rc, RT_SRC_POS,
     852                                 N_("Failed to write lock the images"));
     853    return VINF_SUCCESS;
     854}
     855
     856
     857/*******************************************************************************
    796858*   Driver methods                                                             *
    797859*******************************************************************************/
    798860
     861static DECLCALLBACK(void) drvvdPowerOff(PPDMDRVINS pDrvIns)
     862{
     863    LogFlow(("%s:\n", __FUNCTION__));
     864    PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
     865
     866    /*
     867     * We must close the disk here to ensure that
     868     * the backend closes all files before the
     869     * async transport driver is destructed.
     870     */
     871    int rc = VDCloseAll(pThis->pDisk);
     872    AssertRC(rc);
     873}
     874
     875/**
     876 * VM resume notification that we use to undo what the temporary read-only image
     877 * mode set by drvvdSuspend.
     878 *
     879 * Also switch to runtime error mode if we're resuming after a state load
     880 * without having been powered on first.
     881 *
     882 * @param   pDrvIns     The driver instance data.
     883 *
     884 * @todo    The VMSetError vs VMSetRuntimeError mess must be fixed elsewhere,
     885 *          we're making assumptions about Main behavior here!
     886 */
     887static DECLCALLBACK(void) drvvdResume(PPDMDRVINS pDrvIns)
     888{
     889    LogFlow(("%s:\n", __FUNCTION__));
     890    PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
     891    drvvdSetWritable(pThis);
     892    pThis->fErrorUseRuntime = true;
     893}
     894
     895/**
     896 * The VM is being suspended, temporarily change to read-only image mode.
     897 *
     898 * This is important for several reasons:
     899 *   -# It makes sure that there are no pending writes to the image.  Most
     900 *      backends implements this by closing and reopening the image in read-only
     901 *      mode.
     902 *   -# It allows Main to read the images during snapshotting without having
     903 *      to account for concurrent writes.
     904 *   -# This is essential for making teleportation targets sharing images work
     905 *      right.  Both with regards to caching and with regards to file sharing
     906 *      locks (RTFILE_O_DENY_*).  (See also drvvdLoadDone.)
     907 *
     908 * @param   pDrvIns     The driver instance data.
     909 */
     910static DECLCALLBACK(void) drvvdSuspend(PPDMDRVINS pDrvIns)
     911{
     912    LogFlow(("%s:\n", __FUNCTION__));
     913    PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
     914    if (!VDIsReadOnly(pThis->pDisk))
     915    {
     916        unsigned uOpenFlags;
     917        int rc = VDGetOpenFlags(pThis->pDisk, VD_LAST_IMAGE, &uOpenFlags);
     918        AssertRC(rc);
     919        uOpenFlags |= VD_OPEN_FLAGS_READONLY;
     920        rc = VDSetOpenFlags(pThis->pDisk, VD_LAST_IMAGE, uOpenFlags);
     921        AssertRC(rc);
     922        pThis->fTempReadOnly = true;
     923    }
     924}
     925
     926/**
     927 * VM PowerOn notification for undoing the TempReadOnly config option and
     928 * changing to runtime error mode.
     929 *
     930 * @param   pDrvIns     The driver instance data.
     931 *
     932 * @todo    The VMSetError vs VMSetRuntimeError mess must be fixed elsewhere,
     933 *          we're making assumptions about Main behavior here!
     934 */
     935static DECLCALLBACK(void) drvvdPowerOn(PPDMDRVINS pDrvIns)
     936{
     937    LogFlow(("%s:\n", __FUNCTION__));
     938    PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
     939    drvvdSetWritable(pThis);
     940    pThis->fErrorUseRuntime = true;
     941}
     942
     943/**
     944 * @copydoc FNPDMDRVDESTRUCT
     945 */
     946static DECLCALLBACK(void) drvvdDestruct(PPDMDRVINS pDrvIns)
     947{
     948    PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
     949    LogFlow(("%s:\n", __FUNCTION__));
     950
     951    if (VALID_PTR(pThis->pDisk))
     952    {
     953        VDDestroy(pThis->pDisk);
     954        pThis->pDisk = NULL;
     955    }
     956    drvvdFreeImages(pThis);
     957}
    799958
    800959/**
     
    812971    char *pszName = NULL;   /**< The path of the disk image file. */
    813972    char *pszFormat = NULL; /**< The format backed to use for this image. */
    814     bool fReadOnly;         /**< True if the media is readonly. */
     973    bool fReadOnly;         /**< True if the media is read-only. */
    815974    bool fHonorZeroWrites;  /**< True if zero blocks should be written. */
    816975
     
    10961255           rc = PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
    10971256                                    N_("Failed to open image '%s' in %s mode rc=%Rrc"), pszName,
    1098                                     (uOpenFlags & VD_OPEN_FLAGS_READONLY) ? "readonly" : "read-write", rc);
     1257                                    (uOpenFlags & VD_OPEN_FLAGS_READONLY) ? "read-only" : "read-write", rc);
    10991258           break;
    11001259        }
     
    11101269        pCurNode = CFGMR3GetParent(pCurNode);
    11111270    }
     1271
     1272    /*
     1273     * Register a load-done callback so we can undo TempReadOnly config before
     1274     * we get to drvvdResume.  Autoamtically deregistered upon destruction.
     1275     */
     1276    if (RT_SUCCESS(rc))
     1277        rc = PDMDrvHlpSSMRegisterEx(pDrvIns, 0 /* version */, 0 /* cbGuess */,
     1278                                    NULL /*pfnLivePrep*/, NULL /*pfnLiveExec*/, NULL /*pfnLiveVote*/,
     1279                                    NULL /*pfnSavePrep*/, NULL /*pfnSaveExec*/, NULL /*pfnSaveDone*/,
     1280                                    NULL /*pfnDonePrep*/, NULL /*pfnLoadExec*/, drvvdLoadDone);
     1281
    11121282
    11131283    if (RT_FAILURE(rc))
     
    11191289        /* drvvdDestruct does the rest. */
    11201290    }
    1121     else
    1122     {
    1123         /* Switch to runtime error facility. */
    1124         pThis->fErrorUseRuntime = true;
    1125     }
    1126 
    1127     /* else: drvvdDestruct cleans up. */
    11281291
    11291292    LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
    11301293    return rc;
    11311294}
    1132 
    1133 /**
    1134  * Destruct a driver instance.
    1135  *
    1136  * Most VM resources are freed by the VM. This callback is provided so that any non-VM
    1137  * resources can be freed correctly.
    1138  *
    1139  * @param   pDrvIns     The driver instance data.
    1140  */
    1141 static DECLCALLBACK(void) drvvdDestruct(PPDMDRVINS pDrvIns)
    1142 {
    1143     PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
    1144     LogFlow(("%s:\n", __FUNCTION__));
    1145 
    1146     if (VALID_PTR(pThis->pDisk))
    1147     {
    1148         VDDestroy(pThis->pDisk);
    1149         pThis->pDisk = NULL;
    1150     }
    1151     drvvdFreeImages(pThis);
    1152 }
    1153 
    1154 
    1155 /**
    1156  * When the VM has been suspended we'll change the image mode to read-only
    1157  * so that main and others can read the VDIs. This is important when
    1158  * saving state and so forth.
    1159  *
    1160  * @param   pDrvIns     The driver instance data.
    1161  */
    1162 static DECLCALLBACK(void) drvvdSuspend(PPDMDRVINS pDrvIns)
    1163 {
    1164     LogFlow(("%s:\n", __FUNCTION__));
    1165     PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
    1166     if (!VDIsReadOnly(pThis->pDisk))
    1167     {
    1168         unsigned uOpenFlags;
    1169         int rc = VDGetOpenFlags(pThis->pDisk, VD_LAST_IMAGE, &uOpenFlags);
    1170         AssertRC(rc);
    1171         uOpenFlags |= VD_OPEN_FLAGS_READONLY;
    1172         rc = VDSetOpenFlags(pThis->pDisk, VD_LAST_IMAGE, uOpenFlags);
    1173         AssertRC(rc);
    1174         pThis->fTempReadOnly = true;
    1175     }
    1176 }
    1177 
    1178 /**
    1179  * Before the VM resumes we'll have to undo the read-only mode change
    1180  * done in drvvdSuspend.
    1181  *
    1182  * @param   pDrvIns     The driver instance data.
    1183  */
    1184 static DECLCALLBACK(void) drvvdResumeOrPowerOn(PPDMDRVINS pDrvIns)
    1185 {
    1186     LogFlow(("%s:\n", __FUNCTION__));
    1187     PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
    1188     if (pThis->fTempReadOnly)
    1189     {
    1190         unsigned uOpenFlags;
    1191         int rc = VDGetOpenFlags(pThis->pDisk, VD_LAST_IMAGE, &uOpenFlags);
    1192         AssertRC(rc);
    1193         uOpenFlags &= ~VD_OPEN_FLAGS_READONLY;
    1194         rc = VDSetOpenFlags(pThis->pDisk, VD_LAST_IMAGE, uOpenFlags);
    1195         AssertRC(rc);
    1196         pThis->fTempReadOnly = false;
    1197     }
    1198 }
    1199 
    1200 static DECLCALLBACK(void) drvvdPowerOff(PPDMDRVINS pDrvIns)
    1201 {
    1202     LogFlow(("%s:\n", __FUNCTION__));
    1203     PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
    1204 
    1205     /*
    1206      * We must close the disk here to ensure that
    1207      * the backend closes all files before the
    1208      * async transport driver is destructed.
    1209      */
    1210     int rc = VDCloseAll(pThis->pDisk);
    1211     AssertRC(rc);
    1212 }
    1213 
    12141295
    12151296/**
     
    12391320    NULL,
    12401321    /* pfnPowerOn */
    1241     drvvdResumeOrPowerOn,
     1322    drvvdPowerOn,
    12421323    /* pfnReset */
    12431324    NULL,
     
    12451326    drvvdSuspend,
    12461327    /* pfnResume */
    1247     drvvdResumeOrPowerOn,
     1328    drvvdResume,
    12481329    /* pfnAttach */
    12491330    NULL,
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