Index: /trunk/src/VBox/Main/idl/VirtualBox.xidl
===================================================================
--- /trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 61136)
+++ /trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 61137)
@@ -14583,5 +14583,5 @@
     </attribute>
 
-    <attribute name="type" type="MediumType">
+    <attribute name="type" type="MediumType" wrap-hint-server="passcaller">
       <desc>
         Type (role) of this medium.
@@ -14647,5 +14647,5 @@
     </attribute>
 
-    <attribute name="readOnly" type="boolean" readonly="yes">
+    <attribute name="readOnly" type="boolean" readonly="yes" wrap-hint-server="passcaller">
       <desc>
         Returns @c true if this medium is read-only and @c false otherwise.
@@ -15201,5 +15201,5 @@
     <!-- diff methods -->
 
-    <method name="createDiffStorage">
+    <method name="createDiffStorage" wrap-hint-server="passcaller">
       <desc>
         Starts creating an empty differencing storage unit based on this
@@ -15509,5 +15509,5 @@
     </method>
 
-    <method name="reset">
+    <method name="reset" wrap-hint-server="passcaller">
       <desc>
         Starts erasing the contents of this differencing medium.
Index: /trunk/src/VBox/Main/include/MediumImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/MediumImpl.h	(revision 61136)
+++ /trunk/src/VBox/Main/include/MediumImpl.h	(revision 61137)
@@ -237,11 +237,11 @@
     HRESULT getFormat(com::Utf8Str &aFormat);
     HRESULT getMediumFormat(ComPtr<IMediumFormat> &aMediumFormat);
-    HRESULT getType(MediumType_T *aType);
-    HRESULT setType(MediumType_T aType);
+    HRESULT getType(AutoCaller &autoCaller, MediumType_T *aType);
+    HRESULT setType(AutoCaller &autoCaller, MediumType_T aType);
     HRESULT getAllowedTypes(std::vector<MediumType_T> &aAllowedTypes);
     HRESULT getParent(AutoCaller &autoCaller, ComPtr<IMedium> &aParent);
     HRESULT getChildren(AutoCaller &autoCaller, std::vector<ComPtr<IMedium> > &aChildren);
     HRESULT getBase(AutoCaller &autoCaller, ComPtr<IMedium> &aBase);
-    HRESULT getReadOnly(BOOL *aReadOnly);
+    HRESULT getReadOnly(AutoCaller &autoCaller, BOOL *aReadOnly);
     HRESULT getLogicalSize(LONG64 *aLogicalSize);
     HRESULT getAutoReset(BOOL *aAutoReset);
@@ -276,5 +276,6 @@
                               ComPtr<IProgress> &aProgress);
     HRESULT deleteStorage(ComPtr<IProgress> &aProgress);
-    HRESULT createDiffStorage(const ComPtr<IMedium> &aTarget,
+    HRESULT createDiffStorage(AutoCaller &autoCaller,
+                              const ComPtr<IMedium> &aTarget,
                               const std::vector<MediumVariant_T> &aVariant,
                               ComPtr<IProgress> &aProgress);
@@ -293,5 +294,5 @@
     HRESULT resize(LONG64 aLogicalSize,
                    ComPtr<IProgress> &aProgress);
-    HRESULT reset(ComPtr<IProgress> &aProgress);
+    HRESULT reset(AutoCaller &autoCaller, ComPtr<IProgress> &aProgress);
     HRESULT changeEncryption(const com::Utf8Str &aCurrentPassword, const com::Utf8Str &aCipher,
                              const com::Utf8Str &aNewPassword, const com::Utf8Str &aNewPasswordId,
Index: /trunk/src/VBox/Main/src-server/MediumImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-server/MediumImpl.cpp	(revision 61136)
+++ /trunk/src/VBox/Main/src-server/MediumImpl.cpp	(revision 61137)
@@ -1524,8 +1524,12 @@
     /* It is possible that some previous/concurrent uninit has already cleared
      * the pVirtualBox reference, and in this case we don't need to continue.
-     * Normally this would be handled through the AutoUninitSpan magic,
-     * however this cannot be done at this point as the media tree must be
-     * locked before reaching the AutoUninitSpan, otherwise deadlocks can
-     * happen due to*/
+     * Normally this would be handled through the AutoUninitSpan magic, however
+     * this cannot be done at this point as the media tree must be locked
+     * before reaching the AutoUninitSpan, otherwise deadlocks can happen.
+     *
+     * NOTE: The tree lock is higher priority than the medium caller and medium
+     * object locks, i.e. the medium caller may have to be released and be
+     * re-acquired in the right place later. See Medium::getParent() for sample
+     * code how to do this safely. */
     ComObjPtr<VirtualBox> pVirtualBox(m->pVirtualBox);
     if (!pVirtualBox)
@@ -1731,6 +1735,7 @@
 }
 
-HRESULT Medium::getType(MediumType_T *aType)
-{
+HRESULT Medium::getType(AutoCaller &autoCaller, MediumType_T *aType)
+{
+    NOREF(autoCaller);
     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
 
@@ -1740,8 +1745,18 @@
 }
 
-HRESULT Medium::setType(MediumType_T aType)
-{
-    // we access mParent and members
-    AutoWriteLock treeLock(m->pVirtualBox->i_getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
+HRESULT Medium::setType(AutoCaller &autoCaller, MediumType_T aType)
+{
+    autoCaller.release();
+
+    /* It is possible that some previous/concurrent uninit has already cleared
+     * the pVirtualBox reference, see #uninit(). */
+    ComObjPtr<VirtualBox> pVirtualBox(m->pVirtualBox);
+
+    // we access m->pParent
+    AutoReadLock treeLock(!pVirtualBox.isNull() ? &pVirtualBox->i_getMediaTreeLockHandle() : NULL COMMA_LOCKVAL_SRC_POS);
+
+    autoCaller.add();
+    if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
     AutoWriteLock mlock(this COMMA_LOCKVAL_SRC_POS);
 
@@ -1885,5 +1900,5 @@
     ComObjPtr<VirtualBox> pVirtualBox(m->pVirtualBox);
 
-    /* we access mParent */
+    /* we access m->pParent */
     AutoReadLock treeLock(!pVirtualBox.isNull() ? &pVirtualBox->i_getMediaTreeLockHandle() : NULL COMMA_LOCKVAL_SRC_POS);
 
@@ -1928,6 +1943,8 @@
 }
 
-HRESULT Medium::getReadOnly(BOOL *aReadOnly)
-{
+HRESULT Medium::getReadOnly(AutoCaller &autoCaller, BOOL *aReadOnly)
+{
+    autoCaller.release();
+
     /* isReadOnly() will do locking */
     *aReadOnly = i_isReadOnly();
@@ -2587,14 +2604,28 @@
 }
 
-HRESULT Medium::createDiffStorage(const ComPtr<IMedium> &aTarget,
+HRESULT Medium::createDiffStorage(AutoCaller &autoCaller,
+                                  const ComPtr<IMedium> &aTarget,
                                   const std::vector<MediumVariant_T> &aVariant,
                                   ComPtr<IProgress> &aProgress)
 {
+    /** @todo r=klaus The code below needs to be double checked with regard
+     * to lock order violations, it probably causes lock order issues related
+     * to the AutoCaller usage. */
     IMedium *aT = aTarget;
     ComObjPtr<Medium> diff = static_cast<Medium*>(aT);
 
-    // locking: we need the tree lock first because we access parent pointers
-    AutoMultiWriteLock3 alock(&m->pVirtualBox->i_getMediaTreeLockHandle(),
-                              this->lockHandle(), diff->lockHandle() COMMA_LOCKVAL_SRC_POS);
+    autoCaller.release();
+
+    /* It is possible that some previous/concurrent uninit has already cleared
+     * the pVirtualBox reference, see #uninit(). */
+    ComObjPtr<VirtualBox> pVirtualBox(m->pVirtualBox);
+
+    // we access m->pParent
+    AutoReadLock treeLock(!pVirtualBox.isNull() ? &pVirtualBox->i_getMediaTreeLockHandle() : NULL COMMA_LOCKVAL_SRC_POS);
+
+    autoCaller.add();
+    if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+    AutoMultiWriteLock2 alock(this->lockHandle(), diff->lockHandle() COMMA_LOCKVAL_SRC_POS);
 
     if (m->type == MediumType_Writethrough)
@@ -2614,4 +2645,5 @@
     MediumLockList *pMediumLockList(new MediumLockList());
     alock.release();
+    treeLock.release();
     HRESULT rc = diff->i_createMediumLockList(true /* fFailIfInaccessible */,
                                               diff /* pToLockWrite */,
@@ -2619,4 +2651,5 @@
                                               this,
                                               *pMediumLockList);
+    treeLock.acquire();
     alock.acquire();
     if (FAILED(rc))
@@ -2627,5 +2660,7 @@
 
     alock.release();
+    treeLock.release();
     rc = pMediumLockList->Lock();
+    treeLock.acquire();
     alock.acquire();
     if (FAILED(rc))
@@ -2643,9 +2678,12 @@
         diff->m->llRegistryIDs.push_back(parentMachineRegistry);
         alock.release();
+        treeLock.release();
         diff->i_markRegistriesModified();
+        treeLock.acquire();
         alock.acquire();
     }
 
     alock.release();
+    treeLock.release();
 
     ComObjPtr<Progress> pProgress;
@@ -2673,4 +2711,7 @@
 {
 
+    /** @todo r=klaus The code below needs to be double checked with regard
+     * to lock order violations, it probably causes lock order issues related
+     * to the AutoCaller usage. */
     IMedium *aT = aTarget;
 
@@ -2717,4 +2758,7 @@
                         ComPtr<IProgress> &aProgress)
 {
+    /** @todo r=klaus The code below needs to be double checked with regard
+     * to lock order violations, it probably causes lock order issues related
+     * to the AutoCaller usage. */
     ComAssertRet(aTarget != this, E_INVALIDARG);
 
@@ -3010,5 +3054,5 @@
 }
 
-HRESULT Medium::reset(ComPtr<IProgress> &aProgress)
+HRESULT Medium::reset(AutoCaller &autoCaller, ComPtr<IProgress> &aProgress)
 {
     HRESULT rc = S_OK;
@@ -3018,8 +3062,17 @@
     try
     {
+        autoCaller.release();
+
+        /* It is possible that some previous/concurrent uninit has already
+         * cleared the pVirtualBox reference, see #uninit(). */
+        ComObjPtr<VirtualBox> pVirtualBox(m->pVirtualBox);
+
         /* canClose() needs the tree lock */
-        AutoMultiWriteLock2 multilock(&m->pVirtualBox->i_getMediaTreeLockHandle(),
+        AutoMultiWriteLock2 multilock(!pVirtualBox.isNull() ? &pVirtualBox->i_getMediaTreeLockHandle() : NULL,
                                       this->lockHandle()
                                       COMMA_LOCKVAL_SRC_POS);
+
+        autoCaller.add();
+        if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
         LogFlowThisFunc(("ENTER for medium %s\n", m->strLocationFull.c_str()));
@@ -4034,5 +4087,5 @@
         return pBase;
 
-    /* we access mParent */
+    /* we access m->pParent */
     AutoReadLock treeLock(pVirtualBox->i_getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
 
@@ -4077,5 +4130,5 @@
         return 1;
 
-    /* we access mParent */
+    /* we access m->pParent */
     AutoReadLock treeLock(pVirtualBox->i_getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
 
@@ -4103,9 +4156,15 @@
 bool Medium::i_isReadOnly()
 {
+    /* it is possible that some previous/concurrent uninit has already cleared
+     * the pVirtualBox reference, and in this case we don't need to continue */
+    ComObjPtr<VirtualBox> pVirtualBox(m->pVirtualBox);
+    if (!pVirtualBox)
+        return false;
+
+    /* we access children */
+    AutoReadLock treeLock(m->pVirtualBox->i_getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
+
     AutoCaller autoCaller(this);
     AssertComRCReturn(autoCaller.rc(), false);
-
-    /* we access children */
-    AutoReadLock treeLock(m->pVirtualBox->i_getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
 
     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
@@ -4234,9 +4293,9 @@
                                const Utf8Str &strHardDiskFolder)
 {
+    /* we access m->pParent */
+    AutoReadLock treeLock(m->pVirtualBox->i_getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
+
     AutoCaller autoCaller(this);
     if (FAILED(autoCaller.rc())) return autoCaller.rc();
-
-    /* we access mParent */
-    AutoReadLock treeLock(m->pVirtualBox->i_getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
 
     i_saveSettingsOne(data, strHardDiskFolder);
@@ -4283,5 +4342,8 @@
                                        MediumLockList &mediumLockList)
 {
-    Assert(!m->pVirtualBox->i_getMediaTreeLockHandle().isWriteLockOnCurrentThread());
+    /** @todo r=klaus this needs to be reworked, as the code below uses
+     * i_getParent without holding the tree lock, and changing this is
+     * a significant amount of effort. */
+    Assert(m->pVirtualBox->i_getMediaTreeLockHandle().isWriteLockOnCurrentThread());
     Assert(!isWriteLockOnCurrentThread());
 
@@ -4651,4 +4713,7 @@
                               bool aWait)
 {
+    /** @todo r=klaus The code below needs to be double checked with regard
+     * to lock order violations, it probably causes lock order issues related
+     * to the AutoCaller usage. */
     AssertReturn(aProgress != NULL || aWait == true, E_FAIL);
 
@@ -4933,4 +4998,8 @@
                                                bool &fMergeForward)
 {
+    /** @todo r=klaus The code below needs to be double checked with regard
+     * to lock order violations, it probably causes lock order issues related
+     * to the AutoCaller usage. Likewise the code using this method seems
+     * problematic. */
     AssertReturn(pOther != NULL, E_FAIL);
     AssertReturn(pOther != this, E_FAIL);
@@ -5058,4 +5127,8 @@
                                  MediumLockList * &aMediumLockList)
 {
+    /** @todo r=klaus The code below needs to be double checked with regard
+     * to lock order violations, it probably causes lock order issues related
+     * to the AutoCaller usage. Likewise the code using this method seems
+     * problematic. */
     AssertReturn(pTarget != NULL, E_FAIL);
     AssertReturn(pTarget != this, E_FAIL);
@@ -5563,4 +5636,8 @@
 HRESULT Medium::i_fixParentUuidOfChildren(MediumLockList *pChildrenToReparent)
 {
+    /** @todo r=klaus The code below needs to be double checked with regard
+     * to lock order violations, it probably causes lock order issues related
+     * to the AutoCaller usage. Likewise the code using this method seems
+     * problematic. */
     Assert(!isWriteLockOnCurrentThread());
     Assert(!m->pVirtualBox->i_getMediaTreeLockHandle().isWriteLockOnCurrentThread());
@@ -5742,4 +5819,7 @@
                              const ComObjPtr<Progress> &aProgress)
 {
+    /** @todo r=klaus The code below needs to be double checked with regard
+     * to lock order violations, it probably causes lock order issues related
+     * to the AutoCaller usage. */
     AssertPtrReturn(aFilename, E_INVALIDARG);
     AssertReturn(!aFormat.isNull(), E_INVALIDARG);
@@ -5838,4 +5918,7 @@
                             uint32_t idxSrcImageSame, uint32_t idxDstImageSame)
 {
+    /** @todo r=klaus The code below needs to be double checked with regard
+     * to lock order violations, it probably causes lock order issues related
+     * to the AutoCaller usage. */
     CheckComArgNotNull(aTarget);
     CheckComArgOutPointerValid(aProgress);
@@ -6033,5 +6116,5 @@
  * @note Caller MUST NOT hold the media tree or medium lock.
  *
- * @note Locks mParent for reading. Locks this object for writing.
+ * @note Locks m->pParent for reading. Locks this object for writing.
  *
  * @param fSetImageId Whether to reset the UUID contained in the image file to the UUID in the medium instance data (see SetIDs())
@@ -6342,5 +6425,5 @@
                     /* must drop the caller before taking the tree lock */
                     autoCaller.release();
-                    /* we set mParent & children() */
+                    /* we set m->pParent & children() */
                     treeLock.acquire();
                     autoCaller.add();
@@ -6367,5 +6450,5 @@
                     /* must drop the caller before taking the tree lock */
                     autoCaller.release();
-                    /* we access mParent */
+                    /* we access m->pParent */
                     treeLock.acquire();
                     autoCaller.add();
@@ -6577,5 +6660,5 @@
      * VirtualBox::i_unregisterMedium() properly save the registry */
 
-    /* we modify mParent and access children */
+    /* we modify m->pParent and access children */
     Assert(m->pVirtualBox->i_getMediaTreeLockHandle().isWriteLockOnCurrentThread());
 
@@ -7438,4 +7521,7 @@
 HRESULT Medium::i_taskCreateBaseHandler(Medium::CreateBaseTask &task)
 {
+    /** @todo r=klaus The code below needs to be double checked with regard
+     * to lock order violations, it probably causes lock order issues related
+     * to the AutoCaller usage. */
     HRESULT rc = S_OK;
 
@@ -7581,4 +7667,7 @@
 HRESULT Medium::i_taskCreateDiffHandler(Medium::CreateDiffTask &task)
 {
+    /** @todo r=klaus The code below needs to be double checked with regard
+     * to lock order violations, it probably causes lock order issues related
+     * to the AutoCaller usage. */
     HRESULT rcTmp = S_OK;
 
@@ -7801,4 +7890,7 @@
 HRESULT Medium::i_taskMergeHandler(Medium::MergeTask &task)
 {
+    /** @todo r=klaus The code below needs to be double checked with regard
+     * to lock order violations, it probably causes lock order issues related
+     * to the AutoCaller usage. */
     HRESULT rcTmp = S_OK;
 
@@ -8111,4 +8203,7 @@
 HRESULT Medium::i_taskCloneHandler(Medium::CloneTask &task)
 {
+    /** @todo r=klaus The code below needs to be double checked with regard
+     * to lock order violations, it probably causes lock order issues related
+     * to the AutoCaller usage. */
     HRESULT rcTmp = S_OK;
 
@@ -8320,5 +8415,5 @@
     if (SUCCEEDED(mrc) && fCreatingTarget)
     {
-        /* we set mParent & children() */
+        /* we set m->pParent & children() */
         AutoWriteLock treeLock(m->pVirtualBox->i_getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
 
@@ -9049,4 +9144,7 @@
 HRESULT Medium::i_taskImportHandler(Medium::ImportTask &task)
 {
+    /** @todo r=klaus The code below needs to be double checked with regard
+     * to lock order violations, it probably causes lock order issues related
+     * to the AutoCaller usage. */
     HRESULT rcTmp = S_OK;
 
@@ -9218,5 +9316,5 @@
     if (SUCCEEDED(mrc) && fCreatingTarget)
     {
-        /* we set mParent & children() */
+        /* we set m->pParent & children() */
         AutoWriteLock treeLock(m->pVirtualBox->i_getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
 
