VirtualBox

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

Last change on this file since 54971 was 54971, checked in by vboxsync, 10 years ago

Main/AudioAdapter+BandwidthControl+Machine+NetworkAdapter+ParallelPort+SerialPort+StorageController+USBDeviceFilter+USBDeviceFilters: Adjust rules when settings can be changed to allow as much as possible. Some changes restored the old rules (a previous change made the definition more restrictive), but many now allow changing settings when VM is saved or even at runtime when it is safe. Will resolve many complaints, especially when the GUI also is adapted accordingly.

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