VirtualBox

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

Last change on this file since 74897 was 72973, checked in by vboxsync, 6 years ago

Main: Some early sketches on how to get proper C++ enums with xpidl.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.0 KB
Line 
1/* $Id: StorageControllerImpl.cpp 72973 2018-07-08 13:23:58Z vboxsync $ */
2
3/** @file
4 *
5 * Implementation of IStorageController.
6 */
7
8/*
9 * Copyright (C) 2008-2017 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#ifdef VBOX_WITH_XPCOM_CPP_ENUM_HACK
168 case StorageBus_32BitHack: break; /* Shut up GCC. */
169#endif
170 }
171
172 /* Confirm a successful initialization */
173 autoInitSpan.setSucceeded();
174
175 return S_OK;
176}
177
178/**
179 * Initializes the object given another object
180 * (a kind of copy constructor). This object shares data with
181 * the object passed as an argument.
182 *
183 * @param aParent Pointer to our parent object.
184 * @param aThat
185 * @param aReshare
186 * When false, the original object will remain a data owner.
187 * Otherwise, data ownership will be transferred from the original
188 * object to this one.
189 *
190 * @note This object must be destroyed before the original object
191 * it shares data with is destroyed.
192 *
193 * @note Locks @a aThat object for writing if @a aReshare is @c true, or for
194 * reading if @a aReshare is false.
195 */
196HRESULT StorageController::init(Machine *aParent,
197 StorageController *aThat,
198 bool aReshare /* = false */)
199{
200 LogFlowThisFunc(("aParent=%p, aThat=%p, aReshare=%RTbool\n",
201 aParent, aThat, aReshare));
202
203 ComAssertRet(aParent && aThat, E_INVALIDARG);
204
205 /* Enclose the state transition NotReady->InInit->Ready */
206 AutoInitSpan autoInitSpan(this);
207 AssertReturn(autoInitSpan.isOk(), E_FAIL);
208
209 m = new Data(aParent);
210
211 /* sanity */
212 AutoCaller thatCaller(aThat);
213 AssertComRCReturnRC(thatCaller.rc());
214
215 if (aReshare)
216 {
217 AutoWriteLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
218
219 unconst(aThat->m->pPeer) = this;
220 m->bd.attach(aThat->m->bd);
221 }
222 else
223 {
224 unconst(m->pPeer) = aThat;
225
226 AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
227 m->bd.share(aThat->m->bd);
228 }
229
230 /* Confirm successful initialization */
231 autoInitSpan.setSucceeded();
232
233 return S_OK;
234}
235
236/**
237 * Initializes the storage controller object given another guest object
238 * (a kind of copy constructor). This object makes a private copy of data
239 * of the original object passed as an argument.
240 */
241HRESULT StorageController::initCopy(Machine *aParent, StorageController *aThat)
242{
243 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
244
245 ComAssertRet(aParent && aThat, E_INVALIDARG);
246
247 /* Enclose the state transition NotReady->InInit->Ready */
248 AutoInitSpan autoInitSpan(this);
249 AssertReturn(autoInitSpan.isOk(), E_FAIL);
250
251 m = new Data(aParent);
252 /* m->pPeer is left null */
253
254 AutoCaller thatCaller(aThat);
255 AssertComRCReturnRC(thatCaller.rc());
256
257 AutoReadLock thatlock(aThat COMMA_LOCKVAL_SRC_POS);
258 m->bd.attachCopy(aThat->m->bd);
259
260 /* Confirm a successful initialization */
261 autoInitSpan.setSucceeded();
262
263 return S_OK;
264}
265
266
267/**
268 * Uninitializes the instance and sets the ready flag to FALSE.
269 * Called either from FinalRelease() or by the parent when it gets destroyed.
270 */
271void StorageController::uninit()
272{
273 LogFlowThisFunc(("\n"));
274
275 /* Enclose the state transition Ready->InUninit->NotReady */
276 AutoUninitSpan autoUninitSpan(this);
277 if (autoUninitSpan.uninitDone())
278 return;
279
280 m->bd.free();
281
282 unconst(m->pPeer) = NULL;
283 unconst(m->pParent) = NULL;
284
285 delete m;
286 m = NULL;
287}
288
289
290// IStorageController properties
291HRESULT StorageController::getName(com::Utf8Str &aName)
292{
293 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
294
295 aName = m->bd->strName;
296
297 return S_OK;
298}
299
300HRESULT StorageController::setName(const com::Utf8Str &aName)
301{
302 /* the machine needs to be mutable */
303 AutoMutableStateDependency adep(m->pParent);
304 if (FAILED(adep.rc())) return adep.rc();
305
306 AutoMultiWriteLock2 alock(m->pParent, this COMMA_LOCKVAL_SRC_POS);
307
308 if (m->bd->strName != aName)
309 {
310 ComObjPtr<StorageController> ctrl;
311 HRESULT rc = m->pParent->i_getStorageControllerByName(aName, ctrl, false /* aSetError */);
312 if (SUCCEEDED(rc))
313 return setError(VBOX_E_OBJECT_IN_USE,
314 tr("Storage controller named '%s' already exists"),
315 aName.c_str());
316
317 Machine::MediumAttachmentList atts;
318 rc = m->pParent->i_getMediumAttachmentsOfController(m->bd->strName, atts);
319 for (Machine::MediumAttachmentList::const_iterator
320 it = atts.begin();
321 it != atts.end();
322 ++it)
323 {
324 IMediumAttachment *iA = *it;
325 MediumAttachment *pAttach = static_cast<MediumAttachment *>(iA);
326 AutoWriteLock attlock(pAttach COMMA_LOCKVAL_SRC_POS);
327 pAttach->i_updateName(aName);
328 }
329
330
331 m->bd.backup();
332 m->bd->strName = aName;
333
334 m->pParent->i_setModified(Machine::IsModified_Storage);
335 alock.release();
336
337 m->pParent->i_onStorageControllerChange();
338 }
339
340 return S_OK;
341}
342
343HRESULT StorageController::getBus(StorageBus_T *aBus)
344{
345 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
346
347 *aBus = m->bd->storageBus;
348
349 return S_OK;
350}
351
352HRESULT StorageController::getControllerType(StorageControllerType_T *aControllerType)
353{
354 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
355
356 *aControllerType = m->bd->controllerType;
357
358 return S_OK;
359}
360
361HRESULT StorageController::setControllerType(StorageControllerType_T aControllerType)
362{
363 /* the machine needs to be mutable */
364 AutoMutableStateDependency adep(m->pParent);
365 if (FAILED(adep.rc())) return adep.rc();
366
367 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
368
369 HRESULT rc = S_OK;
370
371 switch (m->bd->storageBus)
372 {
373 case StorageBus_IDE:
374 {
375 if ( (aControllerType != StorageControllerType_PIIX3)
376 && (aControllerType != StorageControllerType_PIIX4)
377 && (aControllerType != StorageControllerType_ICH6))
378 rc = E_INVALIDARG;
379 break;
380 }
381 case StorageBus_SATA:
382 {
383 if (aControllerType != StorageControllerType_IntelAhci)
384 rc = E_INVALIDARG;
385 break;
386 }
387 case StorageBus_SCSI:
388 {
389 if ( (aControllerType != StorageControllerType_LsiLogic)
390 && (aControllerType != StorageControllerType_BusLogic))
391 rc = E_INVALIDARG;
392 break;
393 }
394 case StorageBus_Floppy:
395 {
396 if (aControllerType != StorageControllerType_I82078)
397 rc = E_INVALIDARG;
398 break;
399 }
400 case StorageBus_SAS:
401 {
402 if (aControllerType != StorageControllerType_LsiLogicSas)
403 rc = E_INVALIDARG;
404 break;
405 }
406 case StorageBus_USB:
407 {
408 if (aControllerType != StorageControllerType_USB)
409 rc = E_INVALIDARG;
410 break;
411 }
412 case StorageBus_PCIe:
413 {
414 if (aControllerType != StorageControllerType_NVMe)
415 rc = E_INVALIDARG;
416 break;
417 }
418 default:
419 AssertMsgFailed(("Invalid controller type %d\n", m->bd->storageBus));
420 rc = E_INVALIDARG;
421 }
422
423 if (!SUCCEEDED(rc))
424 return setError(rc,
425 tr("Invalid controller type %d"),
426 aControllerType);
427
428 if (m->bd->controllerType != aControllerType)
429 {
430 m->bd.backup();
431 m->bd->controllerType = aControllerType;
432
433 alock.release();
434 AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS); // m->pParent is const, needs no locking
435 m->pParent->i_setModified(Machine::IsModified_Storage);
436 mlock.release();
437
438 m->pParent->i_onStorageControllerChange();
439 }
440
441 return S_OK;
442}
443
444HRESULT StorageController::getMaxDevicesPerPortCount(ULONG *aMaxDevicesPerPortCount)
445{
446 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
447
448 HRESULT rc = m->pSystemProperties->GetMaxDevicesPerPortForStorageBus(m->bd->storageBus, aMaxDevicesPerPortCount);
449
450 return rc;
451}
452
453HRESULT StorageController::getMinPortCount(ULONG *aMinPortCount)
454{
455 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
456
457 HRESULT rc = m->pSystemProperties->GetMinPortCountForStorageBus(m->bd->storageBus, aMinPortCount);
458 return rc;
459}
460
461HRESULT StorageController::getMaxPortCount(ULONG *aMaxPortCount)
462{
463 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
464 HRESULT rc = m->pSystemProperties->GetMaxPortCountForStorageBus(m->bd->storageBus, aMaxPortCount);
465
466 return rc;
467}
468
469HRESULT StorageController::getPortCount(ULONG *aPortCount)
470{
471 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
472
473 *aPortCount = m->bd->ulPortCount;
474
475 return S_OK;
476}
477
478HRESULT StorageController::setPortCount(ULONG aPortCount)
479{
480 /* the machine needs to be mutable */
481 AutoMutableStateDependency adep(m->pParent);
482 if (FAILED(adep.rc())) return adep.rc();
483
484 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
485
486 switch (m->bd->storageBus)
487 {
488 case StorageBus_SATA:
489 {
490 /* AHCI SATA supports a maximum of 30 ports. */
491 if (aPortCount < 1 || aPortCount > 30)
492 return setError(E_INVALIDARG,
493 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
494 aPortCount, 1, 30);
495 break;
496 }
497 case StorageBus_SCSI:
498 {
499 /*
500 * SCSI does not support setting different ports.
501 * (doesn't make sense here either).
502 * The maximum and minimum is 16 and unless the callee
503 * tries to set a different value we return an error.
504 */
505 if (aPortCount != 16)
506 return setError(E_INVALIDARG,
507 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
508 aPortCount, 16, 16);
509 break;
510 }
511 case StorageBus_IDE:
512 {
513 /*
514 * The port count is fixed to 2.
515 */
516 if (aPortCount != 2)
517 return setError(E_INVALIDARG,
518 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
519 aPortCount, 2, 2);
520 break;
521 }
522 case StorageBus_Floppy:
523 {
524 /*
525 * The port count is fixed to 1.
526 */
527 if (aPortCount != 1)
528 return setError(E_INVALIDARG,
529 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
530 aPortCount, 1, 1);
531 break;
532 }
533 case StorageBus_SAS:
534 {
535 /* SAS supports a maximum of 255 ports. */
536 if (aPortCount < 1 || aPortCount > 255)
537 return setError(E_INVALIDARG,
538 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
539 aPortCount, 1, 255);
540 break;
541 }
542 case StorageBus_USB:
543 {
544 /*
545 * The port count is fixed to 8.
546 */
547 if (aPortCount != 8)
548 return setError(E_INVALIDARG,
549 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
550 aPortCount, 8, 8);
551 break;
552 }
553 case StorageBus_PCIe:
554 {
555 /*
556 * PCIe (NVMe in particular) supports theoretically 2^32 - 1
557 * different namespaces, limit the amount artifically here.
558 */
559 if (aPortCount < 1 || aPortCount > 255)
560 return setError(E_INVALIDARG,
561 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
562 aPortCount, 1, 255);
563 break;
564 }
565 default:
566 AssertMsgFailed(("Invalid controller type %d\n", m->bd->storageBus));
567 }
568
569 if (m->bd->ulPortCount != aPortCount)
570 {
571 m->bd.backup();
572 m->bd->ulPortCount = aPortCount;
573
574 alock.release();
575 AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS); // m->pParent is const, needs no locking
576 m->pParent->i_setModified(Machine::IsModified_Storage);
577 mlock.release();
578
579 m->pParent->i_onStorageControllerChange();
580 }
581
582 return S_OK;
583}
584
585HRESULT StorageController::getInstance(ULONG *aInstance)
586{
587 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
588
589 *aInstance = m->bd->ulInstance;
590
591 return S_OK;
592}
593
594HRESULT StorageController::setInstance(ULONG aInstance)
595{
596 /* the machine needs to be mutable */
597 AutoMutableStateDependency adep(m->pParent);
598 if (FAILED(adep.rc())) return adep.rc();
599
600 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
601
602 if (m->bd->ulInstance != aInstance)
603 {
604 m->bd.backup();
605 m->bd->ulInstance = aInstance;
606
607 alock.release();
608 AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS); // m->pParent is const, needs no locking
609 m->pParent->i_setModified(Machine::IsModified_Storage);
610 mlock.release();
611
612 m->pParent->i_onStorageControllerChange();
613 }
614
615 return S_OK;
616}
617
618HRESULT StorageController::getUseHostIOCache(BOOL *fUseHostIOCache)
619{
620 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
621
622 *fUseHostIOCache = m->bd->fUseHostIOCache;
623
624 return S_OK;
625}
626
627HRESULT StorageController::setUseHostIOCache(BOOL fUseHostIOCache)
628{
629 /* the machine needs to be mutable */
630 AutoMutableStateDependency adep(m->pParent);
631 if (FAILED(adep.rc())) return adep.rc();
632
633 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
634
635 if (m->bd->fUseHostIOCache != !!fUseHostIOCache)
636 {
637 m->bd.backup();
638 m->bd->fUseHostIOCache = !!fUseHostIOCache;
639
640 alock.release();
641 AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS); // m->pParent is const, needs no locking
642 m->pParent->i_setModified(Machine::IsModified_Storage);
643 mlock.release();
644
645 m->pParent->i_onStorageControllerChange();
646 }
647
648 return S_OK;
649}
650
651HRESULT StorageController::getBootable(BOOL *fBootable)
652{
653 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
654
655 *fBootable = m->bd->fBootable;
656
657 return S_OK;
658}
659
660// public methods only for internal purposes
661/////////////////////////////////////////////////////////////////////////////
662
663const Utf8Str& StorageController::i_getName() const
664{
665 return m->bd->strName;
666}
667
668StorageControllerType_T StorageController::i_getControllerType() const
669{
670 return m->bd->controllerType;
671}
672
673StorageBus_T StorageController::i_getStorageBus() const
674{
675 return m->bd->storageBus;
676}
677
678ULONG StorageController::i_getInstance() const
679{
680 return m->bd->ulInstance;
681}
682
683bool StorageController::i_getBootable() const
684{
685 return !!m->bd->fBootable;
686}
687
688/**
689 * Checks the validity of a port and device number.
690 *
691 * @retval S_OK If the given port and device numbers are within the range
692 * supported by this controller.
693 * @retval E_INVALIDARG If not. Sets an error.
694 * @param aControllerPort Controller port number.
695 * @param aDevice Device number.
696 */
697HRESULT StorageController::i_checkPortAndDeviceValid(LONG aControllerPort,
698 LONG aDevice)
699{
700 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
701
702 ULONG portCount = m->bd->ulPortCount;
703 ULONG devicesPerPort;
704 HRESULT rc = m->pSystemProperties->GetMaxDevicesPerPortForStorageBus(m->bd->storageBus, &devicesPerPort);
705 if (FAILED(rc)) return rc;
706
707 if ( aControllerPort < 0
708 || aControllerPort >= (LONG)portCount
709 || aDevice < 0
710 || aDevice >= (LONG)devicesPerPort
711 )
712 return setError(E_INVALIDARG,
713 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])"),
714 (int)aControllerPort, (int)portCount-1, (int)aDevice, (int)devicesPerPort-1);
715
716 return S_OK;
717}
718
719/** @note Locks objects for writing! */
720void StorageController::i_setBootable(BOOL fBootable)
721{
722 AutoCaller autoCaller(this);
723 AssertComRCReturnVoid(autoCaller.rc());
724
725 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
726
727 m->bd.backup();
728 m->bd->fBootable = RT_BOOL(fBootable);
729}
730
731/** @note Locks objects for writing! */
732void StorageController::i_rollback()
733{
734 AutoCaller autoCaller(this);
735 AssertComRCReturnVoid(autoCaller.rc());
736
737 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
738
739 m->bd.rollback();
740}
741
742/**
743 * @note Locks this object for writing, together with the peer object (also
744 * for writing) if there is one.
745 */
746void StorageController::i_commit()
747{
748 /* sanity */
749 AutoCaller autoCaller(this);
750 AssertComRCReturnVoid(autoCaller.rc());
751
752 /* sanity too */
753 AutoCaller peerCaller(m->pPeer);
754 AssertComRCReturnVoid(peerCaller.rc());
755
756 /* lock both for writing since we modify both (m->pPeer is "master" so locked
757 * first) */
758 AutoMultiWriteLock2 alock(m->pPeer, this COMMA_LOCKVAL_SRC_POS);
759
760 if (m->bd.isBackedUp())
761 {
762 m->bd.commit();
763 if (m->pPeer)
764 {
765 // attach new data to the peer and reshare it
766 m->pPeer->m->bd.attach(m->bd);
767 }
768 }
769}
770
771/**
772 * Cancels sharing (if any) by making an independent copy of data.
773 * This operation also resets this object's peer to NULL.
774 *
775 * @note Locks this object for writing, together with the peer object
776 * represented by @a aThat (locked for reading).
777 */
778void StorageController::i_unshare()
779{
780 /* sanity */
781 AutoCaller autoCaller(this);
782 AssertComRCReturnVoid(autoCaller.rc());
783
784 /* sanity too */
785 AutoCaller peerCaller(m->pPeer);
786 AssertComRCReturnVoid(peerCaller.rc());
787
788 /* peer is not modified, lock it for reading (m->pPeer is "master" so locked
789 * first) */
790 AutoReadLock rl(m->pPeer COMMA_LOCKVAL_SRC_POS);
791 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
792
793 if (m->bd.isShared())
794 {
795 if (!m->bd.isBackedUp())
796 m->bd.backup();
797
798 m->bd.commit();
799 }
800
801 unconst(m->pPeer) = NULL;
802}
803
804Machine* StorageController::i_getMachine()
805{
806 return m->pParent;
807}
808
809ComObjPtr<StorageController> StorageController::i_getPeer()
810{
811 return m->pPeer;
812}
813
814// private methods
815/////////////////////////////////////////////////////////////////////////////
816
817
818/* 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