Changeset 24210 in vbox
- Timestamp:
- Oct 30, 2009 4:30:19 PM (15 years ago)
- svn:sync-xref-src-repo-rev:
- 54157
- Location:
- trunk/src/VBox/Main
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/MediumImpl.cpp
r24209 r24210 90 90 : state(MediumState_NotCreated), 91 91 size(0), 92 preLockState(MediumState_NotCreated), 92 93 readers(0), 93 94 queryInfoSem(NIL_RTSEMEVENTMULTI), 94 queryInfoCallers(0), 95 accessibleInLock(false), 95 queryInfoRunning(false), 96 96 type(MediumType_Normal), 97 97 devType(DeviceType_HardDisk), … … 119 119 120 120 size_t readers; 121 MediumState_T preLockState; 121 122 122 123 RTSEMEVENTMULTI queryInfoSem; 123 size_t queryInfoCallers; 124 125 bool accessibleInLock : 1; 124 bool queryInfoRunning : 1; 126 125 127 126 const Bstr format; … … 416 415 417 416 /* We have to fetch the state with the COM method, cause it's possible 418 that the medium isn't fully initialized yet. See HRESULT 419 Medium::protectedInit(VirtualBox *aVirtualBox, const 420 settings::Key &aImageNode) for an explanation why. */ 417 that the medium isn't fully initialized yet. */ 421 418 MediumState_T m; 422 419 rc = aMedium->COMGETTER(State)(&m); … … 854 851 AssertRCReturn(vrc, E_FAIL); 855 852 853 vrc = RTSemEventMultiCreate(&m->queryInfoSem); 854 AssertRCReturn(vrc, E_FAIL); 855 vrc = RTSemEventMultiSignal(m->queryInfoSem); 856 AssertRCReturn(vrc, E_FAIL); 857 856 858 return S_OK; 857 859 } … … 1302 1304 } 1303 1305 1306 RTSemEventMultiSignal(m->queryInfoSem); 1307 RTSemEventMultiDestroy(m->queryInfoSem); 1308 m->queryInfoSem = NIL_RTSEMEVENTMULTI; 1309 1304 1310 unconst(mVirtualBox).setNull(); 1305 1311 } … … 1830 1836 ComAssertMsgBreak(m->readers != 0, ("Counter overflow"), rc = E_FAIL); 1831 1837 1832 if (m->state == MediumState_Created) 1833 m->accessibleInLock = true; 1834 else if (m->state == MediumState_Inaccessible) 1835 m->accessibleInLock = false; 1838 /* Remember pre-lock state */ 1839 if (m->state != MediumState_LockedRead) 1840 m->preLockState = m->state; 1836 1841 1837 1842 LogFlowThisFunc(("Okay - prev state=%d readers=%d\n", m->state, m->readers)); … … 1868 1873 case MediumState_LockedRead: 1869 1874 { 1870 if (m->queryInfoSem == NIL_RTSEMEVENTMULTI) 1871 { 1872 Assert(m->readers != 0); 1873 --m->readers; 1874 1875 /* Reset the state after the last reader */ 1876 if (m->readers == 0) 1877 { 1878 if (m->accessibleInLock) 1879 m->state = MediumState_Created; 1880 else 1881 m->state = MediumState_Inaccessible; 1882 } 1883 1884 LogFlowThisFunc(("new state=%d\n", m->state)); 1885 break; 1886 } 1887 1888 /* otherwise, queryInfo() is in progress; fall through */ 1875 Assert(m->readers != 0); 1876 --m->readers; 1877 1878 /* Reset the state after the last reader */ 1879 if (m->readers == 0) 1880 m->state = m->preLockState; 1881 1882 LogFlowThisFunc(("new state=%d\n", m->state)); 1883 break; 1889 1884 } 1890 1885 default: … … 1927 1922 case MediumState_Inaccessible: 1928 1923 { 1929 if (m->state == MediumState_Created) 1930 m->accessibleInLock = true; 1931 else if (m->state == MediumState_Inaccessible) 1932 m->accessibleInLock = false; 1924 m->preLockState = m->state; 1933 1925 1934 1926 LogFlowThisFunc(("Okay - prev state=%d\n", m->state)); … … 1964 1956 case MediumState_LockedWrite: 1965 1957 { 1966 if (m->accessibleInLock) 1967 m->state = MediumState_Created; 1968 else 1969 m->state = MediumState_Inaccessible; 1958 m->state = m->preLockState; 1970 1959 LogFlowThisFunc(("new state=%d\n", m->state)); 1971 1960 break; … … 2652 2641 } 2653 2642 2654 HRESULT rc = canAttach(aMachineId, aSnapshotId); 2655 CheckComRCReturnRC(rc); 2643 if (m->numCreateDiffTasks > 0) 2644 return setError(E_FAIL, 2645 tr("One or more differencing child hard disks are being created for the hard disk '%ls' (%u)"), 2646 m->locationFull.raw(), m->numCreateDiffTasks); 2656 2647 2657 2648 BackRefList::iterator it = … … 3354 3345 } 3355 3346 3356 // pr otectedmethods3347 // private methods 3357 3348 //////////////////////////////////////////////////////////////////////////////// 3358 3349 … … 3563 3554 AssertReturn(m->state == MediumState_Created || 3564 3555 m->state == MediumState_Inaccessible || 3565 m->state == MediumState_LockedRead || 3566 m->state == MediumState_LockedWrite, 3556 m->state == MediumState_LockedRead, 3567 3557 E_FAIL); 3568 3558 … … 3573 3563 /* check if a blocking queryInfo() call is in progress on some other thread, 3574 3564 * and wait for it to finish if so instead of querying data ourselves */ 3575 if (m->queryInfo Sem != NIL_RTSEMEVENTMULTI)3576 { 3577 Assert( m->state == MediumState_LockedRead);3578 3579 ++m->queryInfoCallers; 3565 if (m->queryInfoRunning) 3566 { 3567 Assert( m->state == MediumState_LockedRead 3568 || m->state == MediumState_LockedWrite); 3569 3580 3570 alock.leave(); 3581 3571 … … 3583 3573 3584 3574 alock.enter(); 3585 --m->queryInfoCallers;3586 3587 if (m->queryInfoCallers == 0)3588 {3589 /* last waiting caller deletes the semaphore */3590 RTSemEventMultiDestroy(m->queryInfoSem);3591 m->queryInfoSem = NIL_RTSEMEVENTMULTI;3592 }3593 3575 3594 3576 AssertRC(vrc); … … 3596 3578 return S_OK; 3597 3579 } 3598 3599 /* lazily create a semaphore for possible callers */3600 vrc = RTSemEventMultiCreate(&m->queryInfoSem);3601 ComAssertRCRet(vrc, E_FAIL);3602 3603 bool tempStateSet = false;3604 if (m->state != MediumState_LockedRead &&3605 m->state != MediumState_LockedWrite)3606 {3607 /* Cause other methods to prevent any modifications before leaving the3608 * lock. Note that clients will never see this temporary state change3609 * since any COMGETTER(State) is (or will be) blocked until we finish3610 * and restore the actual state. */3611 LogFlowThisFunc(("read locking - prev state=%d - %ls\n", m->state, m->locationFull.raw()));3612 m->state = MediumState_LockedRead;3613 tempStateSet = true;3614 }3615 3616 /* leave the lock before a blocking operation */3617 alock.leave();3618 3580 3619 3581 bool success = false; 3620 3582 Utf8Str lastAccessError; 3621 3583 3584 /* are we dealing with a new medium constructed using the existing 3585 * location? */ 3586 bool isImport = m->id.isEmpty(); 3587 unsigned flags = VD_OPEN_FLAGS_INFO; 3588 3589 /* Note that we don't use VD_OPEN_FLAGS_READONLY when opening new 3590 * media because that would prevent necessary modifications 3591 * when opening media of some third-party formats for the first 3592 * time in VirtualBox (such as VMDK for which VDOpen() needs to 3593 * generate an UUID if it is missing) */ 3594 if ( (m->hddOpenMode == OpenReadOnly) 3595 || !isImport 3596 ) 3597 flags |= VD_OPEN_FLAGS_READONLY; 3598 3599 /* Lock the medium, which makes the behavior much more consistent */ 3600 if (flags & VD_OPEN_FLAGS_READONLY) 3601 rc = LockRead(NULL); 3602 else 3603 rc = LockWrite(NULL); 3604 CheckComRCReturnRC(rc); 3605 3606 /* Copies of the input state fields which are not read-only, 3607 * as we're dropping the lock. CAUTION: be extremely careful what 3608 * you do with the contents of this medium object, as you will 3609 * create races if there are concurrent changes. */ 3610 Utf8Str format(m->format); 3611 Utf8Str location(m->locationFull); 3612 ComObjPtr<MediumFormat> formatObj = m->formatObj; 3613 3614 /* "Output" values which can't be set because the lock isn't held 3615 * at the time the values are determined. */ 3616 Guid mediumId = m->id; 3617 uint64_t mediumSize = 0; 3618 uint64_t mediumLogicalSize = 0; 3619 3620 /* leave the lock before a lengthy operation */ 3621 vrc = RTSemEventMultiReset(m->queryInfoSem); 3622 ComAssertRCThrow(vrc, E_FAIL); 3623 m->queryInfoRunning = true; 3624 alock.leave(); 3625 3622 3626 try 3623 3627 { 3624 Utf8Str location(m->locationFull); 3625 3626 /* totally useless to do accessibility checks for host drives */ 3628 /* skip accessibility checks for host drives */ 3627 3629 if (m->hostDrive) 3628 3630 { … … 3630 3632 throw S_OK; 3631 3633 } 3632 3633 /* are we dealing with a new medium constructed using the existing3634 * location? */3635 bool isImport = m->id.isEmpty();3636 3634 3637 3635 PVBOXHDD hdd; … … 3641 3639 try 3642 3640 { 3643 unsigned flags = VD_OPEN_FLAGS_INFO;3644 3645 /* Note that we don't use VD_OPEN_FLAGS_READONLY when opening new3646 * media because that would prevent necessary modifications3647 * when opening media of some third-party formats for the first3648 * time in VirtualBox (such as VMDK for which VDOpen() needs to3649 * generate an UUID if it is missing) */3650 if ( (m->hddOpenMode == OpenReadOnly)3651 || !isImport3652 )3653 flags |= VD_OPEN_FLAGS_READONLY;3654 3655 3641 /** @todo This kind of opening of images is assuming that diff 3656 3642 * images can be opened as base images. Should be fixed ASAP. */ 3657 3643 vrc = VDOpen(hdd, 3658 Utf8Str(m->format).c_str(),3644 format.c_str(), 3659 3645 location.c_str(), 3660 3646 flags, … … 3662 3648 if (RT_FAILURE(vrc)) 3663 3649 { 3664 lastAccessError = Utf8StrFmt(tr("Could not open the medium '% ls'%s"),3665 m->locationFull.raw(), vdError(vrc).raw());3650 lastAccessError = Utf8StrFmt(tr("Could not open the medium '%s'%s"), 3651 location.c_str(), vdError(vrc).c_str()); 3666 3652 throw S_OK; 3667 3653 } 3668 3654 3669 if ( m->formatObj->capabilities() & MediumFormatCapabilities_Uuid)3655 if (formatObj->capabilities() & MediumFormatCapabilities_Uuid) 3670 3656 { 3671 /* modify the UUIDs if necessary */ 3657 /* Modify the UUIDs if necessary. The associated fields are 3658 * not modified by other code, so no need to copy. */ 3672 3659 if (m->setImageId) 3673 3660 { … … 3693 3680 if (isImport) 3694 3681 { 3695 unconst(m->id)= uuid;3696 3697 if (m ->id.isEmpty() && (m->hddOpenMode == OpenReadOnly))3682 mediumId = uuid; 3683 3684 if (mediumId.isEmpty() && (m->hddOpenMode == OpenReadOnly)) 3698 3685 // only when importing a VDMK that has no UUID, create one in memory 3699 unconst(m->id).create();3686 mediumId.create(); 3700 3687 } 3701 3688 else 3702 3689 { 3703 Assert(!m ->id.isEmpty());3704 3705 if (m ->id != uuid)3690 Assert(!mediumId.isEmpty()); 3691 3692 if (mediumId != uuid) 3706 3693 { 3707 3694 lastAccessError = Utf8StrFmt( 3708 tr("UUID {%RTuuid} of the medium '% ls' does not match the value {%RTuuid} stored in the media registry ('%ls')"),3709 &uuid, m->locationFull.raw(), m->id.raw(),3695 tr("UUID {%RTuuid} of the medium '%s' does not match the value {%RTuuid} stored in the media registry ('%ls')"), 3696 &uuid, location.c_str(), mediumId.raw(), 3710 3697 mVirtualBox->settingsFilePath().raw()); 3711 3698 throw S_OK; … … 3722 3709 { 3723 3710 if (m->setImageId) 3724 unconst(m->id)= m->imageId;3711 mediumId = m->imageId; 3725 3712 else 3726 unconst(m->id).create();3713 mediumId.create(); 3727 3714 } 3728 3715 } … … 3756 3743 { 3757 3744 lastAccessError = Utf8StrFmt( 3758 tr("Parent hard disk with UUID {%RTuuid} of the hard disk '% ls' is not found in the media registry ('%ls')"),3759 &parentId, m->locationFull.raw(),3745 tr("Parent hard disk with UUID {%RTuuid} of the hard disk '%s' is not found in the media registry ('%ls')"), 3746 &parentId, location.c_str(), 3760 3747 mVirtualBox->settingsFilePath().raw()); 3761 3748 throw S_OK; … … 3785 3772 { 3786 3773 lastAccessError = Utf8StrFmt( 3787 tr("Hard disk '% ls' is differencing but it is not associated with any parent hard disk in the media registry ('%ls')"),3788 m->locationFull.raw(),3774 tr("Hard disk '%s' is differencing but it is not associated with any parent hard disk in the media registry ('%ls')"), 3775 location.c_str(), 3789 3776 mVirtualBox->settingsFilePath().raw()); 3790 3777 throw S_OK; … … 3796 3783 { 3797 3784 lastAccessError = Utf8StrFmt( 3798 tr ("Parent UUID {%RTuuid} of the hard disk '% ls' does not match UUID {%RTuuid} of its parent hard disk stored in the media registry ('%ls')"),3799 &parentId, m->locationFull.raw(),3785 tr ("Parent UUID {%RTuuid} of the hard disk '%s' does not match UUID {%RTuuid} of its parent hard disk stored in the media registry ('%ls')"), 3786 &parentId, location.c_str(), 3800 3787 mParent->id().raw(), 3801 3788 mVirtualBox->settingsFilePath().raw()); … … 3809 3796 } 3810 3797 3811 m ->size = VDGetFileSize(hdd, 0);3812 m ->logicalSize = VDGetSize(hdd, 0) / _1M;3798 mediumSize = VDGetFileSize(hdd, 0); 3799 mediumLogicalSize = VDGetSize(hdd, 0) / _1M; 3813 3800 3814 3801 success = true; … … 3829 3816 alock.enter(); 3830 3817 3818 if (isImport) 3819 unconst(m->id) = mediumId; 3820 3831 3821 if (success) 3822 { 3823 m->size = mediumSize; 3824 m->logicalSize = mediumLogicalSize; 3832 3825 m->lastAccessError.setNull(); 3826 } 3833 3827 else 3834 3828 { 3835 3829 m->lastAccessError = lastAccessError; 3836 LogWarningFunc(("'% ls' is not accessible (error='%ls', rc=%Rhrc, vrc=%Rrc)\n",3837 m->locationFull.raw(), m->lastAccessError.raw(),3830 LogWarningFunc(("'%s' is not accessible (error='%ls', rc=%Rhrc, vrc=%Rrc)\n", 3831 location.c_str(), m->lastAccessError.raw(), 3838 3832 rc, vrc)); 3839 3833 } 3840 3834 3841 3835 /* inform other callers if there are any */ 3842 if (m->queryInfoCallers > 0) 3843 { 3844 RTSemEventMultiSignal(m->queryInfoSem); 3845 } 3836 RTSemEventMultiSignal(m->queryInfoSem); 3837 m->queryInfoRunning = false; 3838 3839 /* Set the proper state according to the result of the check */ 3840 if (success) 3841 m->preLockState = MediumState_Created; 3846 3842 else 3847 { 3848 /* delete the semaphore ourselves */ 3849 RTSemEventMultiDestroy(m->queryInfoSem); 3850 m->queryInfoSem = NIL_RTSEMEVENTMULTI; 3851 } 3852 3853 if (tempStateSet) 3854 { 3855 /* Set the proper state according to the result of the check */ 3856 if (success) 3857 m->state = MediumState_Created; 3858 else 3859 m->state = MediumState_Inaccessible; 3860 LogFlowThisFunc(("restored state=%d\n", m->state)); 3861 } 3843 m->preLockState = MediumState_Inaccessible; 3844 3845 if (flags & VD_OPEN_FLAGS_READONLY) 3846 rc = UnlockRead(NULL); 3862 3847 else 3863 { 3864 /* we're locked, use a special field to store the result */ 3865 m->accessibleInLock = success; 3866 } 3848 rc = UnlockWrite(NULL); 3849 CheckComRCReturnRC(rc); 3867 3850 3868 3851 return rc; … … 4493 4476 4494 4477 /** 4495 * Initializes the image medium object by opening an image file at the specified4496 * location.4497 *4498 * @param aVirtualBox Parent VirtualBox object.4499 * @param aLocation Path to the image file (can be relative to the4500 * VirtualBox home directory).4501 * @param aId UUID of the image.4502 */4503 HRESULT Medium::protectedInit(VirtualBox *aVirtualBox, CBSTR aLocation,4504 const Guid &aId)4505 {4506 LogFlowThisFunc(("aLocation='%ls', aId={%RTuuid}\n", aLocation, aId.raw()));4507 4508 AssertReturn(aVirtualBox, E_INVALIDARG);4509 AssertReturn(aLocation, E_INVALIDARG);4510 AssertReturn(!aId.isEmpty(), E_INVALIDARG);4511 4512 /* Enclose the state transition NotReady->InInit->Ready */4513 AutoInitSpan autoInitSpan(this);4514 AssertReturn(autoInitSpan.isOk(), E_FAIL);4515 4516 HRESULT rc = S_OK;4517 4518 /* share parent weakly */4519 unconst(mVirtualBox) = aVirtualBox;4520 4521 /* register with parent early, since uninit() will unconditionally4522 * unregister on failure */4523 mVirtualBox->addDependentChild(this);4524 4525 /* there must be a storage unit */4526 m->state = MediumState_Created;4527 4528 unconst(m->id) = aId;4529 rc = setLocation(aLocation);4530 CheckComRCReturnRC(rc);4531 4532 LogFlowThisFunc(("m->locationFull='%ls'\n", m->locationFull.raw()));4533 4534 /* get all the information about the medium from the file */4535 rc = queryInfo();4536 4537 if (SUCCEEDED(rc))4538 {4539 /* if the image file is not accessible, it's not acceptable for the4540 * newly opened media so convert this into an error */4541 if (!m->lastAccessError.isEmpty())4542 rc = setError(VBOX_E_FILE_ERROR, Utf8Str(m->lastAccessError).c_str());4543 }4544 4545 /* Confirm a successful initialization when it's the case */4546 if (SUCCEEDED(rc))4547 autoInitSpan.setSucceeded();4548 4549 return rc;4550 }4551 4552 /**4553 * Initializes the image medium object by loading its data from the given4554 * settings node.4555 *4556 * Note that it is assumed that this method is called only for registered media.4557 *4558 * @param aVirtualBox Parent VirtualBox object.4559 * @param aImageNode Either <DVDImage> or <FloppyImage> settings node.4560 */4561 HRESULT Medium::protectedInit(VirtualBox *aVirtualBox,4562 const settings::Medium &data)4563 {4564 AssertReturn(aVirtualBox, E_INVALIDARG);4565 4566 /* Enclose the state transition NotReady->InInit->Ready */4567 AutoInitSpan autoInitSpan(this);4568 AssertReturn(autoInitSpan.isOk(), E_FAIL);4569 4570 HRESULT rc = S_OK;4571 4572 /* share parent weakly */4573 unconst(mVirtualBox) = aVirtualBox;4574 4575 /* register with parent early, since uninit() will unconditionally4576 * unregister on failure */4577 mVirtualBox->addDependentChild(this);4578 4579 /* see below why we don't call queryInfo() (and therefore treat the medium4580 * as inaccessible for now */4581 m->state = MediumState_Inaccessible;4582 4583 /* required */4584 unconst(m->id) = data.uuid;4585 /* required */4586 rc = setLocation(data.strLocation);4587 CheckComRCReturnRC(rc);4588 4589 m->description = data.strDescription;4590 4591 LogFlowThisFunc(("m->locationFull='%ls', m->id={%RTuuid}\n",4592 m->locationFull.raw(), m->id.raw()));4593 4594 /* Don't call queryInfo() for registered media to prevent the calling4595 * thread (i.e. the VirtualBox server startup thread) from an unexpected4596 * freeze but mark it as initially inaccessible instead. The vital UUID and4597 * location properties are read from the registry file above; to get the4598 * actual state and the rest of the data, the user will have to call4599 * COMGETTER(State).*/4600 4601 /* Confirm a successful initialization when it's the case */4602 if (SUCCEEDED(rc))4603 autoInitSpan.setSucceeded();4604 4605 return rc;4606 }4607 4608 /**4609 * Uninitializes the instance.4610 *4611 * Called either from FinalRelease() or by the parent when it gets destroyed.4612 */4613 void Medium::protectedUninit()4614 {4615 LogFlowThisFunc(("\n"));4616 4617 /* Enclose the state transition Ready->InUninit->NotReady */4618 AutoUninitSpan autoUninitSpan(this);4619 if (autoUninitSpan.uninitDone())4620 return;4621 4622 mVirtualBox->removeDependentChild(this);4623 4624 unconst(mVirtualBox).setNull();4625 }4626 4627 // private methods4628 ////////////////////////////////////////////////////////////////////////////////4629 4630 /**4631 4478 * Checks that the format ID is valid and sets it on success. 4632 4479 * … … 4691 4538 tr("Hard disk '%ls' has %d child hard disks"), 4692 4539 children().size()); 4693 4694 return S_OK;4695 }4696 4697 /**4698 * @note Called from within this object's AutoWriteLock.4699 */4700 HRESULT Medium::canAttach(const Guid & /* aMachineId */,4701 const Guid & /* aSnapshotId */)4702 {4703 if (m->numCreateDiffTasks > 0)4704 return setError(E_FAIL,4705 tr("One or more differencing child hard disks are being created for the hard disk '%ls' (%u)"),4706 m->locationFull.raw(), m->numCreateDiffTasks);4707 4540 4708 4541 return S_OK; -
trunk/src/VBox/Main/include/MediumImpl.h
r23947 r24210 166 166 const Bstr& location() const; 167 167 const Bstr& locationFull() const; 168 // const BackRefList& backRefs() const;169 168 170 169 const Guid* getFirstMachineBackrefId() const; … … 261 260 protected: 262 261 263 // protected initializer/uninitializer for internal purposes only264 HRESULT protectedInit(VirtualBox *aVirtualBox, 265 CBSTR aLocation,266 const Guid &aId);267 HRESULT protectedInit(VirtualBox *aVirtualBox,268 const settings::Medium &data); 269 void protectedUninit(); 262 RWLockHandle* treeLock(); 263 264 /** Reimplements VirtualBoxWithTypedChildren::childrenLock() to return 265 * treeLock(). */ 266 RWLockHandle *childrenLock() { return treeLock(); } 267 268 private: 270 269 271 270 HRESULT queryInfo(); … … 280 279 281 280 /** 282 * Performs extra checks if the medium can be attached to the specified283 * VM and shapshot at the given time and returns S_OK in this case.284 * Otherwise, returns a respective error message. Called by attachTo() from285 * within this object's AutoWriteLock.286 */287 HRESULT canAttach(const Guid & /* aMachineId */,288 const Guid & /* aSnapshotId */);289 290 /**291 281 * Unregisters this medium with mVirtualBox. Called by Close() from within 292 282 * this object's AutoMayUninitSpan and from under mVirtualBox write lock. … … 309 299 ComObjPtr<Progress> *aProgress, 310 300 bool aWait); 311 312 RWLockHandle* treeLock();313 314 /** Reimplements VirtualBoxWithTypedChildren::childrenLock() to return315 * treeLock(). */316 RWLockHandle *childrenLock() { return treeLock(); }317 318 private:319 301 320 302 HRESULT setLocation(const Utf8Str &aLocation, const Utf8Str &aFormat = Utf8Str());
Note:
See TracChangeset
for help on using the changeset viewer.