VirtualBox

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

Last change on this file since 30670 was 29686, checked in by vboxsync, 14 years ago

Floppy disk controllers should use the host I/O cache by default too

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