VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/StorageControllerImpl.cpp@ 65120

Last change on this file since 65120 was 65103, checked in by vboxsync, 8 years ago

Main: doxygen fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.9 KB
Line 
1/* $Id: StorageControllerImpl.cpp 65103 2017-01-04 12:08:18Z vboxsync $ */
2
3/** @file
4 *
5 * Implementation of IStorageController.
6 */
7
8/*
9 * Copyright (C) 2008-2016 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20#include "StorageControllerImpl.h"
21#include "MachineImpl.h"
22#include "VirtualBoxImpl.h"
23#include "SystemPropertiesImpl.h"
24
25#include <iprt/string.h>
26#include <iprt/cpp/utils.h>
27
28#include <VBox/err.h>
29#include <VBox/settings.h>
30
31#include <algorithm>
32
33#include "AutoStateDep.h"
34#include "AutoCaller.h"
35#include "Logging.h"
36
37// defines
38/////////////////////////////////////////////////////////////////////////////
39
40struct StorageController::Data
41{
42 Data(Machine * const aMachine)
43 : pVirtualBox(NULL),
44 pSystemProperties(NULL),
45 pParent(aMachine)
46 {
47 unconst(pVirtualBox) = aMachine->i_getVirtualBox();
48 unconst(pSystemProperties) = pVirtualBox->i_getSystemProperties();
49 }
50
51 VirtualBox * const pVirtualBox;
52 SystemProperties * const pSystemProperties;
53 Machine * const pParent;
54 const ComObjPtr<StorageController> pPeer;
55
56 Backupable<settings::StorageController> bd;
57};
58
59
60// constructor / destructor
61/////////////////////////////////////////////////////////////////////////////
62
63DEFINE_EMPTY_CTOR_DTOR(StorageController)
64
65HRESULT StorageController::FinalConstruct()
66{
67 return BaseFinalConstruct();
68}
69
70void StorageController::FinalRelease()
71{
72 uninit();
73 BaseFinalRelease();
74}
75
76// public initializer/uninitializer for internal purposes only
77/////////////////////////////////////////////////////////////////////////////
78
79/**
80 * Initializes the storage controller object.
81 *
82 * @returns COM result indicator.
83 * @param aParent Pointer to our parent object.
84 * @param aName Name of the storage controller.
85 * @param aStorageBus Type of the storage bus.
86 * @param aInstance Instance number of the storage controller.
87 * @param fBootable Bootable flag.
88 */
89HRESULT StorageController::init(Machine *aParent,
90 const Utf8Str &aName,
91 StorageBus_T aStorageBus,
92 ULONG aInstance, bool fBootable)
93{
94 LogFlowThisFunc(("aParent=%p aName=\"%s\" aInstance=%u\n",
95 aParent, aName.c_str(), aInstance));
96
97 ComAssertRet(aParent && !aName.isEmpty(), E_INVALIDARG);
98 if ( (aStorageBus <= StorageBus_Null)
99 || (aStorageBus > StorageBus_PCIe))
100 return setError(E_INVALIDARG,
101 tr("Invalid storage connection type"));
102
103 ULONG maxInstances;
104 ChipsetType_T chipsetType;
105 HRESULT rc = aParent->COMGETTER(ChipsetType)(&chipsetType);
106 if (FAILED(rc))
107 return rc;
108 rc = aParent->i_getVirtualBox()->i_getSystemProperties()->
109 GetMaxInstancesOfStorageBus(chipsetType, aStorageBus, &maxInstances);
110 if (FAILED(rc))
111 return rc;
112 if (aInstance >= maxInstances)
113 return setError(E_INVALIDARG,
114 tr("Too many storage controllers of this type"));
115
116 /* Enclose the state transition NotReady->InInit->Ready */
117 AutoInitSpan autoInitSpan(this);
118 AssertReturn(autoInitSpan.isOk(), E_FAIL);
119
120 m = new Data(aParent);
121
122 /* m->pPeer is left null */
123
124 m->bd.allocate();
125
126 m->bd->strName = aName;
127 m->bd->ulInstance = aInstance;
128 m->bd->fBootable = fBootable;
129 m->bd->storageBus = aStorageBus;
130 if ( aStorageBus != StorageBus_IDE
131 && aStorageBus != StorageBus_Floppy)
132 m->bd->fUseHostIOCache = false;
133 else
134 m->bd->fUseHostIOCache = true;
135
136 switch (aStorageBus)
137 {
138 case StorageBus_IDE:
139 m->bd->ulPortCount = 2;
140 m->bd->controllerType = StorageControllerType_PIIX4;
141 break;
142 case StorageBus_SATA:
143 m->bd->ulPortCount = 30;
144 m->bd->controllerType = StorageControllerType_IntelAhci;
145 break;
146 case StorageBus_SCSI:
147 m->bd->ulPortCount = 16;
148 m->bd->controllerType = StorageControllerType_LsiLogic;
149 break;
150 case StorageBus_Floppy:
151 m->bd->ulPortCount = 1;
152 m->bd->controllerType = StorageControllerType_I82078;
153 break;
154 case StorageBus_SAS:
155 m->bd->ulPortCount = 8;
156 m->bd->controllerType = StorageControllerType_LsiLogicSas;
157 break;
158 case StorageBus_USB:
159 m->bd->ulPortCount = 8;
160 m->bd->controllerType = StorageControllerType_USB;
161 break;
162 case StorageBus_PCIe:
163 m->bd->ulPortCount = 1;
164 m->bd->controllerType = StorageControllerType_NVMe;
165 break;
166 case StorageBus_Null: break; /* Shut up MSC. */
167 }
168
169 /* Confirm a successful initialization */
170 autoInitSpan.setSucceeded();
171
172 return S_OK;
173}
174
175/**
176 * Initializes the object given another object
177 * (a kind of copy constructor). This object shares data with
178 * the object passed as an argument.
179 *
180 * @param aParent Pointer to our parent object.
181 * @param aThat
182 * @param aReshare
183 * When false, the original object will remain a data owner.
184 * Otherwise, data ownership will be transferred from the original
185 * object to this one.
186 *
187 * @note This object must be destroyed before the original object
188 * it shares data with is destroyed.
189 *
190 * @note Locks @a aThat object for writing if @a aReshare is @c true, or for
191 * reading if @a aReshare is false.
192 */
193HRESULT StorageController::init(Machine *aParent,
194 StorageController *aThat,
195 bool aReshare /* = false */)
196{
197 LogFlowThisFunc(("aParent=%p, aThat=%p, aReshare=%RTbool\n",
198 aParent, aThat, aReshare));
199
200 ComAssertRet(aParent && aThat, E_INVALIDARG);
201
202 /* Enclose the state transition NotReady->InInit->Ready */
203 AutoInitSpan autoInitSpan(this);
204 AssertReturn(autoInitSpan.isOk(), E_FAIL);
205
206 m = new Data(aParent);
207
208 /* sanity */
209 AutoCaller thatCaller(aThat);
210 AssertComRCReturnRC(thatCaller.rc());
211
212 if (aReshare)
213 {
214 AutoWriteLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
215
216 unconst(aThat->m->pPeer) = this;
217 m->bd.attach(aThat->m->bd);
218 }
219 else
220 {
221 unconst(m->pPeer) = aThat;
222
223 AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
224 m->bd.share(aThat->m->bd);
225 }
226
227 /* Confirm successful initialization */
228 autoInitSpan.setSucceeded();
229
230 return S_OK;
231}
232
233/**
234 * Initializes the storage controller object given another guest object
235 * (a kind of copy constructor). This object makes a private copy of data
236 * of the original object passed as an argument.
237 */
238HRESULT StorageController::initCopy(Machine *aParent, StorageController *aThat)
239{
240 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
241
242 ComAssertRet(aParent && aThat, E_INVALIDARG);
243
244 /* Enclose the state transition NotReady->InInit->Ready */
245 AutoInitSpan autoInitSpan(this);
246 AssertReturn(autoInitSpan.isOk(), E_FAIL);
247
248 m = new Data(aParent);
249 /* m->pPeer is left null */
250
251 AutoCaller thatCaller(aThat);
252 AssertComRCReturnRC(thatCaller.rc());
253
254 AutoReadLock thatlock(aThat COMMA_LOCKVAL_SRC_POS);
255 m->bd.attachCopy(aThat->m->bd);
256
257 /* Confirm a successful initialization */
258 autoInitSpan.setSucceeded();
259
260 return S_OK;
261}
262
263
264/**
265 * Uninitializes the instance and sets the ready flag to FALSE.
266 * Called either from FinalRelease() or by the parent when it gets destroyed.
267 */
268void StorageController::uninit()
269{
270 LogFlowThisFunc(("\n"));
271
272 /* Enclose the state transition Ready->InUninit->NotReady */
273 AutoUninitSpan autoUninitSpan(this);
274 if (autoUninitSpan.uninitDone())
275 return;
276
277 m->bd.free();
278
279 unconst(m->pPeer) = NULL;
280 unconst(m->pParent) = NULL;
281
282 delete m;
283 m = NULL;
284}
285
286
287// IStorageController properties
288HRESULT StorageController::getName(com::Utf8Str &aName)
289{
290 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
291
292 aName = m->bd->strName;
293
294 return S_OK;
295}
296
297HRESULT StorageController::setName(const com::Utf8Str &aName)
298{
299 /* the machine needs to be mutable */
300 AutoMutableStateDependency adep(m->pParent);
301 if (FAILED(adep.rc())) return adep.rc();
302
303 AutoMultiWriteLock2 alock(m->pParent, this COMMA_LOCKVAL_SRC_POS);
304
305 if (m->bd->strName != aName)
306 {
307 ComObjPtr<StorageController> ctrl;
308 HRESULT rc = m->pParent->i_getStorageControllerByName(aName, ctrl, false /* aSetError */);
309 if (SUCCEEDED(rc))
310 return setError(VBOX_E_OBJECT_IN_USE,
311 tr("Storage controller named '%s' already exists"),
312 aName.c_str());
313
314 Machine::MediaData::AttachmentList atts;
315 rc = m->pParent->i_getMediumAttachmentsOfController(m->bd->strName, atts);
316 for (Machine::MediaData::AttachmentList::const_iterator it = atts.begin();
317 it != atts.end();
318 ++it)
319 {
320 IMediumAttachment *iA = *it;
321 MediumAttachment *pAttach = static_cast<MediumAttachment *>(iA);
322 AutoWriteLock attlock(pAttach COMMA_LOCKVAL_SRC_POS);
323 pAttach->i_updateName(aName);
324 }
325
326
327 m->bd.backup();
328 m->bd->strName = aName;
329
330 m->pParent->i_setModified(Machine::IsModified_Storage);
331 alock.release();
332
333 m->pParent->i_onStorageControllerChange();
334 }
335
336 return S_OK;
337}
338
339HRESULT StorageController::getBus(StorageBus_T *aBus)
340{
341 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
342
343 *aBus = m->bd->storageBus;
344
345 return S_OK;
346}
347
348HRESULT StorageController::getControllerType(StorageControllerType_T *aControllerType)
349{
350 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
351
352 *aControllerType = m->bd->controllerType;
353
354 return S_OK;
355}
356
357HRESULT StorageController::setControllerType(StorageControllerType_T aControllerType)
358{
359 /* the machine needs to be mutable */
360 AutoMutableStateDependency adep(m->pParent);
361 if (FAILED(adep.rc())) return adep.rc();
362
363 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
364
365 HRESULT rc = S_OK;
366
367 switch (m->bd->storageBus)
368 {
369 case StorageBus_IDE:
370 {
371 if ( (aControllerType != StorageControllerType_PIIX3)
372 && (aControllerType != StorageControllerType_PIIX4)
373 && (aControllerType != StorageControllerType_ICH6))
374 rc = E_INVALIDARG;
375 break;
376 }
377 case StorageBus_SATA:
378 {
379 if (aControllerType != StorageControllerType_IntelAhci)
380 rc = E_INVALIDARG;
381 break;
382 }
383 case StorageBus_SCSI:
384 {
385 if ( (aControllerType != StorageControllerType_LsiLogic)
386 && (aControllerType != StorageControllerType_BusLogic))
387 rc = E_INVALIDARG;
388 break;
389 }
390 case StorageBus_Floppy:
391 {
392 if (aControllerType != StorageControllerType_I82078)
393 rc = E_INVALIDARG;
394 break;
395 }
396 case StorageBus_SAS:
397 {
398 if (aControllerType != StorageControllerType_LsiLogicSas)
399 rc = E_INVALIDARG;
400 break;
401 }
402 case StorageBus_USB:
403 {
404 if (aControllerType != StorageControllerType_USB)
405 rc = E_INVALIDARG;
406 break;
407 }
408 case StorageBus_PCIe:
409 {
410 if (aControllerType != StorageControllerType_NVMe)
411 rc = E_INVALIDARG;
412 break;
413 }
414 default:
415 AssertMsgFailed(("Invalid controller type %d\n", m->bd->storageBus));
416 rc = E_INVALIDARG;
417 }
418
419 if (!SUCCEEDED(rc))
420 return setError(rc,
421 tr("Invalid controller type %d"),
422 aControllerType);
423
424 if (m->bd->controllerType != aControllerType)
425 {
426 m->bd.backup();
427 m->bd->controllerType = aControllerType;
428
429 alock.release();
430 AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS); // m->pParent is const, needs no locking
431 m->pParent->i_setModified(Machine::IsModified_Storage);
432 mlock.release();
433
434 m->pParent->i_onStorageControllerChange();
435 }
436
437 return S_OK;
438}
439
440HRESULT StorageController::getMaxDevicesPerPortCount(ULONG *aMaxDevicesPerPortCount)
441{
442 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
443
444 HRESULT rc = m->pSystemProperties->GetMaxDevicesPerPortForStorageBus(m->bd->storageBus, aMaxDevicesPerPortCount);
445
446 return rc;
447}
448
449HRESULT StorageController::getMinPortCount(ULONG *aMinPortCount)
450{
451 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
452
453 HRESULT rc = m->pSystemProperties->GetMinPortCountForStorageBus(m->bd->storageBus, aMinPortCount);
454 return rc;
455}
456
457HRESULT StorageController::getMaxPortCount(ULONG *aMaxPortCount)
458{
459 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
460 HRESULT rc = m->pSystemProperties->GetMaxPortCountForStorageBus(m->bd->storageBus, aMaxPortCount);
461
462 return rc;
463}
464
465HRESULT StorageController::getPortCount(ULONG *aPortCount)
466{
467 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
468
469 *aPortCount = m->bd->ulPortCount;
470
471 return S_OK;
472}
473
474HRESULT StorageController::setPortCount(ULONG aPortCount)
475{
476 /* the machine needs to be mutable */
477 AutoMutableStateDependency adep(m->pParent);
478 if (FAILED(adep.rc())) return adep.rc();
479
480 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
481
482 switch (m->bd->storageBus)
483 {
484 case StorageBus_SATA:
485 {
486 /* AHCI SATA supports a maximum of 30 ports. */
487 if (aPortCount < 1 || aPortCount > 30)
488 return setError(E_INVALIDARG,
489 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
490 aPortCount, 1, 30);
491 break;
492 }
493 case StorageBus_SCSI:
494 {
495 /*
496 * SCSI does not support setting different ports.
497 * (doesn't make sense here either).
498 * The maximum and minimum is 16 and unless the callee
499 * tries to set a different value we return an error.
500 */
501 if (aPortCount != 16)
502 return setError(E_INVALIDARG,
503 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
504 aPortCount, 16, 16);
505 break;
506 }
507 case StorageBus_IDE:
508 {
509 /*
510 * The port count is fixed to 2.
511 */
512 if (aPortCount != 2)
513 return setError(E_INVALIDARG,
514 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
515 aPortCount, 2, 2);
516 break;
517 }
518 case StorageBus_Floppy:
519 {
520 /*
521 * The port count is fixed to 1.
522 */
523 if (aPortCount != 1)
524 return setError(E_INVALIDARG,
525 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
526 aPortCount, 1, 1);
527 break;
528 }
529 case StorageBus_SAS:
530 {
531 /* SAS supports a maximum of 255 ports. */
532 if (aPortCount < 1 || aPortCount > 255)
533 return setError(E_INVALIDARG,
534 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
535 aPortCount, 1, 255);
536 break;
537 }
538 case StorageBus_USB:
539 {
540 /*
541 * The port count is fixed to 8.
542 */
543 if (aPortCount != 8)
544 return setError(E_INVALIDARG,
545 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
546 aPortCount, 8, 8);
547 break;
548 }
549 case StorageBus_PCIe:
550 {
551 /*
552 * PCIe (NVMe in particular) supports theoretically 2^32 - 1
553 * different namespaces, limit the amount artifically here.
554 */
555 if (aPortCount < 1 || aPortCount > 255)
556 return setError(E_INVALIDARG,
557 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
558 aPortCount, 1, 255);
559 break;
560 }
561 default:
562 AssertMsgFailed(("Invalid controller type %d\n", m->bd->storageBus));
563 }
564
565 if (m->bd->ulPortCount != aPortCount)
566 {
567 m->bd.backup();
568 m->bd->ulPortCount = aPortCount;
569
570 alock.release();
571 AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS); // m->pParent is const, needs no locking
572 m->pParent->i_setModified(Machine::IsModified_Storage);
573 mlock.release();
574
575 m->pParent->i_onStorageControllerChange();
576 }
577
578 return S_OK;
579}
580
581HRESULT StorageController::getInstance(ULONG *aInstance)
582{
583 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
584
585 *aInstance = m->bd->ulInstance;
586
587 return S_OK;
588}
589
590HRESULT StorageController::setInstance(ULONG aInstance)
591{
592 /* the machine needs to be mutable */
593 AutoMutableStateDependency adep(m->pParent);
594 if (FAILED(adep.rc())) return adep.rc();
595
596 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
597
598 if (m->bd->ulInstance != aInstance)
599 {
600 m->bd.backup();
601 m->bd->ulInstance = aInstance;
602
603 alock.release();
604 AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS); // m->pParent is const, needs no locking
605 m->pParent->i_setModified(Machine::IsModified_Storage);
606 mlock.release();
607
608 m->pParent->i_onStorageControllerChange();
609 }
610
611 return S_OK;
612}
613
614HRESULT StorageController::getUseHostIOCache(BOOL *fUseHostIOCache)
615{
616 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
617
618 *fUseHostIOCache = m->bd->fUseHostIOCache;
619
620 return S_OK;
621}
622
623HRESULT StorageController::setUseHostIOCache(BOOL fUseHostIOCache)
624{
625 /* the machine needs to be mutable */
626 AutoMutableStateDependency adep(m->pParent);
627 if (FAILED(adep.rc())) return adep.rc();
628
629 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
630
631 if (m->bd->fUseHostIOCache != !!fUseHostIOCache)
632 {
633 m->bd.backup();
634 m->bd->fUseHostIOCache = !!fUseHostIOCache;
635
636 alock.release();
637 AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS); // m->pParent is const, needs no locking
638 m->pParent->i_setModified(Machine::IsModified_Storage);
639 mlock.release();
640
641 m->pParent->i_onStorageControllerChange();
642 }
643
644 return S_OK;
645}
646
647HRESULT StorageController::getBootable(BOOL *fBootable)
648{
649 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
650
651 *fBootable = m->bd->fBootable;
652
653 return S_OK;
654}
655
656// public methods only for internal purposes
657/////////////////////////////////////////////////////////////////////////////
658
659const Utf8Str& StorageController::i_getName() const
660{
661 return m->bd->strName;
662}
663
664StorageControllerType_T StorageController::i_getControllerType() const
665{
666 return m->bd->controllerType;
667}
668
669StorageBus_T StorageController::i_getStorageBus() const
670{
671 return m->bd->storageBus;
672}
673
674ULONG StorageController::i_getInstance() const
675{
676 return m->bd->ulInstance;
677}
678
679bool StorageController::i_getBootable() const
680{
681 return !!m->bd->fBootable;
682}
683
684/**
685 * Checks the validity of a port and device number.
686 *
687 * @retval S_OK If the given port and device numbers are within the range
688 * supported by this controller.
689 * @retval E_INVALIDARG If not. Sets an error.
690 * @param aControllerPort Controller port number.
691 * @param aDevice Device number.
692 */
693HRESULT StorageController::i_checkPortAndDeviceValid(LONG aControllerPort,
694 LONG aDevice)
695{
696 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
697
698 ULONG portCount = m->bd->ulPortCount;
699 ULONG devicesPerPort;
700 HRESULT rc = m->pSystemProperties->GetMaxDevicesPerPortForStorageBus(m->bd->storageBus, &devicesPerPort);
701 if (FAILED(rc)) return rc;
702
703 if ( aControllerPort < 0
704 || aControllerPort >= (LONG)portCount
705 || aDevice < 0
706 || aDevice >= (LONG)devicesPerPort
707 )
708 return setError(E_INVALIDARG,
709 tr("The port and/or device parameter are out of range: port=%d (must be in range [0, %d]), device=%d (must be in range [0, %d])"),
710 (int)aControllerPort, (int)portCount-1, (int)aDevice, (int)devicesPerPort-1);
711
712 return S_OK;
713}
714
715/** @note Locks objects for writing! */
716void StorageController::i_setBootable(BOOL fBootable)
717{
718 AutoCaller autoCaller(this);
719 AssertComRCReturnVoid(autoCaller.rc());
720
721 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
722
723 m->bd.backup();
724 m->bd->fBootable = RT_BOOL(fBootable);
725}
726
727/** @note Locks objects for writing! */
728void StorageController::i_rollback()
729{
730 AutoCaller autoCaller(this);
731 AssertComRCReturnVoid(autoCaller.rc());
732
733 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
734
735 m->bd.rollback();
736}
737
738/**
739 * @note Locks this object for writing, together with the peer object (also
740 * for writing) if there is one.
741 */
742void StorageController::i_commit()
743{
744 /* sanity */
745 AutoCaller autoCaller(this);
746 AssertComRCReturnVoid(autoCaller.rc());
747
748 /* sanity too */
749 AutoCaller peerCaller(m->pPeer);
750 AssertComRCReturnVoid(peerCaller.rc());
751
752 /* lock both for writing since we modify both (m->pPeer is "master" so locked
753 * first) */
754 AutoMultiWriteLock2 alock(m->pPeer, this COMMA_LOCKVAL_SRC_POS);
755
756 if (m->bd.isBackedUp())
757 {
758 m->bd.commit();
759 if (m->pPeer)
760 {
761 // attach new data to the peer and reshare it
762 m->pPeer->m->bd.attach(m->bd);
763 }
764 }
765}
766
767/**
768 * Cancels sharing (if any) by making an independent copy of data.
769 * This operation also resets this object's peer to NULL.
770 *
771 * @note Locks this object for writing, together with the peer object
772 * represented by @a aThat (locked for reading).
773 */
774void StorageController::i_unshare()
775{
776 /* sanity */
777 AutoCaller autoCaller(this);
778 AssertComRCReturnVoid(autoCaller.rc());
779
780 /* sanity too */
781 AutoCaller peerCaller(m->pPeer);
782 AssertComRCReturnVoid(peerCaller.rc());
783
784 /* peer is not modified, lock it for reading (m->pPeer is "master" so locked
785 * first) */
786 AutoReadLock rl(m->pPeer COMMA_LOCKVAL_SRC_POS);
787 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
788
789 if (m->bd.isShared())
790 {
791 if (!m->bd.isBackedUp())
792 m->bd.backup();
793
794 m->bd.commit();
795 }
796
797 unconst(m->pPeer) = NULL;
798}
799
800Machine* StorageController::i_getMachine()
801{
802 return m->pParent;
803}
804
805ComObjPtr<StorageController> StorageController::i_getPeer()
806{
807 return m->pPeer;
808}
809
810// private methods
811/////////////////////////////////////////////////////////////////////////////
812
813
814/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

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