VirtualBox

Changeset 40466 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Mar 14, 2012 2:34:15 PM (13 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
76832
Message:

Main/Medium: another go at the medium locking related to queryInfo, since there was a remaining deadlock with the LockWrite method.

Location:
trunk/src/VBox/Main
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/include/MediumImpl.h

    r40432 r40466  
    265265
    266266    HRESULT queryInfo(bool fSetImageId, bool fSetParentId);
    267     HRESULT lockRead(MediumState_T *aState, bool fWithinQueryInfo);
    268     HRESULT lockWrite(MediumState_T *aState, bool fWithinQueryInfo);
    269267
    270268    HRESULT canClose();
  • trunk/src/VBox/Main/src-server/MediumImpl.cpp

    r40432 r40466  
    20802080    if (FAILED(autoCaller.rc())) return autoCaller.rc();
    20812081
    2082     return lockRead(aState, false /* fWithinQueryInfo */);
     2082    /* Must not hold the object lock, as we need control over it below. */
     2083    Assert(!isWriteLockOnCurrentThread());
     2084    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     2085
     2086    /* Wait for a concurrently running Medium::queryInfo to complete. */
     2087    if (m->queryInfoRunning)
     2088    {
     2089        /* Must not hold the media tree lock, as Medium::queryInfo needs this
     2090         * lock and thus we would run into a deadlock here. */
     2091        Assert(!m->pVirtualBox->getMediaTreeLockHandle().isWriteLockOnCurrentThread());
     2092        while (m->queryInfoRunning)
     2093        {
     2094            alock.release();
     2095            {
     2096                AutoReadLock qlock(m->queryInfoSem COMMA_LOCKVAL_SRC_POS);
     2097            }
     2098            alock.acquire();
     2099        }
     2100    }
     2101
     2102    /* return the current state before */
     2103    if (aState)
     2104        *aState = m->state;
     2105
     2106    HRESULT rc = S_OK;
     2107
     2108    switch (m->state)
     2109    {
     2110        case MediumState_Created:
     2111        case MediumState_Inaccessible:
     2112        case MediumState_LockedRead:
     2113        {
     2114            ++m->readers;
     2115
     2116            ComAssertMsgBreak(m->readers != 0, ("Counter overflow"), rc = E_FAIL);
     2117
     2118            /* Remember pre-lock state */
     2119            if (m->state != MediumState_LockedRead)
     2120                m->preLockState = m->state;
     2121
     2122            LogFlowThisFunc(("Okay - prev state=%d readers=%d\n", m->state, m->readers));
     2123            m->state = MediumState_LockedRead;
     2124
     2125            break;
     2126        }
     2127        default:
     2128        {
     2129            LogFlowThisFunc(("Failing - state=%d\n", m->state));
     2130            rc = setStateError();
     2131            break;
     2132        }
     2133    }
     2134
     2135    return rc;
    20832136}
    20842137
     
    21432196    if (FAILED(autoCaller.rc())) return autoCaller.rc();
    21442197
    2145     return lockWrite(aState, false /* fWithinQueryInfo */);
     2198    /* Must not hold the object lock, as we need control over it below. */
     2199    Assert(!isWriteLockOnCurrentThread());
     2200    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     2201
     2202    /* Wait for a concurrently running Medium::queryInfo to complete. */
     2203    if (m->queryInfoRunning)
     2204    {
     2205        /* Must not hold the media tree lock, as Medium::queryInfo needs this
     2206         * lock and thus we would run into a deadlock here. */
     2207        Assert(!m->pVirtualBox->getMediaTreeLockHandle().isWriteLockOnCurrentThread());
     2208        while (m->queryInfoRunning)
     2209        {
     2210            alock.release();
     2211            {
     2212                AutoReadLock qlock(m->queryInfoSem COMMA_LOCKVAL_SRC_POS);
     2213            }
     2214            alock.acquire();
     2215        }
     2216    }
     2217
     2218    /* return the current state before */
     2219    if (aState)
     2220        *aState = m->state;
     2221
     2222    HRESULT rc = S_OK;
     2223
     2224    switch (m->state)
     2225    {
     2226        case MediumState_Created:
     2227        case MediumState_Inaccessible:
     2228        {
     2229            m->preLockState = m->state;
     2230
     2231            LogFlowThisFunc(("Okay - prev state=%d locationFull=%s\n", m->state, getLocationFull().c_str()));
     2232            m->state = MediumState_LockedWrite;
     2233            break;
     2234        }
     2235        default:
     2236        {
     2237            LogFlowThisFunc(("Failing - state=%d locationFull=%s\n", m->state, getLocationFull().c_str()));
     2238            rc = setStateError();
     2239            break;
     2240        }
     2241    }
     2242
     2243    return rc;
    21462244}
    21472245
     
    51885286
    51895287/**
    5190  * @note @a aState may be NULL if the state value is not needed (only for
    5191  *       in-process calls).
    5192  */
    5193 HRESULT Medium::lockRead(MediumState_T *aState, bool fWithinQueryInfo)
    5194 {
    5195     /* Must not hold the object lock, as we need control over it below. */
     5288 * Queries information from the medium.
     5289 *
     5290 * As a result of this call, the accessibility state and data members such as
     5291 * size and description will be updated with the current information.
     5292 *
     5293 * @note This method may block during a system I/O call that checks storage
     5294 *       accessibility.
     5295 *
     5296 * @note Caller MUST NOT hold the media tree or medium lock.
     5297 *
     5298 * @note Locks mParent for reading. Locks this object for writing.
     5299 *
     5300 * @param fSetImageId Whether to reset the UUID contained in the image file to the UUID in the medium instance data (see SetIDs())
     5301 * @param fSetParentId Whether to reset the parent UUID contained in the image file to the parent UUID in the medium instance data (see SetIDs())
     5302 * @return
     5303 */
     5304HRESULT Medium::queryInfo(bool fSetImageId, bool fSetParentId)
     5305{
    51965306    Assert(!isWriteLockOnCurrentThread());
    51975307    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    51985308
    5199     /* Wait for a concurrently running Medium::queryInfo to complete. */
     5309    if (   m->state != MediumState_Created
     5310        && m->state != MediumState_Inaccessible
     5311        && m->state != MediumState_LockedRead)
     5312        return E_FAIL;
     5313
     5314    HRESULT rc = S_OK;
     5315
     5316    int vrc = VINF_SUCCESS;
     5317
     5318    /* check if a blocking queryInfo() call is in progress on some other thread,
     5319     * and wait for it to finish if so instead of querying data ourselves */
    52005320    if (m->queryInfoRunning)
    52015321    {
    5202         /* Must not hold the media tree lock, as Medium::queryInfo needs this
    5203          * lock and thus we would run into a deadlock here. */
    5204         if (!fWithinQueryInfo)
    5205             Assert(!m->pVirtualBox->getMediaTreeLockHandle().isWriteLockOnCurrentThread());
     5322        Assert(   m->state == MediumState_LockedRead
     5323               || m->state == MediumState_LockedWrite);
     5324
    52065325        while (m->queryInfoRunning)
    52075326        {
     
    52125331            alock.acquire();
    52135332        }
    5214     }
    5215 
    5216     /* return the current state before */
    5217     if (aState)
    5218         *aState = m->state;
    5219 
    5220     HRESULT rc = S_OK;
    5221 
    5222     switch (m->state)
    5223     {
    5224         case MediumState_Created:
    5225         case MediumState_Inaccessible:
    5226         case MediumState_LockedRead:
    5227         {
    5228             ++m->readers;
    5229 
    5230             ComAssertMsgBreak(m->readers != 0, ("Counter overflow"), rc = E_FAIL);
    5231 
    5232             /* Remember pre-lock state */
    5233             if (m->state != MediumState_LockedRead)
    5234                 m->preLockState = m->state;
    5235 
    5236             LogFlowThisFunc(("Okay - prev state=%d readers=%d\n", m->state, m->readers));
    5237             m->state = MediumState_LockedRead;
    5238 
    5239             break;
    5240         }
    5241         default:
    5242         {
    5243             LogFlowThisFunc(("Failing - state=%d\n", m->state));
    5244             rc = setStateError();
    5245             break;
    5246         }
    5247     }
    5248 
    5249     return rc;
    5250 }
    5251 
    5252 /**
    5253  * @note @a aState may be NULL if the state value is not needed (only for
    5254  *       in-process calls).
    5255  */
    5256 HRESULT Medium::lockWrite(MediumState_T *aState, bool fWithinQueryInfo)
    5257 {
    5258     /* Must not hold the object lock, as we need control over it below. */
    5259     Assert(!isWriteLockOnCurrentThread());
    5260     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    5261 
    5262     /* Wait for a concurrently running Medium::queryInfo to complete. */
    5263     if (m->queryInfoRunning)
    5264     {
    5265         /* Must not hold the media tree lock, as Medium::queryInfo needs this
    5266          * lock and thus we would run into a deadlock here. */
    5267         if (!fWithinQueryInfo)
    5268             Assert(!m->pVirtualBox->getMediaTreeLockHandle().isWriteLockOnCurrentThread());
    5269         while (m->queryInfoRunning)
    5270         {
    5271             alock.release();
    5272             {
    5273                 AutoReadLock qlock(m->queryInfoSem COMMA_LOCKVAL_SRC_POS);
    5274             }
    5275             alock.acquire();
    5276         }
    5277     }
    5278 
    5279     /* return the current state before */
    5280     if (aState)
    5281         *aState = m->state;
    5282 
    5283     HRESULT rc = S_OK;
    5284 
    5285     switch (m->state)
    5286     {
    5287         case MediumState_Created:
    5288         case MediumState_Inaccessible:
    5289         {
    5290             m->preLockState = m->state;
    5291 
    5292             LogFlowThisFunc(("Okay - prev state=%d locationFull=%s\n", m->state, getLocationFull().c_str()));
    5293             m->state = MediumState_LockedWrite;
    5294             break;
    5295         }
    5296         default:
    5297         {
    5298             LogFlowThisFunc(("Failing - state=%d locationFull=%s\n", m->state, getLocationFull().c_str()));
    5299             rc = setStateError();
    5300             break;
    5301         }
    5302     }
    5303 
    5304     return rc;
    5305 }
    5306 
    5307 /**
    5308  * Queries information from the medium.
    5309  *
    5310  * As a result of this call, the accessibility state and data members such as
    5311  * size and description will be updated with the current information.
    5312  *
    5313  * @note This method may block during a system I/O call that checks storage
    5314  *       accessibility.
    5315  *
    5316  * @note Caller MUST NOT hold the media tree or medium lock.
    5317  *
    5318  * @note Locks mParent for reading. Locks this object for writing.
    5319  *
    5320  * @param fSetImageId Whether to reset the UUID contained in the image file to the UUID in the medium instance data (see SetIDs())
    5321  * @param fSetParentId Whether to reset the parent UUID contained in the image file to the parent UUID in the medium instance data (see SetIDs())
    5322  * @return
    5323  */
    5324 HRESULT Medium::queryInfo(bool fSetImageId, bool fSetParentId)
    5325 {
    5326     Assert(!isWriteLockOnCurrentThread());
    5327     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    5328 
    5329     if (   m->state != MediumState_Created
    5330         && m->state != MediumState_Inaccessible
    5331         && m->state != MediumState_LockedRead)
    5332         return E_FAIL;
    5333 
    5334     HRESULT rc = S_OK;
    5335 
    5336     int vrc = VINF_SUCCESS;
    5337 
    5338     /* check if a blocking queryInfo() call is in progress on some other thread,
    5339      * and wait for it to finish if so instead of querying data ourselves */
    5340     if (m->queryInfoRunning)
    5341     {
    5342         Assert(   m->state == MediumState_LockedRead
    5343                || m->state == MediumState_LockedWrite);
    5344 
    5345         while (m->queryInfoRunning)
    5346         {
    5347             alock.release();
    5348             {
    5349                 AutoReadLock qlock(m->queryInfoSem COMMA_LOCKVAL_SRC_POS);
    5350             }
    5351             alock.acquire();
    5352         }
    53535333
    53545334        return S_OK;
    53555335    }
    5356 
    5357     alock.release();
    5358     Assert(!isWriteLockOnCurrentThread());
    5359     Assert(!m->pVirtualBox->getMediaTreeLockHandle().isWriteLockOnCurrentThread());
    5360     AutoWriteLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
    5361     alock.acquire();
    53625336
    53635337    bool success = false;
     
    53875361    alock.release();
    53885362    if (uOpenFlags & (VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_SHAREABLE))
    5389         rc = lockRead(NULL, true /* fWithinQueryInfo */);
     5363        rc = LockRead(NULL);
    53905364    else
    5391         rc = lockWrite(NULL, true /* fWithinQueryInfo */);
     5365        rc = LockWrite(NULL);
    53925366    if (FAILED(rc)) return rc;
    53935367    alock.acquire();
     
    54115385    bool fRepairImageZeroParentUuid = false;
    54125386
    5413     /* release the object lock before a lengthy operation */
     5387    /* release the object lock before a lengthy operation, and take the
     5388     * opportunity to have a media tree lock, too, which isn't held initially */
    54145389    m->queryInfoRunning = true;
    54155390    alock.release();
    5416     treeLock.release();
    54175391    Assert(!isWriteLockOnCurrentThread());
    54185392    Assert(!m->pVirtualBox->getMediaTreeLockHandle().isWriteLockOnCurrentThread());
     5393    AutoWriteLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
     5394    treeLock.release();
    54195395
    54205396    /* Note that taking the queryInfoSem after leaving the object lock above
     
    54225398     * complete. This is unavoidable since the other order causes a lock order
    54235399     * violation: here it would be requesting the object lock (at the beginning
    5424      * of the method), then SemRW, and below the other way round. */
     5400     * of the method), then queryInfoSem, and below the other way round. */
    54255401    AutoWriteLock qlock(m->queryInfoSem COMMA_LOCKVAL_SRC_POS);
     5402    alock.acquire();
    54265403
    54275404    try
     
    55625539
    55635540                    /* we set mParent & children() */
     5541                    alock.release();
    55645542                    treeLock.acquire();
    55655543
     
    55695547
    55705548                    treeLock.release();
     5549                    alock.acquire();
    55715550                }
    55725551                else
    55735552                {
    55745553                    /* we access mParent */
     5554                    alock.release();
    55755555                    treeLock.acquire();
    55765556
     
    55965576                                location.c_str(),
    55975577                                m->pVirtualBox->settingsFilePath().c_str());
     5578                        treeLock.release();
     5579                        alock.acquire();
    55985580                        throw S_OK;
    55995581#endif /* 0 */
    56005582                    }
    56015583
    5602                     AutoReadLock parentLock(m->pParent COMMA_LOCKVAL_SRC_POS);
    5603                     if (   !fRepairImageZeroParentUuid
    5604                         && m->pParent->getState() != MediumState_Inaccessible
    5605                         && m->pParent->getId() != parentId)
    56065584                    {
    5607                         /** @todo r=klaus this always refers to VirtualBox.xml as the medium registry, even for new VMs */
    5608                         lastAccessError = Utf8StrFmt(
    5609                                 tr("Parent UUID {%RTuuid} of the medium '%s' does not match UUID {%RTuuid} of its parent medium stored in the media registry ('%s')"),
    5610                                 &parentId, location.c_str(),
    5611                                 m->pParent->getId().raw(),
    5612                                 m->pVirtualBox->settingsFilePath().c_str());
    5613                         throw S_OK;
     5585                        AutoReadLock parentLock(m->pParent COMMA_LOCKVAL_SRC_POS);
     5586                        if (   !fRepairImageZeroParentUuid
     5587                            && m->pParent->getState() != MediumState_Inaccessible
     5588                            && m->pParent->getId() != parentId)
     5589                        {
     5590                            /** @todo r=klaus this always refers to VirtualBox.xml as the medium registry, even for new VMs */
     5591                            lastAccessError = Utf8StrFmt(
     5592                                    tr("Parent UUID {%RTuuid} of the medium '%s' does not match UUID {%RTuuid} of its parent medium stored in the media registry ('%s')"),
     5593                                    &parentId, location.c_str(),
     5594                                    m->pParent->getId().raw(),
     5595                                    m->pVirtualBox->settingsFilePath().c_str());
     5596                            parentLock.release();
     5597                            treeLock.release();
     5598                            alock.acquire();
     5599                            throw S_OK;
     5600                        }
    56145601                    }
    56155602
     
    56195606
    56205607                    treeLock.release();
     5608                    alock.acquire();
    56215609                }
    56225610            }
     
    56465634    }
    56475635
     5636    alock.release();
    56485637    treeLock.acquire();
    56495638    alock.acquire();
     
    57305719            rc = aRC;
    57315720        }
    5732 
    5733         alock.acquire();
    57345721
    57355722        rc = UnlockWrite(NULL);
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette