Changeset 54948 in vbox
- Timestamp:
- Mar 25, 2015 4:56:48 PM (10 years ago)
- svn:sync-xref-src-repo-rev:
- 99196
- Location:
- trunk
- Files:
-
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/settings.h
r54584 r54948 18 18 19 19 /* 20 * Copyright (C) 2007-201 4Oracle Corporation20 * Copyright (C) 2007-2015 Oracle Corporation 21 21 * 22 22 * This file is part of VirtualBox Open Source Edition (OSE), as … … 52 52 53 53 /** 54 * Maximum depth of a medium tree, to prevent stack overflows. 55 * XPCOM has a relatively low stack size for its workers, and we have 56 * to avoid crashes due to exceeding the limit both on reading and 57 * writing config files. 58 */ 59 #define SETTINGS_MEDIUM_DEPTH_MAX 300 60 61 /** 54 62 * Maximum depth of the snapshot tree, to prevent stack overflows. 55 63 * XPCOM has a relatively low stack size for its workers, and we have 56 64 * to avoid crashes due to exceeding the limit both on reading and 57 * writing config files. 65 * writing config files. The bottleneck is reading config files with 66 * deep snapshot nesting, as libxml2 needs quite some stack space, 67 * so with the current stack size the margin isn't big. 58 68 */ 59 69 #define SETTINGS_SNAPSHOT_DEPTH_MAX 250 … … 144 154 }; 145 155 156 extern const struct Medium g_MediumEmpty; 157 146 158 /** 147 159 * A media registry. Starting with VirtualBox 3.3, this can appear in both the … … 229 241 ~ConfigFileBase(); 230 242 243 typedef enum {Error, HardDisk, DVDImage, FloppyImage} MediaType; 244 245 static const char *stringifyMediaType(MediaType t); 231 246 void parseUUID(com::Guid &guid, 232 247 const com::Utf8Str &strUUID) const; 233 248 void parseTimestamp(RTTIMESPEC ×tamp, 234 249 const com::Utf8Str &str) const; 235 236 com::Utf8Str makeString(const RTTIMESPEC &tm); 250 com::Utf8Str stringifyTimestamp(const RTTIMESPEC &tm) const; 237 251 238 252 void readExtraData(const xml::ElementNode &elmExtraData, … … 240 254 void readUSBDeviceFilters(const xml::ElementNode &elmDeviceFilters, 241 255 USBDeviceFiltersList &ll); 242 typedef enum {Error, HardDisk, DVDImage, FloppyImage} MediaType;243 void readMedium(MediaType t, const xml::ElementNode &elmMedium, MediaList &llMedia);256 void readMediumOne(MediaType t, const xml::ElementNode &elmMedium, Medium &med); 257 void readMedium(MediaType t, uint32_t depth, const xml::ElementNode &elmMedium, Medium &med); 244 258 void readMediaRegistry(const xml::ElementNode &elmMediaRegistry, MediaRegistry &mr); 245 259 void readNATForwardRuleList(const xml::ElementNode &elmParent, NATRuleList &llRules); … … 253 267 const USBDeviceFiltersList &ll, 254 268 bool fHostMode); 255 void buildMedium( xml::ElementNode &elmMedium,256 DeviceType_T devType,257 const Medium &m,258 uint32_t level);269 void buildMedium(MediaType t, 270 uint32_t depth, 271 xml::ElementNode &elmMedium, 272 const Medium &mdm); 259 273 void buildMediaRegistry(xml::ElementNode &elmParent, 260 274 const MediaRegistry &mr); … … 1151 1165 struct Snapshot 1152 1166 { 1167 Snapshot() 1168 { 1169 RTTimeSpecSetNano(×tamp, 0); 1170 } 1171 1153 1172 bool operator==(const Snapshot &s) const; 1154 1173 … … 1225 1244 com::Utf8Str ovIcon; 1226 1245 }; 1246 1247 extern const struct Snapshot g_SnapshotEmpty; 1227 1248 1228 1249 /** -
trunk/src/VBox/Main/include/MediumImpl.h
r54885 r54948 1 1 /* $Id$ */ 2 3 2 /** @file 4 *5 3 * VirtualBox COM class implementation 6 4 */ … … 72 70 73 71 // initializer used when loading settings 72 HRESULT initOne(Medium *aParent, 73 DeviceType_T aDeviceType, 74 const Guid &uuidMachineRegistry, 75 const settings::Medium &data, 76 const Utf8Str &strMachineFolder); 74 77 HRESULT init(VirtualBox *aVirtualBox, 75 78 Medium *aParent, … … 77 80 const Guid &uuidMachineRegistry, 78 81 const settings::Medium &data, 79 const Utf8Str &strMachineFolder); 82 const Utf8Str &strMachineFolder, 83 AutoWriteLock &mediaTreeLock); 80 84 81 85 // initializer for host floppy/DVD … … 109 113 110 114 /* handles caller/locking itself */ 111 bool i_addRegistry(const Guid& id, bool fRecurse); 115 bool i_addRegistry(const Guid &id); 116 /* handles caller/locking itself, caller is responsible for tree lock */ 117 bool i_addRegistryRecursive(const Guid &id); 112 118 /* handles caller/locking itself */ 113 bool i_removeRegistry(const Guid& id, bool fRecurse); 119 bool i_removeRegistry(const Guid& id); 120 /* handles caller/locking itself, caller is responsible for tree lock */ 121 bool i_removeRegistryRecursive(const Guid& id); 114 122 bool i_isInRegistry(const Guid& id); 115 123 bool i_getFirstRegistryMachineId(Guid &uuid) const; … … 135 143 HRESULT i_updatePath(const Utf8Str &strOldPath, const Utf8Str &strNewPath); 136 144 145 /* handles caller/locking itself */ 137 146 ComObjPtr<Medium> i_getBase(uint32_t *aLevel = NULL); 147 /* handles caller/locking itself */ 148 uint32_t i_getDepth(); 138 149 139 150 bool i_isReadOnly(); 140 151 void i_updateId(const Guid &id); 141 152 153 void i_saveSettingsOne(settings::Medium &data, 154 const Utf8Str &strHardDiskFolder); 142 155 HRESULT i_saveSettings(settings::Medium &data, 143 156 const Utf8Str &strHardDiskFolder); -
trunk/src/VBox/Main/include/SnapshotImpl.h
r50504 r54948 1 1 /* $Id$ */ 2 3 2 /** @file 4 *5 3 * VirtualBox COM class implementation 6 4 */ 7 5 8 6 /* 9 * Copyright (C) 2006-201 3Oracle Corporation7 * Copyright (C) 2006-2015 Oracle Corporation 10 8 * 11 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 92 90 Snapshot *pSnapshotToIgnore); 93 91 94 HRESULT i_saveSnapshot(settings::Snapshot &data, bool aAttrsOnly); 95 HRESULT i_saveSnapshotImpl(settings::Snapshot &data, bool aAttrsOnly); 92 HRESULT i_saveSnapshot(settings::Snapshot &data) const; 93 HRESULT i_saveSnapshotImpl(settings::Snapshot &data) const; 94 HRESULT i_saveSnapshotImplOne(settings::Snapshot &data) const; 96 95 96 HRESULT i_uninitOne(AutoWriteLock &writeLock, 97 CleanupMode_T cleanupMode, 98 MediaList &llMedia, 99 std::list<Utf8Str> &llFilenames); 97 100 HRESULT i_uninitRecursively(AutoWriteLock &writeLock, 98 101 CleanupMode_T cleanupMode, -
trunk/src/VBox/Main/include/VirtualBoxImpl.h
r54438 r54948 93 93 HRESULT initMachines(); 94 94 HRESULT initMedia(const Guid &uuidMachineRegistry, 95 const settings::MediaRegistry mediaRegistry,95 const settings::MediaRegistry &mediaRegistry, 96 96 const Utf8Str &strMachineFolder); 97 97 void uninit(); … … 230 230 HRESULT i_saveSettings(); 231 231 void i_markRegistryModified(const Guid &uuid); 232 void i_unmarkRegistryModified(const Guid &uuid); 232 233 void i_saveModifiedRegistries(); 233 234 static const com::Utf8Str &i_getVersionNormalized(); -
trunk/src/VBox/Main/src-server/MachineImpl.cpp
r54927 r54948 4273 4273 } 4274 4274 4275 /* Save modified registries, but skip this machine as it's the caller's 4276 * job to save its settings like all other settings changes. */ 4277 mParent->i_unmarkRegistryModified(i_getId()); 4275 4278 mParent->i_saveModifiedRegistries(); 4276 4279 … … 4353 4356 alock.release(); 4354 4357 4358 /* Save modified registries, but skip this machine as it's the caller's 4359 * job to save its settings like all other settings changes. */ 4360 mParent->i_unmarkRegistryModified(i_getId()); 4355 4361 mParent->i_saveModifiedRegistries(); 4356 4362 … … 4794 4800 multiLock.release(); 4795 4801 4802 /* Save modified registries, but skip this machine as it's the caller's 4803 * job to save its settings like all other settings changes. */ 4804 mParent->i_unmarkRegistryModified(i_getId()); 4796 4805 mParent->i_saveModifiedRegistries(); 4797 4806 … … 5118 5127 if (cSnapshots) 5119 5128 { 5120 // autoCleanup must be true here, or we would have failed above5121 5122 5129 // add the media from the medium attachments of the snapshots to llMedia 5123 5130 // as well, after the "main" machine media; Snapshot::uninitRecursively() … … 9278 9285 if (puuidRegistry) 9279 9286 // caller wants registry ID to be set on all attached media (OVF import case) 9280 medium->i_addRegistry(*puuidRegistry , false /* fRecurse */);9287 medium->i_addRegistry(*puuidRegistry); 9281 9288 } 9282 9289 … … 9963 9970 if (mData->mFirstSnapshot) 9964 9971 { 9965 settings::Snapshot snapNew; 9966 config.llFirstSnapshot.push_back(snapNew); 9967 9968 // get reference to the fresh copy of the snapshot on the list and 9969 // work on that copy directly to avoid excessive copying later 9970 settings::Snapshot &snap = config.llFirstSnapshot.front(); 9971 9972 rc = mData->mFirstSnapshot->i_saveSnapshot(snap, false /*aAttrsOnly*/); 9972 // the settings use a list for "the first snapshot" 9973 config.llFirstSnapshot.push_back(settings::g_SnapshotEmpty); 9974 9975 // get reference to the snapshot on the list and work on that 9976 // element straight in the list to avoid excessive copying later 9977 rc = mData->mFirstSnapshot->i_saveSnapshot(config.llFirstSnapshot.back()); 9973 9978 if (FAILED(rc)) throw rc; 9974 9979 } … … 10473 10478 uuid = mParent->i_getGlobalRegistryId(); // VirtualBox global registry UUID 10474 10479 10475 if (pMedium->i_addRegistry(uuid , false /* fRecurse */))10480 if (pMedium->i_addRegistry(uuid)) 10476 10481 mParent->i_markRegistryModified(uuid); 10477 10482 … … 10480 10485 if (pMedium != pBase) 10481 10486 { 10482 if (pBase->i_addRegistry(uuid, true /* fRecurse */)) 10487 /* Tree lock needed by Medium::addRegistry when recursing. */ 10488 AutoReadLock treeLock(&mParent->i_getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS); 10489 if (pBase->i_addRegistryRecursive(uuid)) 10490 { 10491 treeLock.release(); 10483 10492 mParent->i_markRegistryModified(uuid); 10493 } 10484 10494 } 10485 10495 } -
trunk/src/VBox/Main/src-server/MachineImplCloneVM.cpp
r54645 r54948 1342 1342 mlock.acquire(); 1343 1343 } 1344 pMedium->i_addRegistry(uuid , false /* fRecurse */);1344 pMedium->i_addRegistry(uuid); 1345 1345 } 1346 1346 /* Check if a snapshot folder is necessary and if so doesn't already -
trunk/src/VBox/Main/src-server/MediumImpl.cpp
r54945 r54948 1213 1213 /** 1214 1214 * Initializes the medium object by loading its data from the given settings 1215 * node. In this mode, the medium will always be opened read/write.1215 * node. The medium will always be opened read/write. 1216 1216 * 1217 1217 * In this case, since we're loading from a registry, uuidMachineRegistry is … … 1219 1219 * loading from a per-machine registry. 1220 1220 * 1221 * @param aVirtualBox VirtualBox object.1222 1221 * @param aParent Parent medium disk or NULL for a root (base) medium. 1223 1222 * @param aDeviceType Device type of the medium. 1224 1223 * @param uuidMachineRegistry The registry to which this medium should be 1225 1224 * added (global registry UUID or machine UUID). 1226 * @param aNodeConfiguration settings.1225 * @param data Configuration settings. 1227 1226 * @param strMachineFolder The machine folder with which to resolve relative paths; 1228 1227 * if empty, then we use the VirtualBox home directory … … 1230 1229 * @note Locks the medium tree for writing. 1231 1230 */ 1232 HRESULT Medium::init(VirtualBox *aVirtualBox, 1233 Medium *aParent, 1234 DeviceType_T aDeviceType, 1235 const Guid &uuidMachineRegistry, 1236 const settings::Medium &data, 1237 const Utf8Str &strMachineFolder) 1238 { 1239 using namespace settings; 1240 1241 AssertReturn(aVirtualBox, E_INVALIDARG); 1242 1243 /* Enclose the state transition NotReady->InInit->Ready */ 1244 AutoInitSpan autoInitSpan(this); 1245 AssertReturn(autoInitSpan.isOk(), E_FAIL); 1246 1247 HRESULT rc = S_OK; 1248 1249 unconst(m->pVirtualBox) = aVirtualBox; 1231 HRESULT Medium::initOne(Medium *aParent, 1232 DeviceType_T aDeviceType, 1233 const Guid &uuidMachineRegistry, 1234 const settings::Medium &data, 1235 const Utf8Str &strMachineFolder) 1236 { 1237 HRESULT rc; 1250 1238 1251 1239 if (uuidMachineRegistry.isValid() && !uuidMachineRegistry.isZero()) … … 1258 1246 // differencing medium: add to parent 1259 1247 AutoWriteLock treeLock(m->pVirtualBox->i_getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS); 1260 m->pParent = aParent;1261 aParent->m->llChildren.push_back(this);1248 // no need to check maximum depth as settings reading did it 1249 i_setParent(aParent); 1262 1250 } 1263 1251 … … 1369 1357 m->strLocationFull.c_str(), m->strFormat.c_str(), m->id.raw())); 1370 1358 1359 return S_OK; 1360 } 1361 1362 /** 1363 * Initializes the medium object and its children by loading its data from the 1364 * given settings node. The medium will always be opened read/write. 1365 * 1366 * In this case, since we're loading from a registry, uuidMachineRegistry is 1367 * always set: it's either the global registry UUID or a machine UUID when 1368 * loading from a per-machine registry. 1369 * 1370 * @param aVirtualBox VirtualBox object. 1371 * @param aParent Parent medium disk or NULL for a root (base) medium. 1372 * @param aDeviceType Device type of the medium. 1373 * @param uuidMachineRegistry The registry to which this medium should be added (global registry UUID or machine UUID). 1374 * @param data Configuration settings. 1375 * @param strMachineFolder The machine folder with which to resolve relative paths; if empty, then we use the VirtualBox home directory 1376 * 1377 * @note Locks the medium tree for writing. 1378 */ 1379 HRESULT Medium::init(VirtualBox *aVirtualBox, 1380 Medium *aParent, 1381 DeviceType_T aDeviceType, 1382 const Guid &uuidMachineRegistry, 1383 const settings::Medium &data, 1384 const Utf8Str &strMachineFolder, 1385 AutoWriteLock &mediaTreeLock) 1386 { 1387 using namespace settings; 1388 1389 Assert(aVirtualBox->i_getMediaTreeLockHandle().isWriteLockOnCurrentThread()); 1390 AssertReturn(aVirtualBox, E_INVALIDARG); 1391 1392 /* Enclose the state transition NotReady->InInit->Ready */ 1393 AutoInitSpan autoInitSpan(this); 1394 AssertReturn(autoInitSpan.isOk(), E_FAIL); 1395 1396 unconst(m->pVirtualBox) = aVirtualBox; 1397 1398 // Do not inline this method call, as the purpose of having this separate 1399 // is to save on stack size. Less local variables are the key for reaching 1400 // deep recursion levels with small stack (XPCOM/g++ without optimization). 1401 HRESULT rc = initOne(aParent, aDeviceType, uuidMachineRegistry, data, strMachineFolder); 1402 1403 1371 1404 /* Don't call Medium::i_queryInfo for registered media to prevent the calling 1372 1405 * thread (i.e. the VirtualBox server startup thread) from an unexpected … … 1390 1423 uuidMachineRegistry, 1391 1424 med, // child data 1392 strMachineFolder); 1425 strMachineFolder, 1426 mediaTreeLock); 1393 1427 if (FAILED(rc)) break; 1394 1428 1395 AutoWriteLock treeLock(aVirtualBox->i_getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS); 1396 1397 rc = m->pVirtualBox->i_registerMedium(pMedium, &pMedium, treeLock); 1429 rc = m->pVirtualBox->i_registerMedium(pMedium, &pMedium, mediaTreeLock); 1398 1430 if (FAILED(rc)) break; 1399 1431 } … … 3073 3105 m->strLocationFull.c_str(), m->backRefs.size()); 3074 3106 3075 if ( m->llChildren.size() != 0)3107 if (i_getChildren().size() != 0) 3076 3108 return setError(VBOX_E_INVALID_OBJECT_STATE, 3077 3109 tr("Cannot encrypt medium '%s' because it has %d children"), 3078 m->strLocationFull.c_str(), m->llChildren.size());3110 m->strLocationFull.c_str(), i_getChildren().size()); 3079 3111 3080 3112 /* Build the medium lock list. */ … … 3127 3159 break; 3128 3160 } 3129 else if (pMedium-> m->llChildren.size() > 1)3161 else if (pMedium->i_getChildren().size() > 1) 3130 3162 { 3131 3163 rc = setError(VBOX_E_INVALID_OBJECT_STATE, 3132 3164 tr("Cannot encrypt medium '%s' because it has %d children"), 3133 pMedium->m->strLocationFull.c_str(), pMedium-> m->llChildren.size());3165 pMedium->m->strLocationFull.c_str(), pMedium->i_getChildren().size()); 3134 3166 break; 3135 3167 } … … 3473 3505 * See getFirstRegistryMachineId() for details. 3474 3506 * 3475 * If fRecurse == true, then the media tree lock must be held for reading.3476 *3477 3507 * @param id 3478 * @param fRecurse If true, recurses into child media to make sure the whole tree has registries in sync.3479 3508 * @return true if the registry was added; false if the given id was already on the list. 3480 3509 */ 3481 bool Medium::i_addRegistry(const Guid& id , bool fRecurse)3510 bool Medium::i_addRegistry(const Guid& id) 3482 3511 { 3483 3512 AutoCaller autoCaller(this); … … 3511 3540 m->llRegistryIDs.push_back(id); 3512 3541 3513 if (fRecurse)3514 {3515 // Get private list of children and release medium lock straight away.3516 MediaList llChildren(m->llChildren);3517 alock.release();3518 3519 for (MediaList::iterator it = llChildren.begin();3520 it != llChildren.end();3521 ++it)3522 {3523 Medium *pChild = *it;3524 fAdd |= pChild->i_addRegistry(id, true);3525 }3526 }3527 3528 3542 return fAdd; 3529 3543 } 3530 3544 3531 3545 /** 3532 * Removes the given UUID from the list of media registry UUIDs. Returns true 3533 * if found or false if not. 3534 * 3535 * If fRecurse == true, then the media tree lock must be held for reading. 3546 * This adds the given UUID to the list of media registries in which this 3547 * medium should be registered. The UUID can either be a machine UUID, 3548 * to add a machine registry, or the global registry UUID as returned by 3549 * VirtualBox::getGlobalRegistryId(). This recurses over all children. 3550 * 3551 * Note that for hard disks, this method does nothing if the medium is 3552 * already in another registry to avoid having hard disks in more than 3553 * one registry, which causes trouble with keeping diff images in sync. 3554 * See getFirstRegistryMachineId() for details. 3555 * 3556 * @note the caller must hold the media tree lock for reading. 3536 3557 * 3537 3558 * @param id 3538 * @param fRecurse If true, recurses into child media to make sure the whole tree has registries in sync. 3539 * @return 3540 */ 3541 bool Medium::i_removeRegistry(const Guid& id, bool fRecurse) 3559 * @return true if the registry was added; false if the given id was already on the list. 3560 */ 3561 bool Medium::i_addRegistryRecursive(const Guid &id) 3562 { 3563 AutoCaller autoCaller(this); 3564 if (FAILED(autoCaller.rc())) 3565 return false; 3566 3567 bool fAdd = i_addRegistry(id); 3568 3569 // protected by the medium tree lock held by our original caller 3570 for (MediaList::const_iterator it = i_getChildren().begin(); 3571 it != i_getChildren().end(); 3572 ++it) 3573 { 3574 Medium *pChild = *it; 3575 fAdd |= pChild->i_addRegistryRecursive(id); 3576 } 3577 3578 return fAdd; 3579 } 3580 3581 /** 3582 * Removes the given UUID from the list of media registry UUIDs of this medium. 3583 * 3584 * @param id 3585 * @return true if the UUID was found or false if not. 3586 */ 3587 bool Medium::i_removeRegistry(const Guid &id) 3542 3588 { 3543 3589 AutoCaller autoCaller(this); … … 3548 3594 bool fRemove = false; 3549 3595 3596 // @todo r=klaus eliminate this code, replace it by using find. 3550 3597 for (GuidList::iterator it = m->llRegistryIDs.begin(); 3551 3598 it != m->llRegistryIDs.end(); … … 3554 3601 if ((*it) == id) 3555 3602 { 3603 // getting away with this as the iterator isn't used after 3556 3604 m->llRegistryIDs.erase(it); 3557 3605 fRemove = true; … … 3560 3608 } 3561 3609 3562 if (fRecurse) 3563 { 3564 // Get private list of children and release medium lock straight away. 3565 MediaList llChildren(m->llChildren); 3566 alock.release(); 3567 3568 for (MediaList::iterator it = llChildren.begin(); 3569 it != llChildren.end(); 3570 ++it) 3571 { 3572 Medium *pChild = *it; 3573 fRemove |= pChild->i_removeRegistry(id, true); 3574 } 3610 return fRemove; 3611 } 3612 3613 /** 3614 * Removes the given UUID from the list of media registry UUIDs, for this 3615 * medium and all its children recursively. 3616 * 3617 * @note the caller must hold the media tree lock for reading. 3618 * 3619 * @param id 3620 * @return true if the UUID was found or false if not. 3621 */ 3622 bool Medium::i_removeRegistryRecursive(const Guid &id) 3623 { 3624 AutoCaller autoCaller(this); 3625 if (FAILED(autoCaller.rc())) 3626 return false; 3627 3628 bool fRemove = i_removeRegistry(id); 3629 3630 // protected by the medium tree lock held by our original caller 3631 for (MediaList::const_iterator it = i_getChildren().begin(); 3632 it != i_getChildren().end(); 3633 ++it) 3634 { 3635 Medium *pChild = *it; 3636 fRemove |= pChild->i_removeRegistryRecursive(id); 3575 3637 } 3576 3638 … … 3586 3648 * @return 3587 3649 */ 3588 bool Medium::i_isInRegistry(const Guid& id) 3589 { 3650 bool Medium::i_isInRegistry(const Guid &id) 3651 { 3652 // @todo r=klaus eliminate this code, replace it by using find. 3590 3653 for (GuidList::const_iterator it = m->llRegistryIDs.begin(); 3591 3654 it != m->llRegistryIDs.end(); … … 3832 3895 return &m->backRefs.front().machineId; 3833 3896 3834 for (MediaList:: iterator it = m->llChildren.begin();3835 it != m->llChildren.end();3897 for (MediaList::const_iterator it = i_getChildren().begin(); 3898 it != i_getChildren().end(); 3836 3899 ++it) 3837 3900 { … … 3981 4044 3982 4045 return pBase; 4046 } 4047 4048 /** 4049 * Returns the depth of this medium in the media chain. 4050 * 4051 * @note Locks medium tree for reading. 4052 */ 4053 uint32_t Medium::i_getDepth() 4054 { 4055 /* it is possible that some previous/concurrent uninit has already cleared 4056 * the pVirtualBox reference, and in this case we don't need to continue */ 4057 ComObjPtr<VirtualBox> pVirtualBox(m->pVirtualBox); 4058 if (!pVirtualBox) 4059 return 1; 4060 4061 /* we access mParent */ 4062 AutoReadLock treeLock(pVirtualBox->i_getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS); 4063 4064 uint32_t cDepth = 0; 4065 ComObjPtr<Medium> pMedium(this); 4066 while (!pMedium.isNull()) 4067 { 4068 AutoCaller autoCaller(this); 4069 AssertReturn(autoCaller.isOk(), cDepth + 1); 4070 4071 pMedium = pMedium->m->pParent; 4072 cDepth++; 4073 } 4074 4075 return cDepth; 3983 4076 } 3984 4077 … … 4041 4134 4042 4135 /** 4043 * Saves medium data by appending a new child node to the given 4044 * parent XML settings node. 4136 * Saves the settings of one medium. 4137 * 4138 * @note Caller MUST take care of the medium tree lock and caller. 4045 4139 * 4046 4140 * @param data Settings struct to be updated. 4047 4141 * @param strHardDiskFolder Folder for which paths should be relative. 4048 * 4049 * @note Locks this object, medium tree and children for reading. 4050 */ 4051 HRESULT Medium::i_saveSettings(settings::Medium &data, 4052 const Utf8Str &strHardDiskFolder) 4053 { 4054 AutoCaller autoCaller(this); 4055 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 4056 4057 /* we access mParent */ 4058 AutoReadLock treeLock(m->pVirtualBox->i_getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS); 4059 4142 */ 4143 void Medium::i_saveSettingsOne(settings::Medium &data, const Utf8Str &strHardDiskFolder) 4144 { 4060 4145 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 4061 4146 … … 4117 4202 if (m->pParent.isNull()) 4118 4203 data.hdType = m->type; 4204 } 4205 4206 /** 4207 * Saves medium data by putting it into the provided data structure. 4208 * Recurses over all children to save their settings, too. 4209 * 4210 * @param data Settings struct to be updated. 4211 * @param strHardDiskFolder Folder for which paths should be relative. 4212 * 4213 * @note Locks this object, medium tree and children for reading. 4214 */ 4215 HRESULT Medium::i_saveSettings(settings::Medium &data, 4216 const Utf8Str &strHardDiskFolder) 4217 { 4218 AutoCaller autoCaller(this); 4219 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 4220 4221 /* we access mParent */ 4222 AutoReadLock treeLock(m->pVirtualBox->i_getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS); 4223 4224 i_saveSettingsOne(data, strHardDiskFolder); 4119 4225 4120 4226 /* save all children */ 4227 settings::MediaList &llSettingsChildren = data.llChildren; 4121 4228 for (MediaList::const_iterator it = i_getChildren().begin(); 4122 4229 it != i_getChildren().end(); 4123 4230 ++it) 4124 4231 { 4125 settings::Medium med; 4126 HRESULT rc = (*it)->i_saveSettings(med, strHardDiskFolder); 4127 AssertComRCReturnRC(rc); 4128 data.llChildren.push_back(med); 4232 // Use the element straight in the list to reduce both unnecessary 4233 // deep copying (when unwinding the recursion the entire medium 4234 // settings sub-tree is copied) and the stack footprint (the settings 4235 // need almost 1K, and there can be VMs with long image chains. 4236 llSettingsChildren.push_back(settings::g_MediumEmpty); 4237 HRESULT rc = (*it)->i_saveSettings(llSettingsChildren.back(), strHardDiskFolder); 4238 if (FAILED(rc)) 4239 { 4240 llSettingsChildren.pop_back(); 4241 return rc; 4242 } 4129 4243 } 4130 4244 … … 6120 6234 if (m->pParent) 6121 6235 i_deparent(); 6236 6237 if (!pParent.isNull()) 6238 if (pParent->i_getDepth() >= SETTINGS_MEDIUM_DEPTH_MAX) 6239 { 6240 AutoReadLock plock(pParent COMMA_LOCKVAL_SRC_POS); 6241 throw setError(VBOX_E_INVALID_OBJECT_STATE, 6242 tr("Cannot open differencing image for medium '%s', because it exceeds the medium tree depth limit. Please merge some images which you no longer need"), 6243 pParent->m->strLocationFull.c_str()); 6244 } 6122 6245 i_setParent(pParent); 6123 6246 … … 6353 6476 { 6354 6477 // re-associate with the parent as we are still relatives in the registry 6355 m->pParent = pParentBackup; 6356 m->pParent->m->llChildren.push_back(this); 6478 i_setParent(pParentBackup); 6357 6479 } 6358 6480 } … … 7346 7468 try 7347 7469 { 7470 if (i_getDepth() >= SETTINGS_MEDIUM_DEPTH_MAX) 7471 { 7472 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 7473 throw setError(VBOX_E_INVALID_OBJECT_STATE, 7474 tr("Cannot create differencing image for medium '%s', because it exceeds the medium tree depth limit. Please merge some images which you no longer need"), 7475 m->strLocationFull.c_str()); 7476 } 7477 7348 7478 /* Lock both in {parent,child} order. */ 7349 7479 AutoMultiWriteLock2 mediaLock(this, pTarget COMMA_LOCKVAL_SRC_POS); … … 7467 7597 Assert(pTarget->m->pParent.isNull()); 7468 7598 7469 /* associate the child with the parent */ 7470 pTarget->m->pParent = this; 7471 m->llChildren.push_back(pTarget); 7472 7473 /** @todo r=klaus neither target nor base() are locked, 7474 * potential race! */ 7599 /* associate child with the parent, maximum depth was checked above */ 7600 pTarget->i_setParent(this); 7601 7475 7602 /* diffs for immutable media are auto-reset by default */ 7476 pTarget->m->autoReset = (i_getBase()->m->type == MediumType_Immutable); 7603 bool fAutoReset; 7604 { 7605 ComObjPtr<Medium> pBase = i_getBase(); 7606 AutoReadLock block(pBase COMMA_LOCKVAL_SRC_POS); 7607 fAutoReset = (pBase->m->type == MediumType_Immutable); 7608 } 7609 { 7610 AutoWriteLock tlock(pTarget COMMA_LOCKVAL_SRC_POS); 7611 pTarget->m->autoReset = fAutoReset; 7612 } 7477 7613 7478 7614 /* register with mVirtualBox as the last step and move to … … 7548 7684 try 7549 7685 { 7686 if (!task.mParentForTarget.isNull()) 7687 if (task.mParentForTarget->i_getDepth() >= SETTINGS_MEDIUM_DEPTH_MAX) 7688 { 7689 AutoReadLock plock(task.mParentForTarget COMMA_LOCKVAL_SRC_POS); 7690 throw setError(VBOX_E_INVALID_OBJECT_STATE, 7691 tr("Cannot merge image for medium '%s', because it exceeds the medium tree depth limit. Please merge some images which you no longer need"), 7692 task.mParentForTarget->m->strLocationFull.c_str()); 7693 } 7694 7550 7695 PVBOXHDD hdd; 7551 7696 int vrc = VDCreate(m->vdDiskIfaces, i_convertDeviceType(), &hdd); … … 7702 7847 AssertComRC(rc2); 7703 7848 7704 /* then, reparent it and disconnect the deleted branch at 7705 * both ends (chain->parent() is source's parent)*/7849 /* then, reparent it and disconnect the deleted branch at both ends 7850 * (chain->parent() is source's parent). Depth check above. */ 7706 7851 pTarget->i_deparent(); 7707 pTarget->m->pParent = task.mParentForTarget; 7708 if (pTarget->m->pParent) 7709 { 7710 pTarget->m->pParent->m->llChildren.push_back(pTarget); 7852 pTarget->i_setParent(task.mParentForTarget); 7853 if (task.mParentForTarget) 7711 7854 i_deparent(); 7712 }7713 7855 7714 7856 /* then, register again */ … … 7743 7885 7744 7886 pMedium->i_deparent(); // removes pMedium from source 7887 // no depth check, reduces depth 7745 7888 pMedium->i_setParent(pTarget); 7746 7889 } … … 7859 8002 try 7860 8003 { 8004 if (!pParent.isNull()) 8005 if (pParent->i_getDepth() >= SETTINGS_MEDIUM_DEPTH_MAX) 8006 { 8007 AutoReadLock plock(pParent COMMA_LOCKVAL_SRC_POS); 8008 throw setError(VBOX_E_INVALID_OBJECT_STATE, 8009 tr("Cannot clone image for medium '%s', because it exceeds the medium tree depth limit. Please merge some images which you no longer need"), 8010 pParent->m->strLocationFull.c_str()); 8011 } 8012 7861 8013 /* Lock all in {parent,child} order. The lock is also used as a 7862 8014 * signal from the task initiator (which releases it only after … … 7983 8135 } 7984 8136 7985 /* * @todo r=klaus target isn't locked, race getting the state*/8137 /* target isn't locked, but no changing data is accessed */ 7986 8138 if (task.midxSrcImageSame == UINT32_MAX) 7987 8139 { … … 8053 8205 if (pParent) 8054 8206 { 8055 /* associate the clone with the parent and deassociate 8056 * from VirtualBox */ 8057 pTarget->m->pParent = pParent; 8058 pParent->m->llChildren.push_back(pTarget); 8207 /* Associate the clone with the parent and deassociate 8208 * from VirtualBox. Depth check above. */ 8209 pTarget->i_setParent(pParent); 8059 8210 8060 8211 /* register with mVirtualBox as the last step and move to … … 8692 8843 try 8693 8844 { 8845 if (!pParent.isNull()) 8846 if (pParent->i_getDepth() >= SETTINGS_MEDIUM_DEPTH_MAX) 8847 { 8848 AutoReadLock plock(pParent COMMA_LOCKVAL_SRC_POS); 8849 throw setError(VBOX_E_INVALID_OBJECT_STATE, 8850 tr("Cannot import image for medium '%s', because it exceeds the medium tree depth limit. Please merge some images which you no longer need"), 8851 pParent->m->strLocationFull.c_str()); 8852 } 8853 8694 8854 /* Lock all in {parent,child} order. The lock is also used as a 8695 8855 * signal from the task initiator (which releases it only after … … 8799 8959 } 8800 8960 8801 /** @todo r=klaus target isn't locked, race getting the state */8802 8961 vrc = VDCopy(hdd, 8803 8962 VD_LAST_IMAGE, … … 8848 9007 if (pParent) 8849 9008 { 8850 /* associate the imported medium with the parent and deassociate 8851 * from VirtualBox */ 8852 m->pParent = pParent; 8853 pParent->m->llChildren.push_back(this); 9009 /* Associate the imported medium with the parent and deassociate 9010 * from VirtualBox. Depth check above. */ 9011 i_setParent(pParent); 8854 9012 8855 9013 /* register with mVirtualBox as the last step and move to -
trunk/src/VBox/Main/src-server/SnapshotImpl.cpp
r54438 r54948 1 1 /* $Id$ */ 2 2 /** @file 3 *4 3 * COM class implementation for Snapshot and SnapshotMachine in VBoxSVC. 5 4 */ … … 175 174 m->llChildren.clear(); // this unsets all the ComPtrs and probably calls delete 176 175 176 // since there is no guarantee anyone holds a reference to us except the 177 // list of children in our parent, make sure that the reference count 178 // will not drop to 0 before we've declared ourselves as uninitialized, 179 // otherwise there will be another uninit call which causes a self-deadlock 180 // because this uninit isn't complete yet. 181 ComObjPtr<Snapshot> pSnapshot(this); 177 182 if (m->pParent) 178 183 i_deparent(); … … 186 191 delete m; 187 192 m = NULL; 193 194 autoUninitSpan.setSucceeded(); 195 // see above, now the refcount may reach 0 196 pSnapshot.setNull(); 188 197 } 189 198 … … 725 734 726 735 /** 727 * Internal implementation for Snapshot::saveSnapshot (below). Caller has 728 * requested the snapshots tree (machine) lock. 729 * 730 * @param aNode 731 * @param aAttrsOnly 736 * Saves the settings attributes of one snapshot. 737 * 738 * @param data Target for saving snapshot settings. 732 739 * @return 733 740 */ 734 HRESULT Snapshot::i_saveSnapshotImpl (settings::Snapshot &data, bool aAttrsOnly)741 HRESULT Snapshot::i_saveSnapshotImplOne(settings::Snapshot &data) const 735 742 { 736 743 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); … … 740 747 data.timestamp = m->timeStamp; 741 748 data.strDescription = m->strDescription; 742 743 if (aAttrsOnly)744 return S_OK;745 749 746 750 // state file (only if this snapshot is online) … … 756 760 if (FAILED(rc)) return rc; 757 761 758 alock.release(); 759 760 data.llChildSnapshots.clear(); 761 762 if (m->llChildren.size()) 763 { 764 for (SnapshotsList::const_iterator it = m->llChildren.begin(); 765 it != m->llChildren.end(); 766 ++it) 762 return S_OK; 763 } 764 765 /** 766 * Internal implementation for Snapshot::saveSnapshot (below). Caller has 767 * requested the snapshots tree (machine) lock. 768 * 769 * @param data Target for saving snapshot settings. 770 * @return 771 */ 772 HRESULT Snapshot::i_saveSnapshotImpl(settings::Snapshot &data) const 773 { 774 HRESULT rc = i_saveSnapshotImplOne(data); 775 if (FAILED(rc)) 776 return rc; 777 778 settings::SnapshotsList &llSettingsChildren = data.llChildSnapshots; 779 for (SnapshotsList::const_iterator it = m->llChildren.begin(); 780 it != m->llChildren.end(); 781 ++it) 782 { 783 // Use the heap (indirectly through the list container) to reduce the 784 // stack footprint, avoiding local settings objects on the stack which 785 // need a lot of stack space. There can be VMs with deeply nested 786 // snapshots. The stack can be quite small, especially with XPCOM. 787 llSettingsChildren.push_back(settings::g_SnapshotEmpty); 788 Snapshot *pSnap = *it; 789 rc = pSnap->i_saveSnapshotImpl(llSettingsChildren.back()); 790 if (FAILED(rc)) 767 791 { 768 // Use the heap to reduce the stack footprint. Each recursion needs 769 // over 1K, and there can be VMs with deeply nested snapshots. The 770 // stack can be quite small, especially with XPCOM. 771 772 settings::Snapshot *snap = new settings::Snapshot(); 773 rc = (*it)->i_saveSnapshotImpl(*snap, aAttrsOnly); 774 if (FAILED(rc)) 775 { 776 delete snap; 777 return rc; 778 } 779 data.llChildSnapshots.push_back(*snap); 780 delete snap; 792 llSettingsChildren.pop_back(); 793 return rc; 781 794 } 782 795 } … … 786 799 787 800 /** 788 * Saves the given snapshot and all its children (unless \a aAttrsOnly is true). 789 * It is assumed that the given node is empty (unless \a aAttrsOnly is true). 790 * 791 * @param aNode <Snapshot> node to save the snapshot to. 792 * @param aSnapshot Snapshot to save. 793 * @param aAttrsOnly If true, only update user-changeable attrs. 794 */ 795 HRESULT Snapshot::i_saveSnapshot(settings::Snapshot &data, bool aAttrsOnly) 801 * Saves the given snapshot and all its children. 802 * It is assumed that the given node is empty. 803 * 804 * @param data Target for saving snapshot settings. 805 */ 806 HRESULT Snapshot::i_saveSnapshot(settings::Snapshot &data) const 796 807 { 797 808 // snapshots tree is protected by machine lock 798 809 AutoReadLock alock(m->pMachine COMMA_LOCKVAL_SRC_POS); 799 810 800 return i_saveSnapshotImpl(data , aAttrsOnly);811 return i_saveSnapshotImpl(data); 801 812 } 802 813 … … 804 815 * Part of the cleanup engine of Machine::Unregister(). 805 816 * 806 * This recursively removes all medium attachments from the snapshot's machine 807 * and returns the snapshot's saved state file name, if any, and then calls 808 * uninit() on "this" itself. 809 * 810 * This recurses into children first, so the given MediaList receives child 811 * media first before their parents. If the caller wants to close all media, 812 * they should go thru the list from the beginning to the end because media 813 * cannot be closed if they have children. 814 * 815 * This calls uninit() on itself, so the snapshots tree (beginning with a machine's pFirstSnapshot) becomes invalid after this. 816 * It does not alter the main machine's snapshot pointers (pFirstSnapshot, pCurrentSnapshot). 817 * This removes all medium attachments from the snapshot's machine and returns 818 * the snapshot's saved state file name, if any, and then calls uninit() on 819 * "this" itself. 817 820 * 818 821 * Caller must hold the machine write lock (which protects the snapshots tree!) … … 824 827 * @return 825 828 */ 826 HRESULT Snapshot::i_uninitRecursively(AutoWriteLock &writeLock, 827 CleanupMode_T cleanupMode, 828 MediaList &llMedia, 829 std::list<Utf8Str> &llFilenames) 830 { 831 Assert(m->pMachine->isWriteLockOnCurrentThread()); 832 833 HRESULT rc = S_OK; 834 835 // make a copy of the Guid for logging before we uninit ourselves 836 #ifdef LOG_ENABLED 837 Guid uuid = i_getId(); 838 Utf8Str name = i_getName(); 839 LogFlowThisFunc(("Entering for snapshot '%s' {%RTuuid}\n", name.c_str(), uuid.raw())); 840 #endif 841 842 // recurse into children first so that the child media appear on 843 // the list first; this way caller can close the media from the 844 // beginning to the end because parent media can't be closed if 845 // they have children 846 847 // make a copy of the children list since uninit() modifies it 848 SnapshotsList llChildrenCopy(m->llChildren); 849 for (SnapshotsList::iterator it = llChildrenCopy.begin(); 850 it != llChildrenCopy.end(); 851 ++it) 852 { 853 Snapshot *pChild = *it; 854 rc = pChild->i_uninitRecursively(writeLock, cleanupMode, llMedia, llFilenames); 855 if (FAILED(rc)) 856 return rc; 857 } 858 829 HRESULT Snapshot::i_uninitOne(AutoWriteLock &writeLock, 830 CleanupMode_T cleanupMode, 831 MediaList &llMedia, 832 std::list<Utf8Str> &llFilenames) 833 { 859 834 // now call detachAllMedia on the snapshot machine 860 rc = m->pMachine->i_detachAllMedia(writeLock,861 this /* pSnapshot */,862 cleanupMode,863 llMedia);835 HRESULT rc = m->pMachine->i_detachAllMedia(writeLock, 836 this /* pSnapshot */, 837 cleanupMode, 838 llMedia); 864 839 if (FAILED(rc)) 865 840 return rc; … … 884 859 } 885 860 886 this->i_beginSnapshotDelete(); 887 this->uninit(); 888 861 i_beginSnapshotDelete(); 862 uninit(); 863 864 return S_OK; 865 } 866 867 /** 868 * Part of the cleanup engine of Machine::Unregister(). 869 * 870 * This recursively removes all medium attachments from the snapshot's machine 871 * and returns the snapshot's saved state file name, if any, and then calls 872 * uninit() on "this" itself. 873 * 874 * This recurses into children first, so the given MediaList receives child 875 * media first before their parents. If the caller wants to close all media, 876 * they should go thru the list from the beginning to the end because media 877 * cannot be closed if they have children. 878 * 879 * This calls uninit() on itself, so the snapshots tree (beginning with a machine's pFirstSnapshot) becomes invalid after this. 880 * It does not alter the main machine's snapshot pointers (pFirstSnapshot, pCurrentSnapshot). 881 * 882 * Caller must hold the machine write lock (which protects the snapshots tree!) 883 * 884 * @param writeLock Machine write lock, which can get released temporarily here. 885 * @param cleanupMode Cleanup mode; see Machine::detachAllMedia(). 886 * @param llMedia List of media returned to caller, depending on cleanupMode. 887 * @param llFilenames 888 * @return 889 */ 890 HRESULT Snapshot::i_uninitRecursively(AutoWriteLock &writeLock, 891 CleanupMode_T cleanupMode, 892 MediaList &llMedia, 893 std::list<Utf8Str> &llFilenames) 894 { 895 Assert(m->pMachine->isWriteLockOnCurrentThread()); 896 897 HRESULT rc = S_OK; 898 899 // make a copy of the Guid for logging before we uninit ourselves 889 900 #ifdef LOG_ENABLED 890 LogFlowThisFunc(("Leaving for snapshot '%s' {%RTuuid}\n", name.c_str(), uuid.raw())); 901 Guid uuid = i_getId(); 902 Utf8Str name = i_getName(); 903 LogFlowThisFunc(("Entering for snapshot '%s' {%RTuuid}\n", name.c_str(), uuid.raw())); 891 904 #endif 892 905 893 return S_OK; 906 // Recurse into children first so that the child media appear on the list 907 // first; this way caller can close the media from the beginning to the end 908 // because parent media can't be closed if they have children and 909 // additionally it postpones the uninit() call until we no longer need 910 // anything from the list. Oh, and remember that the child removes itself 911 // from the list, so keep the iterator at the beginning. 912 for (SnapshotsList::const_iterator it = m->llChildren.begin(); 913 it != m->llChildren.end(); 914 it = m->llChildren.begin()) 915 { 916 Snapshot *pChild = *it; 917 rc = pChild->i_uninitRecursively(writeLock, cleanupMode, llMedia, llFilenames); 918 if (FAILED(rc)) 919 break; 920 } 921 922 if (SUCCEEDED(rc)) 923 rc = i_uninitOne(writeLock, cleanupMode, llMedia, llFilenames); 924 925 #ifdef LOG_ENABLED 926 LogFlowThisFunc(("Leaving for snapshot '%s' {%RTuuid}: %Rhrc\n", name.c_str(), uuid.raw(), rc)); 927 #endif 928 929 return rc; 894 930 } 895 931 -
trunk/src/VBox/Main/src-server/VirtualBoxImpl.cpp
r54438 r54948 650 650 */ 651 651 HRESULT VirtualBox::initMedia(const Guid &uuidRegistry, 652 const settings::MediaRegistry mediaRegistry,652 const settings::MediaRegistry &mediaRegistry, 653 653 const Utf8Str &strMachineFolder) 654 654 { … … 674 674 uuidRegistry, 675 675 xmlHD, // XML data; this recurses to processes the children 676 strMachineFolder); 676 strMachineFolder, 677 treeLock); 677 678 if (FAILED(rc)) return rc; 678 679 … … 694 695 uuidRegistry, 695 696 xmlDvd, 696 strMachineFolder); 697 strMachineFolder, 698 treeLock); 697 699 if (FAILED(rc)) return rc; 698 700 … … 714 716 uuidRegistry, 715 717 xmlFloppy, 716 strMachineFolder); 718 strMachineFolder, 719 treeLock); 717 720 if (FAILED(rc)) return rc; 718 721 … … 4014 4017 if (pMedium->i_isInRegistry(uuidRegistry)) 4015 4018 { 4016 settings::Medium med; 4017 rc = pMedium->i_saveSettings(med, strMachineFolder); // this recurses into child hard disks 4018 if (FAILED(rc)) throw rc; 4019 llTarget.push_back(med); 4019 llTarget.push_back(settings::g_MediumEmpty); 4020 rc = pMedium->i_saveSettings(llTarget.back(), strMachineFolder); // this recurses into child hard disks 4021 if (FAILED(rc)) 4022 { 4023 llTarget.pop_back(); 4024 throw rc; 4025 } 4020 4026 } 4021 4027 } … … 4482 4488 AutoWriteLock mlock(pMedium COMMA_LOCKVAL_SRC_POS); 4483 4489 4484 if (pMedium->i_removeRegistry (id, true /* fRecurse */))4490 if (pMedium->i_removeRegistryRecursive(id)) 4485 4491 { 4486 4492 // machine ID was found in base medium's registry list: … … 4491 4497 { 4492 4498 // 2) better registry found: then use that 4493 pMedium->i_addRegistry (*puuidBetter, true /* fRecurse */);4499 pMedium->i_addRegistryRecursive(*puuidBetter); 4494 4500 // 3) and make sure the registry is saved below 4495 4501 mlock.release(); … … 4497 4503 i_markRegistryModified(*puuidBetter); 4498 4504 tlock.acquire(); 4499 mlock. release();4505 mlock.acquire(); 4500 4506 } 4501 4507 } … … 4533 4539 if (SUCCEEDED(machineCaller.rc())) 4534 4540 ASMAtomicIncU64(&pMachine->uRegistryNeedsSaving); 4541 } 4542 } 4543 } 4544 4545 /** 4546 * Marks the registry for @a uuid as unmodified, so that it's not saved in 4547 * a later call to saveModifiedRegistries(). 4548 * 4549 * @param uuid 4550 */ 4551 void VirtualBox::i_unmarkRegistryModified(const Guid &uuid) 4552 { 4553 uint64_t uOld; 4554 if (uuid == i_getGlobalRegistryId()) 4555 { 4556 for (;;) 4557 { 4558 uOld = ASMAtomicReadU64(&m->uRegistryNeedsSaving); 4559 if (!uOld) 4560 break; 4561 if (ASMAtomicCmpXchgU64(&m->uRegistryNeedsSaving, 0, uOld)) 4562 break; 4563 ASMNopPause(); 4564 } 4565 } 4566 else 4567 { 4568 ComObjPtr<Machine> pMachine; 4569 HRESULT rc = i_findMachine(uuid, 4570 false /* fPermitInaccessible */, 4571 false /* aSetError */, 4572 &pMachine); 4573 if (SUCCEEDED(rc)) 4574 { 4575 AutoCaller machineCaller(pMachine); 4576 if (SUCCEEDED(machineCaller.rc())) 4577 { 4578 for (;;) 4579 { 4580 uOld = ASMAtomicReadU64(&pMachine->uRegistryNeedsSaving); 4581 if (!uOld) 4582 break; 4583 if (ASMAtomicCmpXchgU64(&pMachine->uRegistryNeedsSaving, 0, uOld)) 4584 break; 4585 ASMNopPause(); 4586 } 4587 } 4535 4588 } 4536 4589 } -
trunk/src/VBox/Main/xml/Settings.cpp
r54911 r54948 55 55 56 56 /* 57 * Copyright (C) 2007-201 4Oracle Corporation57 * Copyright (C) 2007-2015 Oracle Corporation 58 58 * 59 59 * This file is part of VirtualBox Open Source Edition (OSE), as … … 120 120 /** VirtualBox XML settings full version string ("x.y-platform") */ 121 121 #define VBOX_XML_VERSION_FULL VBOX_XML_VERSION "-" VBOX_XML_PLATFORM 122 123 const struct Snapshot settings::g_SnapshotEmpty; /* default ctor is OK */ 124 const struct Medium settings::g_MediumEmpty; /* default ctor is OK */ 122 125 123 126 //////////////////////////////////////////////////////////////////////////////// … … 377 380 378 381 /** 382 * Helper function to convert a MediaType enum value into string from. 383 * @param t 384 */ 385 /*static*/ 386 const char *ConfigFileBase::stringifyMediaType(MediaType t) 387 { 388 switch (t) 389 { 390 case HardDisk: 391 return "hard disk"; 392 case DVDImage: 393 return "DVD"; 394 case FloppyImage: 395 return "floppy"; 396 default: 397 AssertMsgFailed(("media type %d\n", t)); 398 return "UNKNOWN"; 399 } 400 } 401 402 /** 379 403 * Helper function that parses a UUID in string form into 380 404 * a com::Guid item. Accepts UUIDs both with and without … … 466 490 * @return 467 491 */ 468 com::Utf8Str ConfigFileBase:: makeString(const RTTIMESPEC &stamp)492 com::Utf8Str ConfigFileBase::stringifyTimestamp(const RTTIMESPEC &stamp) const 469 493 { 470 494 RTTIME time; … … 566 590 * @param t 567 591 * @param elmMedium 568 * @param llMedia 569 */ 570 void ConfigFileBase::readMedium(MediaType t, 571 const xml::ElementNode &elmMedium, // HardDisk node if root; if recursing, 572 // child HardDisk node or DiffHardDisk node for pre-1.4 573 MediaList &llMedia) // list to append medium to (root disk or child list) 592 * @param med 593 */ 594 void ConfigFileBase::readMediumOne(MediaType t, 595 const xml::ElementNode &elmMedium, 596 Medium &med) 574 597 { 575 598 // <HardDisk uuid="{5471ecdb-1ddb-4012-a801-6d98e226868b}" location="/mnt/innotek-unix/vdis/Windows XP.vdi" format="VDI" type="Normal"> 576 settings::Medium med; 599 577 600 Utf8Str strUUID; 578 601 if (!elmMedium.getAttributeValue("uuid", strUUID)) … … 726 749 elmMedium.getAttributeValue("Description", med.strDescription); // optional 727 750 728 // recurse to handle children729 xml::NodesLoop nl2(elmMedium );751 // handle medium properties 752 xml::NodesLoop nl2(elmMedium, "Property"); 730 753 const xml::ElementNode *pelmHDChild; 731 754 while ((pelmHDChild = nl2.forAllNodes())) 732 755 { 733 if ( t == HardDisk 734 && ( pelmHDChild->nameEquals("HardDisk") 735 || ( (m->sv < SettingsVersion_v1_4) 736 && (pelmHDChild->nameEquals("DiffHardDisk")) 737 ) 738 ) 739 ) 740 // recurse with this element and push the child onto our current children list 741 readMedium(t, 742 *pelmHDChild, 743 med.llChildren); 744 else if (pelmHDChild->nameEquals("Property")) 745 { 746 Utf8Str strPropName, strPropValue; 747 if ( pelmHDChild->getAttributeValue("name", strPropName) 748 && pelmHDChild->getAttributeValue("value", strPropValue) ) 749 med.properties[strPropName] = strPropValue; 750 else 751 throw ConfigFileError(this, pelmHDChild, N_("Required HardDisk/Property/@name or @value attribute is missing")); 752 } 753 } 754 755 llMedia.push_back(med); 756 Utf8Str strPropName, strPropValue; 757 if ( pelmHDChild->getAttributeValue("name", strPropName) 758 && pelmHDChild->getAttributeValue("value", strPropValue) ) 759 med.properties[strPropName] = strPropValue; 760 else 761 throw ConfigFileError(this, pelmHDChild, N_("Required HardDisk/Property/@name or @value attribute is missing")); 762 } 763 } 764 765 /** 766 * Reads a media registry entry from the main VirtualBox.xml file and recurses 767 * into children where applicable. 768 * 769 * @param t 770 * @param depth 771 * @param elmMedium 772 * @param med 773 */ 774 void ConfigFileBase::readMedium(MediaType t, 775 uint32_t depth, 776 const xml::ElementNode &elmMedium, // HardDisk node if root; if recursing, 777 // child HardDisk node or DiffHardDisk node for pre-1.4 778 Medium &med) // medium settings to fill out 779 { 780 if (depth > SETTINGS_MEDIUM_DEPTH_MAX) 781 throw ConfigFileError(this, &elmMedium, N_("Maximum medium tree depth of %u exceeded"), SETTINGS_MEDIUM_DEPTH_MAX); 782 783 // Do not inline this method call, as the purpose of having this separate 784 // is to save on stack size. Less local variables are the key for reaching 785 // deep recursion levels with small stack (XPCOM/g++ without optimization). 786 readMediumOne(t, elmMedium, med); 787 788 if (t != HardDisk) 789 return; 790 791 // recurse to handle children 792 MediaList &llSettingsChildren = med.llChildren; 793 xml::NodesLoop nl2(elmMedium, m->sv >= SettingsVersion_v1_4 ? "HardDisk" : "DiffHardDisk"); 794 const xml::ElementNode *pelmHDChild; 795 while ((pelmHDChild = nl2.forAllNodes())) 796 { 797 // recurse with this element and put the child at the end of the list. 798 // XPCOM has very small stack, avoid big local variables and use the 799 // list element. 800 llSettingsChildren.push_back(g_MediumEmpty); 801 readMedium(t, 802 depth + 1, 803 *pelmHDChild, 804 llSettingsChildren.back()); 805 } 756 806 } 757 807 … … 788 838 while ((pelmMedium = nl2.forAllNodes())) 789 839 { 790 if ( 791 && (pelmMedium->nameEquals("HardDisk"))792 )793 readMedium(t,794 *pelmMedium,795 mr.llHardDisks); // list to append hard disk data to: the root list796 else if ( 797 && (pelmMedium->nameEquals("Image"))798 )799 readMedium(t,800 *pelmMedium,801 mr.llDvdImages); // list to append dvd images to: the root list802 else if ( 803 && (pelmMedium->nameEquals("Image"))804 )805 readMedium(t,806 *pelmMedium,807 mr.llFloppyImages); // list to append floppy images to: the root list840 if ( t == HardDisk 841 && (pelmMedium->nameEquals("HardDisk"))) 842 { 843 mr.llHardDisks.push_back(g_MediumEmpty); 844 readMedium(t, 1, *pelmMedium, mr.llHardDisks.back()); 845 } 846 else if ( t == DVDImage 847 && (pelmMedium->nameEquals("Image"))) 848 { 849 mr.llDvdImages.push_back(g_MediumEmpty); 850 readMedium(t, 1, *pelmMedium, mr.llDvdImages.back()); 851 } 852 else if ( t == FloppyImage 853 && (pelmMedium->nameEquals("Image"))) 854 { 855 mr.llFloppyImages.push_back(g_MediumEmpty); 856 readMedium(t, 1, *pelmMedium, mr.llFloppyImages.back()); 857 } 808 858 } 809 859 } … … 1086 1136 * MainConfigFile::write(). 1087 1137 * 1138 * @param t 1139 * @param depth 1088 1140 * @param elmMedium 1089 * @param m 1090 * @param level 1091 */ 1092 void ConfigFileBase::buildMedium(xml::ElementNode &elmMedium, 1093 DeviceType_T devType, 1094 const Medium &mdm, 1095 uint32_t level) // 0 for "root" call, incremented with each recursion 1096 { 1141 * @param mdm 1142 */ 1143 void ConfigFileBase::buildMedium(MediaType t, 1144 uint32_t depth, 1145 xml::ElementNode &elmMedium, 1146 const Medium &mdm) 1147 { 1148 if (depth > SETTINGS_MEDIUM_DEPTH_MAX) 1149 throw ConfigFileError(this, &elmMedium, N_("Maximum medium tree depth of %u exceeded"), SETTINGS_MEDIUM_DEPTH_MAX); 1150 1097 1151 xml::ElementNode *pelmMedium; 1098 1152 1099 if ( devType == DeviceType_HardDisk)1153 if (t == HardDisk) 1100 1154 pelmMedium = elmMedium.createChild("HardDisk"); 1101 1155 else … … 1106 1160 pelmMedium->setAttributePath("location", mdm.strLocation); 1107 1161 1108 if ( devType == DeviceType_HardDisk || RTStrICmp(mdm.strFormat.c_str(), "RAW"))1162 if (t == HardDisk || RTStrICmp(mdm.strFormat.c_str(), "RAW")) 1109 1163 pelmMedium->setAttribute("format", mdm.strFormat); 1110 if ( devType == DeviceType_HardDisk1164 if ( t == HardDisk 1111 1165 && mdm.fAutoReset) 1112 1166 pelmMedium->setAttribute("autoReset", mdm.fAutoReset); … … 1124 1178 1125 1179 // only for base hard disks, save the type 1126 if ( level == 0)1180 if (depth == 1) 1127 1181 { 1128 1182 // no need to save the usual DVD/floppy medium types 1129 if ( ( devType != DeviceType_DVD1183 if ( ( t != DVDImage 1130 1184 || ( mdm.hdType != MediumType_Writethrough // shouldn't happen 1131 1185 && mdm.hdType != MediumType_Readonly)) 1132 && ( devType != DeviceType_Floppy1186 && ( t != FloppyImage 1133 1187 || mdm.hdType != MediumType_Writethrough)) 1134 1188 { … … 1150 1204 { 1151 1205 // recurse for children 1152 buildMedium( *pelmMedium, // parent1153 de vType, // device type1154 * it, // settings::Medium1155 ++level); // recursion level1206 buildMedium(t, // device type 1207 depth + 1, // depth 1208 *pelmMedium, // parent 1209 *it); // settings::Medium 1156 1210 } 1157 1211 } … … 1178 1232 ++it) 1179 1233 { 1180 buildMedium( *pelmHardDisks, DeviceType_HardDisk, *it, 0);1234 buildMedium(HardDisk, 1, *pelmHardDisks, *it); 1181 1235 } 1182 1236 … … 1186 1240 ++it) 1187 1241 { 1188 buildMedium( *pelmDVDImages, DeviceType_DVD, *it, 0);1242 buildMedium(DVDImage, 1, *pelmDVDImages, *it); 1189 1243 } 1190 1244 … … 1194 1248 ++it) 1195 1249 { 1196 buildMedium( *pelmFloppyImages, DeviceType_Floppy, *it, 0);1250 buildMedium(FloppyImage, 1, *pelmFloppyImages, *it); 1197 1251 } 1198 1252 } … … 3767 3821 { 3768 3822 if (depth > SETTINGS_SNAPSHOT_DEPTH_MAX) 3769 throw ConfigFileError(this, &elmSnapshot, N_("Maximum snapshot tree depth of %u exceeded"), depth);3823 throw ConfigFileError(this, &elmSnapshot, N_("Maximum snapshot tree depth of %u exceeded"), SETTINGS_SNAPSHOT_DEPTH_MAX); 3770 3824 3771 3825 Utf8Str strTemp; … … 3814 3868 if (pelmChildSnapshot->nameEquals("Snapshot")) 3815 3869 { 3816 // Use the heap to reduce the stack footprint. Each 3817 // recursion needs over 1K, and there can be VMs with 3818 // deeply nested snapshots. The stack can be quite 3819 // small, especially with XPCOM. 3820 Snapshot *child = new Snapshot(); 3821 bool found = readSnapshot(curSnapshotUuid, depth + 1, *pelmChildSnapshot, *child); 3870 // recurse with this element and put the child at the 3871 // end of the list. XPCOM has very small stack, avoid 3872 // big local variables and use the list element. 3873 snap.llChildSnapshots.push_back(g_SnapshotEmpty); 3874 bool found = readSnapshot(curSnapshotUuid, depth + 1, *pelmChildSnapshot, snap.llChildSnapshots.back()); 3822 3875 foundCurrentSnapshot = foundCurrentSnapshot || found; 3823 snap.llChildSnapshots.push_back(*child);3824 delete child;3825 3876 } 3826 3877 } … … 5149 5200 pelmSnapshot->setAttribute("uuid", snap.uuid.toStringCurly()); 5150 5201 pelmSnapshot->setAttribute("name", snap.strName); 5151 pelmSnapshot->setAttribute("timeStamp", makeString(snap.timestamp));5202 pelmSnapshot->setAttribute("timeStamp", stringifyTimestamp(snap.timestamp)); 5152 5203 5153 5204 if (snap.strStateFile.length()) … … 5256 5307 if (!fCurrentStateModified) 5257 5308 elmMachine.setAttribute("currentStateModified", fCurrentStateModified); 5258 elmMachine.setAttribute("lastStateChange", makeString(timeLastStateChange));5309 elmMachine.setAttribute("lastStateChange", stringifyTimestamp(timeLastStateChange)); 5259 5310 if (fAborted) 5260 5311 elmMachine.setAttribute("aborted", fAborted);
Note:
See TracChangeset
for help on using the changeset viewer.