VirtualBox

source: vbox/trunk/src/VBox/Main/StorageControllerImpl.cpp@ 33915

Last change on this file since 33915 was 33915, checked in by vboxsync, 14 years ago

Main, QT/FE, VBoxManage: per-chipset controller count limits

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