VirtualBox

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

Last change on this file since 31308 was 31308, checked in by vboxsync, 15 years ago

Main: storage controller/attachment cleanup

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette