VirtualBox

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

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

Main: Eliminate the last bits of VirtualBoxBaseWithChildrenNEXT. It won't be missed.

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