VirtualBox

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

Last change on this file since 98068 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

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