VirtualBox

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

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

Main/Medium+MediumFormat+GuestOSType+SystemPropertiesImpl+Console+Global: consistently use bytes as size units, forgotten const value in API, MaxVDISize method renamed to InfoVDSize, STDMETHOD macro usage fixes, whitespace cleanup

Frontends/VirtualBox+VBoxManage+VBoxShell: adapt to changed disk size units

Main/StorageControllerImpl: check the storage controller instance limit to avoid creating unusable VM configs, simplify unnecessarily complex code for querying the controller properties

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

© 2023 Oracle
ContactPrivacy policyTerms of Use