VirtualBox

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

Last change on this file since 57823 was 57524, checked in by vboxsync, 9 years ago

Main: NVMe integration

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