VirtualBox

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

Last change on this file since 26313 was 26235, checked in by vboxsync, 15 years ago

Main: coding style

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