VirtualBox

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

Last change on this file since 93920 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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