VirtualBox

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

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

Main: use settings struct for machine user data; remove iprt::MiniString::raw() and change all occurences to c_str()

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