- Timestamp:
- Nov 12, 2009 5:03:47 PM (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Storage/DrvVD.cpp
r24583 r24612 58 58 *******************************************************************************/ 59 59 60 /** Converts a pointer to V DIDISK::IMedia to a PVBOXDISK. */60 /** Converts a pointer to VBOXDISK::IMedia to a PVBOXDISK. */ 61 61 #define PDMIMEDIA_2_VBOXDISK(pInterface) \ 62 62 ( (PVBOXDISK)((uintptr_t)pInterface - RT_OFFSETOF(VBOXDISK, IMedia)) ) … … 146 146 } VBOXDISK, *PVBOXDISK; 147 147 148 149 /******************************************************************************* 150 * Internal Functions * 151 *******************************************************************************/ 152 153 /** 154 * Internal: allocate new image descriptor and put it in the list 155 */ 156 static 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 */ 176 static 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 */ 193 static 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 148 212 /******************************************************************************* 149 213 * Error reporting callback * … … 163 227 else 164 228 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 list170 */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 }199 229 } 200 230 … … 794 824 795 825 /******************************************************************************* 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 */ 839 static 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 /******************************************************************************* 796 858 * Driver methods * 797 859 *******************************************************************************/ 798 860 861 static 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 */ 887 static 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 */ 910 static 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 */ 935 static 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 */ 946 static 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 } 799 958 800 959 /** … … 812 971 char *pszName = NULL; /**< The path of the disk image file. */ 813 972 char *pszFormat = NULL; /**< The format backed to use for this image. */ 814 bool fReadOnly; /**< True if the media is read only. */973 bool fReadOnly; /**< True if the media is read-only. */ 815 974 bool fHonorZeroWrites; /**< True if zero blocks should be written. */ 816 975 … … 1096 1255 rc = PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, 1097 1256 N_("Failed to open image '%s' in %s mode rc=%Rrc"), pszName, 1098 (uOpenFlags & VD_OPEN_FLAGS_READONLY) ? "read only" : "read-write", rc);1257 (uOpenFlags & VD_OPEN_FLAGS_READONLY) ? "read-only" : "read-write", rc); 1099 1258 break; 1100 1259 } … … 1110 1269 pCurNode = CFGMR3GetParent(pCurNode); 1111 1270 } 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 1112 1282 1113 1283 if (RT_FAILURE(rc)) … … 1119 1289 /* drvvdDestruct does the rest. */ 1120 1290 } 1121 else1122 {1123 /* Switch to runtime error facility. */1124 pThis->fErrorUseRuntime = true;1125 }1126 1127 /* else: drvvdDestruct cleans up. */1128 1291 1129 1292 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc)); 1130 1293 return rc; 1131 1294 } 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-VM1137 * 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-only1157 * so that main and others can read the VDIs. This is important when1158 * 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 change1180 * 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 that1207 * the backend closes all files before the1208 * async transport driver is destructed.1209 */1210 int rc = VDCloseAll(pThis->pDisk);1211 AssertRC(rc);1212 }1213 1214 1295 1215 1296 /** … … 1239 1320 NULL, 1240 1321 /* pfnPowerOn */ 1241 drvvd ResumeOrPowerOn,1322 drvvdPowerOn, 1242 1323 /* pfnReset */ 1243 1324 NULL, … … 1245 1326 drvvdSuspend, 1246 1327 /* pfnResume */ 1247 drvvdResume OrPowerOn,1328 drvvdResume, 1248 1329 /* pfnAttach */ 1249 1330 NULL,
Note:
See TracChangeset
for help on using the changeset viewer.