VirtualBox

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

Last change on this file since 54840 was 51498, checked in by vboxsync, 11 years ago

6813 - MachineImpl use of server side wrappers + misc mods on other classes

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