Changeset 14143 in vbox for trunk/src/VBox/Main/HardDisk2Impl.cpp
- Timestamp:
- Nov 12, 2008 8:06:37 PM (16 years ago)
- svn:sync-xref-src-repo-rev:
- 39231
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/HardDisk2Impl.cpp
r14123 r14143 176 176 /** 177 177 * Helper class for merge operations. 178 * 179 * @note It is assumed that when modifying methods of this class are called, 180 * HardDisk2::treeLock() is held in read mode. 178 181 */ 179 182 class HardDisk2::MergeChain : public HardDisk2::List, … … 571 574 * @param aParent Parent hard disk or NULL for a root hard disk. 572 575 * @param aNode <HardDisk> settings node. 576 * 577 * @note Locks VirtualBox lock for writing, treeLock() for writing. 573 578 */ 574 579 HRESULT HardDisk2::init (VirtualBox *aVirtualBox, HardDisk2 *aParent, … … 587 592 /* share VirtualBox and parent weakly */ 588 593 unconst (mVirtualBox) = aVirtualBox; 589 mParent = aParent;590 594 591 595 /* register with VirtualBox/parent early, since uninit() will 592 596 * unconditionally unregister on failure */ 593 if ( !aParent)597 if (aParent == NULL) 594 598 aVirtualBox->addDependentChild (this); 595 else 599 600 { 601 /* we set mParent */ 602 AutoWriteLock treeLock (this->treeLock()); 603 604 mParent = aParent; 596 605 aParent->addDependentChild (this); 606 } 597 607 598 608 /* see below why we don't call queryInfo() (and therefore treat the medium … … 670 680 * @note All children of this hard disk get uninitialized by calling their 671 681 * uninit() methods. 682 * 683 * @note Locks treeLock() for writing, VirtualBox for writing. 672 684 */ 673 685 void HardDisk2::uninit() … … 683 695 * Reparenting has already been done so don't touch it here (we are 684 696 * now orphans and remoeDependentChild() will assert) */ 697 698 Assert (mParent.isNull()); 685 699 } 686 700 else 687 701 { 702 /* we uninit children and reset mParent 703 * and VirtualBox::removeDependentChild() needs a write lock */ 704 AutoMultiWriteLock2 alock (mVirtualBox->lockHandle(), this->treeLock()); 705 688 706 uninitDependentChildren(); 689 707 690 if (mParent) 708 if (!mParent.isNull()) 709 { 691 710 mParent->removeDependentChild (this); 711 mParent.setNull(); 712 } 692 713 else 693 714 mVirtualBox->removeDependentChild (this); 694 715 } 695 716 696 mParent.setNull();697 717 unconst (mVirtualBox).setNull(); 698 718 } … … 752 772 return S_OK; 753 773 } 774 775 /* we access mParent & children() */ 776 AutoReadLock treeLock (this->treeLock()); 754 777 755 778 /* cannot change the type of a differencing hard disk */ … … 803 826 CheckComRCReturnRC (autoCaller.rc()); 804 827 805 AutoReadLock alock (this); 828 /* we access mParent */ 829 AutoReadLock treeLock (this->treeLock()); 806 830 807 831 mParent.queryInterfaceTo (aParent); … … 818 842 CheckComRCReturnRC (autoCaller.rc()); 819 843 820 AutoReadLock alock (this); 844 /* we access children */ 845 AutoReadLock treeLock (this->treeLock()); 821 846 822 847 SafeIfaceArray <IHardDisk2> children (this->children()); … … 863 888 864 889 AutoReadLock alock (this); 890 891 /* we access mParent */ 892 AutoReadLock treeLock (this->treeLock()); 865 893 866 894 if (mParent.isNull()) … … 1081 1109 * @param aNewPath New path (full). 1082 1110 * 1083 * @note Locks t his object and all children for writing.1111 * @note Locks treeLock() for reading, this object and all children for writing. 1084 1112 */ 1085 1113 void HardDisk2::updatePaths (const char *aOldPath, const char *aNewPath) … … 1092 1120 1093 1121 AutoWriteLock alock (this); 1122 1123 /* we access children() */ 1124 AutoReadLock treeLock (this->treeLock()); 1094 1125 1095 1126 updatePath (aOldPath, aNewPath); … … 1114 1145 * (zero for the root), may be @c NULL. 1115 1146 * 1116 * @note This method may return an uninitialized object if it happens in 1117 * parallel with such an operation as the VirtualBox shutdown or hard disk 1118 * merge. 1119 * 1120 * @note Locks this object and ancestors for reading. Neither this object nor 1121 * its ancestors may be locked or have active callers on the current 1122 * thread otherwise a deadlock or an endless loop will occur. 1147 * @note Locks treeLock() for reading. 1123 1148 */ 1124 1149 ComObjPtr <HardDisk2> HardDisk2::root (uint32_t *aLevel /*= NULL*/) 1125 1150 { 1126 /* Note: This method locks hard disks sequentially to avoid breaking the1127 * {parent,child} lock order which is impossible to follow here. As a1128 * result, any hard disk in the chain may become uninitialized before this1129 * method finishes walking (for example, as a result of the merge operation1130 * which removes hard disks from the chain). For this reason, we retry the1131 * walk from the beginnig each time it happens (because we must always1132 * return a non-null object).1133 *1134 * As the worst case, we end up having ourselves uninitialized (either1135 * because VirtualBox has initiated the shutdown procedure, or because we1136 * were closed/deleted/etc). In this case, we just return ourselves to avoid1137 * the endless loop.1138 */1139 1140 1151 ComObjPtr <HardDisk2> root; 1141 1152 uint32_t level; 1142 1153 1143 do 1144 { 1145 root = this; 1146 level = 0; 1147 1148 do 1149 { 1150 AutoCaller autoCaller (root); 1151 if (!autoCaller.isOk()) 1152 { 1153 /* break the endless loop, see above */ 1154 if (root == this) 1155 break; 1156 1157 /* cause to start over with this object */ 1158 root.setNull(); 1159 break; 1160 } 1161 1162 AutoReadLock alock (root); 1154 AutoCaller autoCaller (this); 1155 AssertReturn (autoCaller.isOk(), root); 1156 1157 /* we access mParent */ 1158 AutoReadLock treeLock (this->treeLock()); 1159 1160 root = this; 1161 level = 0; 1162 1163 if (!mParent.isNull()) 1164 { 1165 for (;;) 1166 { 1167 AutoCaller rootCaller (root); 1168 AssertReturn (rootCaller.isOk(), root); 1163 1169 1164 1170 if (root->mParent.isNull()) … … 1168 1174 ++ level; 1169 1175 } 1170 while (true); 1171 } 1172 while (root.isNull()); 1176 } 1173 1177 1174 1178 if (aLevel != NULL) … … 1183 1187 * type and posterity, not to the current media state. 1184 1188 * 1185 * @note Locks this object for reading.1189 * @note Locks this object and treeLock() for reading. 1186 1190 */ 1187 1191 bool HardDisk2::isReadOnly() … … 1191 1195 1192 1196 AutoReadLock alock (this); 1197 1198 /* we access children */ 1199 AutoReadLock treeLock (this->treeLock()); 1193 1200 1194 1201 switch (mm.type) … … 1227 1234 * @param aaParentNode Parent <HardDisks> or <HardDisk> node. 1228 1235 * 1229 * @note Locks this object for reading.1236 * @note Locks this object, treeLock() and children for reading. 1230 1237 */ 1231 1238 HRESULT HardDisk2::saveSettings (settings::Key &aParentNode) … … 1239 1246 1240 1247 AutoReadLock alock (this); 1248 1249 /* we access mParent */ 1250 AutoReadLock treeLock (this->treeLock()); 1241 1251 1242 1252 Key diskNode = aParentNode.appendKey ("HardDisk"); … … 1402 1412 * if no real merge is necessary). 1403 1413 * 1404 * @note Locks t he branch lockfor reading. Locks this object, aTarget and all1414 * @note Locks treeLock() for reading. Locks this object, aTarget and all 1405 1415 * intermediate hard disks for writing. 1406 1416 */ … … 1413 1423 1414 1424 AutoWriteLock alock (this); 1425 1426 /* we access mParent & children() */ 1427 AutoReadLock treeLock (this->treeLock()); 1415 1428 1416 1429 AssertReturn (mm.type == HardDiskType_Normal, E_FAIL); … … 1528 1541 * no real merge takes place). 1529 1542 * 1530 * @note Locks the branch lock for writing. Locks the hard disks from the chain1531 * for writing. Locks the machine object when the backward merge takes1532 * place.1543 * @note Locks the hard disks from the chain for writing. Locks the machine 1544 * object when the backward merge takes place. Locks treeLock() lock for 1545 * reading or writing. 1533 1546 */ 1534 1547 HRESULT HardDisk2::discard (ComObjPtr <Progress> &aProgress, MergeChain *aChain) … … 1550 1563 { 1551 1564 AutoWriteLock alock (this); 1565 1566 /* we access mParent & children() */ 1567 AutoReadLock treeLock (this->treeLock()); 1552 1568 1553 1569 Assert (children().size() == 0); … … 1599 1615 * no real merge takes place). 1600 1616 * 1601 * @note Locks the hard disks from the chain for writing. 1617 * @note Locks the hard disks from the chain for writing. Locks treeLock() for 1618 * reading. 1602 1619 */ 1603 1620 void HardDisk2::cancelDiscard (MergeChain *aChain) … … 1609 1626 { 1610 1627 AutoWriteLock alock (this); 1628 1629 /* we access mParent & children() */ 1630 AutoReadLock treeLock (this->treeLock()); 1611 1631 1612 1632 Assert (children().size() == 0); … … 1656 1676 * an asynchronous thread. 1657 1677 * 1658 * @note Locks mVirtualBox, mParent and this object for writing. 1678 * @note Locks mVirtualBox and this object for writing. Locks treeLock() for 1679 * writing. 1659 1680 */ 1660 1681 HRESULT HardDisk2::deleteStorage (ComObjPtr <Progress> *aProgress, bool aWait) 1661 1682 { 1662 1683 AssertReturn (aProgress != NULL || aWait == true, E_FAIL); 1663 1664 AutoCaller autoCaller (this);1665 CheckComRCReturnRC (autoCaller.rc());1666 1684 1667 1685 /* unregisterWithVirtualBox() needs a write lock. We want to unregister … … 1669 1687 * sure that we don't do that after another thread has done 1670 1688 * VirtualBox::findHardDisk2() but before it starts using us (provided that 1671 * it holds a mVirtualBox lock too of course). 1672 * 1673 * mParent->removeDependentChild() needs a write lock too. */1674 1675 Auto MultiWriteLock3 alock (mVirtualBox, mParent,this);1689 * it holds a mVirtualBox lock too of course). */ 1690 1691 AutoWriteLock vboxLock (mVirtualBox); 1692 1693 AutoWriteLock alock (this); 1676 1694 1677 1695 switch (m.state) … … 1691 1709 CheckComRCReturnRC (rc); 1692 1710 1711 /* go to Deleting state before leaving the lock */ 1712 m.state = MediaState_Deleting; 1713 1714 /* we need to leave this object's write lock now because of 1715 * unregisterWithVirtualBox() that locks treeLock() for writing */ 1716 alock.leave(); 1717 1693 1718 /* try to remove from the list of known hard disks before performing actual 1694 1719 * deletion (we favor the consistency of the media registry in the first … … 1697 1722 1698 1723 rc = unregisterWithVirtualBox(); 1724 1725 alock.enter(); 1726 1727 /* restore the state because we may fail below; we will set it later again*/ 1728 m.state = MediaState_Created; 1729 1699 1730 CheckComRCReturnRC (rc); 1700 1731 … … 1916 1947 * hard disk is attached to any VM. 1917 1948 * 1918 * @note Locks t he branch lockfor reading. Locks this object, aTarget and all1949 * @note Locks treeLock() for reading. Locks this object, aTarget and all 1919 1950 * intermediate hard disks for writing. 1920 1951 */ … … 1928 1959 AssertComRCReturnRC (autoCaller.rc()); 1929 1960 1930 AutoCaller targetCaller ( this);1961 AutoCaller targetCaller (aTarget); 1931 1962 AssertComRCReturnRC (targetCaller.rc()); 1932 1963 1933 1964 aChain = NULL; 1934 1965 1935 /* tree lock is always the first*/1966 /* we walk the tree */ 1936 1967 AutoReadLock treeLock (this->treeLock()); 1937 1968 … … 1956 1987 { 1957 1988 Bstr tgtLoc; 1958 rc = aTarget->COMGETTER(Location) (tgtLoc.asOutParam()); 1959 CheckComRCThrowRC (rc); 1989 { 1990 AutoReadLock alock (this); 1991 tgtLoc = aTarget->locationFull(); 1992 } 1960 1993 1961 1994 AutoReadLock alock (this); … … 2248 2281 * accessibility. 2249 2282 * 2250 * @note Locks this object for writing. 2283 * @note Locks treeLock() for reading and writing (for new diff media checked 2284 * for the first time). Locks mParent for reading. Locks this object for 2285 * writing. 2251 2286 */ 2252 2287 HRESULT HardDisk2::queryInfo() … … 2413 2448 } 2414 2449 2415 /* associate with parent, deassociate from VirtualBox */ 2450 /* deassociate from VirtualBox, associate with parent */ 2451 2452 mVirtualBox->removeDependentChild (this); 2453 2454 /* we set mParent & children() */ 2455 AutoWriteLock treeLock (this->treeLock()); 2456 2416 2457 Assert (mParent.isNull()); 2417 2458 mParent = parent; 2418 2459 mParent->addDependentChild (this); 2419 mVirtualBox->removeDependentChild (this);2420 2460 } 2421 2461 else 2422 2462 { 2463 /* we access mParent */ 2464 AutoReadLock treeLock (this->treeLock()); 2465 2423 2466 /* check that parent UUIDs match. Note that there's no need 2424 2467 * for the parent's AutoCaller (our lifetime is bound to … … 2514 2557 * @note Called from this object's AutoMayUninitSpan and from under mVirtualBox 2515 2558 * write lock. 2559 * 2560 * @note Locks treeLock() for reading. 2516 2561 */ 2517 2562 HRESULT HardDisk2::canClose() 2518 2563 { 2564 /* we access children */ 2565 AutoReadLock treeLock (this->treeLock()); 2566 2519 2567 if (children().size() != 0) 2520 2568 return setError (E_FAIL, … … 2544 2592 * from under mVirtualBox write lock. 2545 2593 * 2546 * @note Locks mParentfor writing.2594 * @note Locks treeLock() for writing. 2547 2595 */ 2548 2596 HRESULT HardDisk2::unregisterWithVirtualBox() … … 2551 2599 * unregisterHardDisk2() properly save the registry */ 2552 2600 2601 /* we modify mParent and access children */ 2602 AutoWriteLock treeLock (this->treeLock()); 2603 2553 2604 const ComObjPtr <HardDisk2, ComWeakRef> parent = mParent; 2554 2555 /* Lock parent to make the try atomic WRT to mParent->COMGETTER(Children) */2556 AutoWriteLock parentLock (parent);2557 2605 2558 2606 AssertReturn (children().size() == 0, E_FAIL); … … 2880 2928 if (SUCCEEDED (rc)) 2881 2929 { 2882 /* mVirtualBox->registerHardDisk2() needs a write lock */ 2883 AutoWriteLock vboxLock (that->mVirtualBox); 2884 thatLock.enter(); 2885 2886 target->m.size = size; 2887 target->mm.logicalSize = logicalSize; 2930 /* we set mParent & children() (note that thatLock is released 2931 * here), but lock VirtualBox first to follow the rule */ 2932 AutoMultiWriteLock2 alock (that->mVirtualBox->lockHandle(), 2933 that->treeLock()); 2888 2934 2889 2935 Assert (target->mParent.isNull()); … … 2900 2946 rc = that->mVirtualBox->registerHardDisk2 (target); 2901 2947 2902 if (SUCCEEDED (rc)) 2903 { 2904 target->m.state = MediaState_Created; 2905 } 2906 else 2948 if (FAILED (rc)) 2907 2949 { 2908 2950 /* break the parent association on failure to register */ … … 2913 2955 } 2914 2956 2915 if (FAILED (rc)) 2957 thatLock.maybeEnter(); 2958 2959 if (SUCCEEDED (rc)) 2916 2960 { 2917 thatLock.maybeEnter(); 2918 2961 target->m.state = MediaState_Created; 2962 2963 target->m.size = size; 2964 target->mm.logicalSize = logicalSize; 2965 } 2966 else 2967 { 2919 2968 /* back to NotCreated on failiure */ 2920 2969 target->m.state = MediaState_NotCreated; … … 2980 3029 /* complex sanity (sane complexity) */ 2981 3030 Assert ((chain->isForward() && 2982 ( *it != chain->back() &&2983 (*it)->m.state == MediaState_Deleting) ||2984 (*it == chain->back() &&2985 (*it)->m.state == MediaState_LockedWrite)) ||3031 ((*it != chain->back() && 3032 (*it)->m.state == MediaState_Deleting) || 3033 (*it == chain->back() && 3034 (*it)->m.state == MediaState_LockedWrite))) || 2986 3035 (!chain->isForward() && 2987 ( *it != chain->front() &&2988 (*it)->m.state == MediaState_Deleting) ||2989 (*it == chain->front() &&2990 (*it)->m.state == MediaState_LockedWrite)));3036 ((*it != chain->front() && 3037 (*it)->m.state == MediaState_Deleting) || 3038 (*it == chain->front() && 3039 (*it)->m.state == MediaState_LockedWrite)))); 2991 3040 2992 3041 Assert (*it == chain->target() || … … 3088 3137 * VDMerge; reparent the last one and uninitialize deleted */ 3089 3138 3090 /* mVirtualBox->(un)registerHardDisk2() needs a write lock */ 3091 AutoWriteLock vboxLock (that->mVirtualBox); 3092 3093 /* we will reparent */ 3094 AutoWriteLock treeLock (that->mVirtualBox->hardDiskTreeHandle()); 3139 /* we set mParent & children() (note that thatLock is released 3140 * here), but lock VirtualBox first to follow the rule */ 3141 AutoMultiWriteLock2 alock (that->mVirtualBox->lockHandle(), 3142 that->treeLock()); 3095 3143 3096 3144 HardDisk2 *source = chain->source(); … … 3104 3152 unregisterHardDisk2 (target, false /* aSaveSettings */); 3105 3153 AssertComRC (rc2); 3106 3107 /* obey {parent,child} lock order (add/remove methods below3108 * do locking) */3109 AutoWriteLock parentLock (chain->parent());3110 AutoWriteLock sourceLock (source);3111 AutoWriteLock targetLock (target);3112 3154 3113 3155 /* then, reparent it and disconnect the deleted branch at … … 3134 3176 else 3135 3177 { 3136 /* obey {parent,child} lock order (add/remove methods below3137 * do locking) */3138 AutoWriteLock targetLock (target);3139 3140 3178 Assert (target->children().size() == 1); 3141 3179 HardDisk2 *targetChild = target->children().front(); 3142 3143 AutoWriteLock targetChildLock (target);3144 3180 3145 3181 /* disconnect the deleted branch at the elder end */
Note:
See TracChangeset
for help on using the changeset viewer.