VirtualBox

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

Last change on this file since 49644 was 49644, checked in by vboxsync, 11 years ago

stage 1/8 of 6813 changes

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