Changeset 18115 in vbox for trunk/src/VBox/Main
- Timestamp:
- Mar 20, 2009 1:10:58 PM (16 years ago)
- Location:
- trunk/src/VBox/Main
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/HardDiskImpl.cpp
r17974 r18115 59 59 { 60 60 enum Operation { CreateBase, CreateDiff, 61 Merge, Clone, Delete, Reset };61 Merge, Clone, Flatten, Delete, Reset }; 62 62 63 63 HardDisk *that; … … 91 91 } 92 92 93 void setData (CloneChain *aChain) 94 { 95 AssertReturnVoid (aChain != NULL); 96 d.source.reset (aChain); 97 } 98 93 99 HRESULT startThread(); 94 100 HRESULT runNow(); … … 106 112 HardDiskVariant_T variant; 107 113 108 /* CreateDiff */114 /* CreateDiff, Flatten */ 109 115 110 116 ComObjPtr<HardDisk> target; 117 118 /* Flatten */ 119 120 /** Hard disks to open, in {parent,child} order */ 121 std::auto_ptr <CloneChain> source; 111 122 112 123 /* Merge */ … … 423 434 /** Children of the source when backward merge (if any) */ 424 435 List mChildren; 436 }; 437 438 //////////////////////////////////////////////////////////////////////////////// 439 440 /** 441 * Helper class for clone operations. 442 * 443 * @note It is assumed that when modifying methods of this class are called, 444 * HardDisk::treeLock() is held in read mode. 445 */ 446 class HardDisk::CloneChain : public HardDisk::List, 447 public com::SupportErrorInfoBase 448 { 449 public: 450 451 CloneChain () {} 452 453 ~CloneChain() 454 { 455 for (iterator it = begin(); it != end(); ++ it) 456 { 457 AutoWriteLock alock (*it); 458 Assert ((*it)->m.state == MediaState_LockedRead); 459 if ((*it)->m.state == MediaState_LockedRead) 460 (*it)->UnlockRead (NULL); 461 462 (*it)->releaseCaller(); 463 } 464 } 465 466 HRESULT addImage (HardDisk *aHardDisk) 467 { 468 HRESULT rc = aHardDisk->addCaller(); 469 CheckComRCReturnRC (rc); 470 471 push_front (aHardDisk); 472 473 return S_OK; 474 } 475 476 HRESULT lockImagesRead () 477 { 478 /* Lock all disks in the chain in {parent, child} order, 479 * and make sure they are accessible. */ 480 /// @todo code duplication with SessionMachine::lockMedia, see below 481 ErrorInfoKeeper eik (true /* aIsNull */); 482 MultiResult mrc (S_OK); 483 for (List::const_iterator it = begin(); it != end(); ++ it) 484 { 485 HRESULT rc = S_OK; 486 MediaState_T mediaState; 487 rc = (*it)->LockRead(&mediaState); 488 CheckComRCReturnRC (rc); 489 490 if (mediaState == MediaState_Inaccessible) 491 { 492 rc = (*it)->COMGETTER(State) (&mediaState); 493 CheckComRCReturnRC (rc); 494 Assert (mediaState == MediaState_LockedRead); 495 496 /* Note that we locked the medium already, so use the error 497 * value to see if there was an accessibility failure */ 498 Bstr error; 499 rc = (*it)->COMGETTER(LastAccessError) (error.asOutParam()); 500 CheckComRCReturnRC (rc); 501 502 if (!error.isNull()) 503 { 504 Bstr loc; 505 rc = (*it)->COMGETTER(Location) (loc.asOutParam()); 506 CheckComRCThrowRC (rc); 507 508 /* collect multiple errors */ 509 eik.restore(); 510 511 /* be in sync with MediumBase::setStateError() */ 512 Assert (!error.isEmpty()); 513 mrc = setError (E_FAIL, 514 tr ("Medium '%ls' is not accessible. %ls"), 515 loc.raw(), error.raw()); 516 517 eik.fetch(); 518 } 519 } 520 } 521 522 eik.restore(); 523 CheckComRCReturnRC ((HRESULT) mrc); 524 525 return S_OK; 526 } 527 528 protected: 529 530 // SupportErrorInfoBase interface 531 const GUID &mainInterfaceID() const { return COM_IIDOF (IHardDisk); } 532 const char *componentName() const { return HardDisk::ComponentName(); } 533 534 private: 535 425 536 }; 426 537 … … 713 824 * they will still be read and accessible (for possible backward 714 825 * compatibility; we can also clean them up from the XML upon next 715 * XML format versi nochange if we wish) */826 * XML format version change if we wish) */ 716 827 Key::List properties = aNode.keys ("Property"); 717 828 for (Key::List::const_iterator it = properties.begin(); … … 1330 1441 AutoMultiWriteLock2 alock (this, target); 1331 1442 1332 /* We want to be locked for reading as long as the clone hard disk is being1333 * created*/1443 /* We want to be locked for reading as long as the clone hard disk is 1444 * being created. */ 1334 1445 rc = LockRead (NULL); 1335 1446 CheckComRCReturnRC (rc); … … 1388 1499 1389 1500 STDMETHODIMP HardDisk::FlattenTo (IHardDisk *aTarget, 1390 HardDiskVariant_T /* aVariant */,1501 HardDiskVariant_T aVariant, 1391 1502 IProgress **aProgress) 1392 1503 { … … 1397 1508 CheckComRCReturnRC (autoCaller.rc()); 1398 1509 1399 ReturnComNotImplemented(); 1510 ComObjPtr <HardDisk> target; 1511 HRESULT rc = mVirtualBox->cast (aTarget, target); 1512 CheckComRCReturnRC (rc); 1513 1514 AutoMultiWriteLock2 alock (this, target); 1515 1516 ComObjPtr <Progress> progress; 1517 1518 try 1519 { 1520 if (target->m.state != MediaState_NotCreated) 1521 throw target->setStateError(); 1522 1523 /** @todo separate out creating/locking an image chain from 1524 * SessionMachine::lockMedia and use it from here too. 1525 * logically this belongs into HardDisk functionality. */ 1526 1527 /* we walk the tree */ 1528 AutoReadLock treeLock (this->treeLock()); 1529 1530 /* Build the chain and at the end lock images in the proper order. */ 1531 std::auto_ptr <CloneChain> chain (new CloneChain ()); 1532 HardDisk *hd = this; 1533 do 1534 { 1535 rc = chain->addImage(hd); 1536 CheckComRCThrowRC (rc); 1537 1538 hd = hd->mParent; 1539 } while (hd); 1540 rc = chain->lockImagesRead(); 1541 CheckComRCThrowRC (rc); 1542 1543 progress.createObject(); 1544 rc = progress->init (mVirtualBox, static_cast <IHardDisk *> (this), 1545 BstrFmt (tr ("Creating flattened clone hard disk '%ls'"), 1546 target->m.locationFull.raw()), 1547 FALSE /* aCancelable */); 1548 CheckComRCThrowRC (rc); 1549 1550 /* setup task object and thread to carry out the operation 1551 * asynchronously */ 1552 1553 std::auto_ptr <Task> task (new Task (this, progress, Task::Flatten)); 1554 AssertComRCThrowRC (task->autoCaller.rc()); 1555 1556 task->setData (target); 1557 task->d.variant = aVariant; 1558 task->setData (chain.release()); 1559 1560 rc = task->startThread(); 1561 CheckComRCThrowRC (rc); 1562 1563 /* go to Creating state before leaving the lock */ 1564 target->m.state = MediaState_Creating; 1565 1566 /* task is now owned (or already deleted) by taskThread() so release it */ 1567 task.release(); 1568 } 1569 catch (HRESULT aRC) 1570 { 1571 rc = aRC; 1572 } 1573 1574 if (FAILED (rc)) 1575 { 1576 HRESULT rc2 = UnlockRead (NULL); 1577 AssertComRC (rc2); 1578 /* Note: on success, taskThread() will unlock this */ 1579 } 1580 else 1581 { 1582 /* return progress to the caller */ 1583 progress.queryInterfaceTo (aProgress); 1584 } 1585 1586 return rc; 1400 1587 } 1401 1588 … … 1751 1938 * changes. 1752 1939 * 1753 * This method is to be called prior to calling the #disc rad() to perform1940 * This method is to be called prior to calling the #discard() to perform 1754 1941 * necessary consistency checks and place involved hard disks to appropriate 1755 1942 * states. If #discard() is not called or fails, the state modifications … … 3436 3623 else 3437 3624 { 3438 /* back to NotCreated on fail iure */3625 /* back to NotCreated on failure */ 3439 3626 that->m.state = MediaState_NotCreated; 3440 3627 … … 3586 3773 else 3587 3774 { 3588 /* back to NotCreated on fail iure */3775 /* back to NotCreated on failure */ 3589 3776 target->m.state = MediaState_NotCreated; 3590 3777 … … 3644 3831 try 3645 3832 { 3646 /* open all hard disks in the chain (they are in the3833 /* Open all hard disks in the chain (they are in the 3647 3834 * {parent,child} order in there. Note that we don't lock 3648 3835 * objects in this chain since they must be in states 3649 * (Deleting and LockedWrite) that prevent from chan ing3836 * (Deleting and LockedWrite) that prevent from changing 3650 3837 * their format and location fields from outside. */ 3651 3838 … … 3926 4113 /* Lock both in {parent,child} order. The lock is also used as a 3927 4114 * signal from the task initiator (which releases it only after 3928 * RTThreadCreate()) that we can start the job */4115 * RTThreadCreate()) that we can start the job. */ 3929 4116 AutoMultiWriteLock2 thatLock (that, target); 3930 4117 … … 4062 4249 else 4063 4250 { 4064 /* back to NotCreated on fail iure */4251 /* back to NotCreated on failure */ 4065 4252 target->m.state = MediaState_NotCreated; 4066 4253 … … 4083 4270 /* Note that in sync mode, it's the caller's responsibility to 4084 4271 * unlock the hard disk */ 4272 4273 break; 4274 } 4275 4276 //////////////////////////////////////////////////////////////////////// 4277 4278 case Task::Flatten: 4279 { 4280 ComObjPtr<HardDisk> &target = task->d.target; 4281 4282 /* Lock both in {parent,child} order. The lock is also used as a 4283 * signal from the task initiator (which releases it only after 4284 * RTThreadCreate()) that we can start the job. */ 4285 AutoMultiWriteLock2 thatLock (that, target); 4286 4287 CloneChain *chain = task->d.source.get(); 4288 4289 uint64_t size = 0, logicalSize = 0; 4290 4291 /* The object may request a specific UUID (through a special form of 4292 * the setLocation() argument). Otherwise we have to generate it */ 4293 Guid targetId = target->m.id; 4294 bool generateUuid = targetId.isEmpty(); 4295 if (generateUuid) 4296 { 4297 targetId.create(); 4298 /* VirtualBox::registerHardDisk() will need UUID */ 4299 unconst (target->m.id) = targetId; 4300 } 4301 4302 try 4303 { 4304 PVBOXHDD hdd; 4305 int vrc = VDCreate (that->mm.vdDiskIfaces, &hdd); 4306 ComAssertRCThrow (vrc, E_FAIL); 4307 4308 try 4309 { 4310 /* Open all hard disk images in the chain. */ 4311 for (List::const_iterator it = chain->begin(); 4312 it != chain->end(); ++ it) 4313 { 4314 /* sanity check */ 4315 Assert ((*it)->m.state == MediaState_LockedRead); 4316 4317 /** Open all diff images in read-only mode. */ 4318 vrc = VDOpen (hdd, Utf8Str ((*it)->mm.format), 4319 Utf8Str ((*it)->m.locationFull), 4320 VD_OPEN_FLAGS_READONLY, 4321 (*it)->mm.vdDiskIfaces); 4322 if (RT_FAILURE (vrc)) 4323 { 4324 throw setError (E_FAIL, 4325 tr ("Could not open the hard disk storage " 4326 "unit '%s'%s"), 4327 Utf8Str ((*it)->m.locationFull).raw(), 4328 that->vdError (vrc).raw()); 4329 } 4330 } 4331 4332 /* unlock before the potentially lengthy operation */ 4333 thatLock.leave(); 4334 4335 Utf8Str targetFormat (target->mm.format); 4336 Utf8Str targetLocation (target->m.locationFull); 4337 4338 Assert (target->m.state == MediaState_Creating); 4339 4340 /* ensure the target directory exists */ 4341 rc = VirtualBox::ensureFilePathExists (targetLocation); 4342 CheckComRCThrowRC (rc); 4343 4344 /* needed for vdProgressCallback */ 4345 that->mm.vdProgress = task->progress; 4346 4347 PVBOXHDD targetHdd; 4348 int vrc = VDCreate (that->mm.vdDiskIfaces, &targetHdd); 4349 ComAssertRCThrow (vrc, E_FAIL); 4350 4351 vrc = VDCopy (hdd, VD_LAST_IMAGE, targetHdd, targetFormat, 4352 targetLocation, false, 0, task->d.variant, 4353 targetId.raw(), NULL, 4354 target->mm.vdDiskIfaces, 4355 that->mm.vdDiskIfaces); 4356 4357 that->mm.vdProgress = NULL; 4358 4359 if (RT_FAILURE (vrc)) 4360 { 4361 VDDestroy (targetHdd); 4362 4363 throw setError (E_FAIL, 4364 tr ("Could not create the flattened hard disk " 4365 "'%s'%s"), 4366 targetLocation.raw(), that->vdError (vrc).raw()); 4367 } 4368 4369 size = VDGetFileSize (targetHdd, 0); 4370 logicalSize = VDGetSize (targetHdd, 0) / _1M; 4371 4372 VDDestroy (targetHdd); 4373 } 4374 catch (HRESULT aRC) { rc = aRC; } 4375 4376 VDDestroy (hdd); 4377 } 4378 catch (HRESULT aRC) { rc = aRC; } 4379 4380 if (SUCCEEDED (rc)) 4381 { 4382 Assert (target->mParent.isNull()); 4383 4384 /* just register */ 4385 rc = that->mVirtualBox->registerHardDisk(target); 4386 } 4387 4388 thatLock.maybeEnter(); 4389 4390 if (SUCCEEDED (rc)) 4391 { 4392 target->m.state = MediaState_Created; 4393 4394 target->m.size = size; 4395 target->mm.logicalSize = logicalSize; 4396 } 4397 else 4398 { 4399 /* back to NotCreated on failure */ 4400 target->m.state = MediaState_NotCreated; 4401 4402 /* reset UUID to prevent it from being reused next time */ 4403 if (generateUuid) 4404 unconst (target->m.id).clear(); 4405 } 4406 4407 /* Everything is explicitly unlocked when the task exits, 4408 * as the task destruction also destroys the source chain. */ 4085 4409 4086 4410 break; -
trunk/src/VBox/Main/MachineImpl.cpp
r17942 r18115 10923 10923 bool first = true; 10924 10924 10925 /** @todo split out the media locking, and put it into 10926 * HardDiskImpl.cpp, as it needs this functionality too. */ 10925 10927 while (!hd.isNull()) 10926 10928 { -
trunk/src/VBox/Main/include/HardDiskImpl.h
r17970 r18115 56 56 57 57 class MergeChain; 58 class CloneChain; 58 59 59 60 VIRTUALBOXSUPPORTTRANSLATION_OVERRIDE (HardDisk)
Note:
See TracChangeset
for help on using the changeset viewer.