VirtualBox

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

Last change on this file since 63503 was 63172, checked in by vboxsync, 8 years ago

Main: warning about switches and some other stuff.

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