VirtualBox

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

Last change on this file since 47348 was 44528, checked in by vboxsync, 12 years ago

header (C) fixes

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