VirtualBox

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

Last change on this file since 78406 was 78261, checked in by vboxsync, 6 years ago

Main: bugref:6913: Added OnStorageControllerChanged to IVirtualBox events and fixed generation the medium events

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