VirtualBox

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

Last change on this file since 67954 was 66126, checked in by vboxsync, 8 years ago

Main/Machine+Snapshot+Appliance+StorageController: eliminate the one-member struct MediaData, as a preparation for later eliminating the Backupable<> template use in combination with anything containing a ComObjPtr (since these are not handled in a sensible way when creating a session or a snapshot anyway, needing more effort to fix than do right from the beginning). Additionally a lot of iterator loop cleanups, making proper use of scoping and const_iterator whenever possible. Also take the opportunity to improve the readability of some quite long lines. No behavior change intended.

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