VirtualBox

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

Last change on this file since 62393 was 61917, checked in by vboxsync, 8 years ago

Main: doxygen fix

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