VirtualBox

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

Last change on this file since 98351 was 98292, checked in by vboxsync, 23 months ago

Main/src-server: rc -> hrc/vrc. Enabled scm rc checks. bugref:10223

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.1 KB
Line 
1/* $Id: StorageControllerImpl.cpp 98292 2023-01-25 01:14:53Z vboxsync $ */
2/** @file
3 * Implementation of IStorageController.
4 */
5
6/*
7 * Copyright (C) 2008-2023 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 hrc = aParent->COMGETTER(ChipsetType)(&chipsetType);
115 if (FAILED(hrc))
116 return hrc;
117 hrc = aParent->i_getVirtualBox()->i_getSystemProperties()->
118 GetMaxInstancesOfStorageBus(chipsetType, aStorageBus, &maxInstances);
119 if (FAILED(hrc))
120 return hrc;
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.hrc());
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.hrc());
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.hrc())) return adep.hrc();
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 hrc = m->pParent->i_getStorageControllerByName(aName, ctrl, false /* aSetError */);
325 if (SUCCEEDED(hrc))
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 hrc = 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.hrc())) return adep.hrc();
379
380 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
381
382 HRESULT hrc = S_OK;
383 switch (m->bd->storageBus)
384 {
385 case StorageBus_IDE:
386 if ( (aControllerType != StorageControllerType_PIIX3)
387 && (aControllerType != StorageControllerType_PIIX4)
388 && (aControllerType != StorageControllerType_ICH6))
389 hrc = E_INVALIDARG;
390 break;
391 case StorageBus_SATA:
392 if (aControllerType != StorageControllerType_IntelAhci)
393 hrc = E_INVALIDARG;
394 break;
395 case StorageBus_SCSI:
396 if ( (aControllerType != StorageControllerType_LsiLogic)
397 && (aControllerType != StorageControllerType_BusLogic))
398 hrc = E_INVALIDARG;
399 break;
400 case StorageBus_Floppy:
401 if (aControllerType != StorageControllerType_I82078)
402 hrc = E_INVALIDARG;
403 break;
404 case StorageBus_SAS:
405 if (aControllerType != StorageControllerType_LsiLogicSas)
406 hrc = E_INVALIDARG;
407 break;
408 case StorageBus_USB:
409 if (aControllerType != StorageControllerType_USB)
410 hrc = E_INVALIDARG;
411 break;
412 case StorageBus_PCIe:
413 if (aControllerType != StorageControllerType_NVMe)
414 hrc = E_INVALIDARG;
415 break;
416 case StorageBus_VirtioSCSI:
417 if (aControllerType != StorageControllerType_VirtioSCSI)
418 hrc = E_INVALIDARG;
419 break;
420 default:
421 AssertMsgFailed(("Invalid controller type %d\n", m->bd->storageBus));
422 hrc = E_INVALIDARG;
423 break;
424 }
425
426 if (!SUCCEEDED(hrc))
427 return setError(hrc, tr("Invalid controller type %d"), aControllerType);
428
429 if (m->bd->controllerType != aControllerType)
430 {
431 m->bd.backup();
432 m->bd->controllerType = aControllerType;
433
434 alock.release();
435 AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS); // m->pParent is const, needs no locking
436 m->pParent->i_setModified(Machine::IsModified_Storage);
437 mlock.release();
438
439 m->pParent->i_onStorageControllerChange(m->pParent->i_getId(), m->bd->strName);
440 }
441
442 return S_OK;
443}
444
445HRESULT StorageController::getMaxDevicesPerPortCount(ULONG *aMaxDevicesPerPortCount)
446{
447 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
448 return m->pSystemProperties->GetMaxDevicesPerPortForStorageBus(m->bd->storageBus, aMaxDevicesPerPortCount);
449}
450
451HRESULT StorageController::getMinPortCount(ULONG *aMinPortCount)
452{
453 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
454 return m->pSystemProperties->GetMinPortCountForStorageBus(m->bd->storageBus, aMinPortCount);
455}
456
457HRESULT StorageController::getMaxPortCount(ULONG *aMaxPortCount)
458{
459 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
460 return m->pSystemProperties->GetMaxPortCountForStorageBus(m->bd->storageBus, aMaxPortCount);
461}
462
463HRESULT StorageController::getPortCount(ULONG *aPortCount)
464{
465 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
466
467 *aPortCount = m->bd->ulPortCount;
468
469 return S_OK;
470}
471
472HRESULT StorageController::setPortCount(ULONG aPortCount)
473{
474 /* the machine needs to be mutable */
475 AutoMutableStateDependency adep(m->pParent);
476 if (FAILED(adep.hrc())) return adep.hrc();
477
478 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
479
480 switch (m->bd->storageBus)
481 {
482 case StorageBus_SATA:
483 {
484 /* AHCI SATA supports a maximum of 30 ports. */
485 if (aPortCount < 1 || aPortCount > 30)
486 return setError(E_INVALIDARG,
487 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
488 aPortCount, 1, 30);
489 break;
490 }
491 case StorageBus_SCSI:
492 {
493 /*
494 * SCSI does not support setting different ports.
495 * (doesn't make sense here either).
496 * The maximum and minimum is 16 and unless the callee
497 * tries to set a different value we return an error.
498 */
499 if (aPortCount != 16)
500 return setError(E_INVALIDARG,
501 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
502 aPortCount, 16, 16);
503 break;
504 }
505 case StorageBus_IDE:
506 {
507 /*
508 * The port count is fixed to 2.
509 */
510 if (aPortCount != 2)
511 return setError(E_INVALIDARG,
512 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
513 aPortCount, 2, 2);
514 break;
515 }
516 case StorageBus_Floppy:
517 {
518 /*
519 * The port count is fixed to 1.
520 */
521 if (aPortCount != 1)
522 return setError(E_INVALIDARG,
523 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
524 aPortCount, 1, 1);
525 break;
526 }
527 case StorageBus_SAS:
528 {
529 /* SAS supports a maximum of 255 ports. */
530 if (aPortCount < 1 || aPortCount > 255)
531 return setError(E_INVALIDARG,
532 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
533 aPortCount, 1, 255);
534 break;
535 }
536 case StorageBus_USB:
537 {
538 /*
539 * The port count is fixed to 8.
540 */
541 if (aPortCount != 8)
542 return setError(E_INVALIDARG,
543 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
544 aPortCount, 8, 8);
545 break;
546 }
547 case StorageBus_PCIe:
548 {
549 /*
550 * PCIe (NVMe in particular) supports theoretically 2^32 - 1
551 * different namespaces, limit the amount artifically here.
552 */
553 if (aPortCount < 1 || aPortCount > 255)
554 return setError(E_INVALIDARG,
555 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
556 aPortCount, 1, 255);
557 break;
558 }
559 case StorageBus_VirtioSCSI:
560 {
561 /*
562 * virtio-scsi supports 256 targets (with 16384 LUNs each).
563 */
564 if (aPortCount < 1 || aPortCount > 256)
565 return setError(E_INVALIDARG,
566 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
567 aPortCount, 1, 256);
568 break;
569 }
570 default:
571 AssertMsgFailed(("Invalid controller type %d\n", m->bd->storageBus));
572 }
573
574 if (m->bd->ulPortCount != aPortCount)
575 {
576 m->bd.backup();
577 m->bd->ulPortCount = aPortCount;
578
579 alock.release();
580 AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS); // m->pParent is const, needs no locking
581 m->pParent->i_setModified(Machine::IsModified_Storage);
582 mlock.release();
583
584 m->pParent->i_onStorageControllerChange(m->pParent->i_getId(), m->bd->strName);
585 }
586
587 return S_OK;
588}
589
590HRESULT StorageController::getInstance(ULONG *aInstance)
591{
592 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
593
594 *aInstance = m->bd->ulInstance;
595
596 return S_OK;
597}
598
599HRESULT StorageController::setInstance(ULONG aInstance)
600{
601 /* the machine needs to be mutable */
602 AutoMutableStateDependency adep(m->pParent);
603 if (FAILED(adep.hrc())) return adep.hrc();
604
605 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
606
607 if (m->bd->ulInstance != aInstance)
608 {
609 m->bd.backup();
610 m->bd->ulInstance = aInstance;
611
612 alock.release();
613 AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS); // m->pParent is const, needs no locking
614 m->pParent->i_setModified(Machine::IsModified_Storage);
615 mlock.release();
616
617 m->pParent->i_onStorageControllerChange(m->pParent->i_getId(), m->bd->strName);
618 }
619
620 return S_OK;
621}
622
623HRESULT StorageController::getUseHostIOCache(BOOL *fUseHostIOCache)
624{
625 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
626
627 *fUseHostIOCache = m->bd->fUseHostIOCache;
628
629 return S_OK;
630}
631
632HRESULT StorageController::setUseHostIOCache(BOOL fUseHostIOCache)
633{
634 /* the machine needs to be mutable */
635 AutoMutableStateDependency adep(m->pParent);
636 if (FAILED(adep.hrc())) return adep.hrc();
637
638 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
639
640 if (m->bd->fUseHostIOCache != !!fUseHostIOCache)
641 {
642 m->bd.backup();
643 m->bd->fUseHostIOCache = !!fUseHostIOCache;
644
645 alock.release();
646 AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS); // m->pParent is const, needs no locking
647 m->pParent->i_setModified(Machine::IsModified_Storage);
648 mlock.release();
649
650 m->pParent->i_onStorageControllerChange(m->pParent->i_getId(), m->bd->strName);
651 }
652
653 return S_OK;
654}
655
656HRESULT StorageController::getBootable(BOOL *fBootable)
657{
658 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
659
660 *fBootable = m->bd->fBootable;
661
662 return S_OK;
663}
664
665// public methods only for internal purposes
666/////////////////////////////////////////////////////////////////////////////
667
668const Utf8Str& StorageController::i_getName() const
669{
670 return m->bd->strName;
671}
672
673StorageControllerType_T StorageController::i_getControllerType() const
674{
675 return m->bd->controllerType;
676}
677
678StorageBus_T StorageController::i_getStorageBus() const
679{
680 return m->bd->storageBus;
681}
682
683ULONG StorageController::i_getInstance() const
684{
685 return m->bd->ulInstance;
686}
687
688bool StorageController::i_getBootable() const
689{
690 return !!m->bd->fBootable;
691}
692
693/**
694 * Checks the validity of a port and device number.
695 *
696 * @retval S_OK If the given port and device numbers are within the range
697 * supported by this controller.
698 * @retval E_INVALIDARG If not. Sets an error.
699 * @param aControllerPort Controller port number.
700 * @param aDevice Device number.
701 */
702HRESULT StorageController::i_checkPortAndDeviceValid(LONG aControllerPort,
703 LONG aDevice)
704{
705 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
706
707 ULONG portCount = m->bd->ulPortCount;
708 ULONG devicesPerPort;
709 HRESULT hrc = m->pSystemProperties->GetMaxDevicesPerPortForStorageBus(m->bd->storageBus, &devicesPerPort);
710 if (FAILED(hrc)) return hrc;
711
712 if ( aControllerPort < 0
713 || aControllerPort >= (LONG)portCount
714 || aDevice < 0
715 || aDevice >= (LONG)devicesPerPort
716 )
717 return setError(E_INVALIDARG,
718 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])"),
719 (int)aControllerPort, (int)portCount-1, (int)aDevice, (int)devicesPerPort-1);
720
721 return S_OK;
722}
723
724/** @note Locks objects for writing! */
725void StorageController::i_setBootable(BOOL fBootable)
726{
727 AutoCaller autoCaller(this);
728 AssertComRCReturnVoid(autoCaller.hrc());
729
730 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
731
732 m->bd.backup();
733 m->bd->fBootable = RT_BOOL(fBootable);
734}
735
736/** @note Locks objects for writing! */
737void StorageController::i_rollback()
738{
739 AutoCaller autoCaller(this);
740 AssertComRCReturnVoid(autoCaller.hrc());
741
742 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
743
744 m->bd.rollback();
745}
746
747/**
748 * @note Locks this object for writing, together with the peer object (also
749 * for writing) if there is one.
750 */
751void StorageController::i_commit()
752{
753 /* sanity */
754 AutoCaller autoCaller(this);
755 AssertComRCReturnVoid(autoCaller.hrc());
756
757 /* sanity too */
758 AutoCaller peerCaller(m->pPeer);
759 AssertComRCReturnVoid(peerCaller.hrc());
760
761 /* lock both for writing since we modify both (m->pPeer is "master" so locked
762 * first) */
763 AutoMultiWriteLock2 alock(m->pPeer, this COMMA_LOCKVAL_SRC_POS);
764
765 if (m->bd.isBackedUp())
766 {
767 m->bd.commit();
768 if (m->pPeer)
769 {
770 // attach new data to the peer and reshare it
771 m->pPeer->m->bd.attach(m->bd);
772 }
773 }
774}
775
776/**
777 * Cancels sharing (if any) by making an independent copy of data.
778 * This operation also resets this object's peer to NULL.
779 *
780 * @note Locks this object for writing, together with the peer object
781 * represented by @a aThat (locked for reading).
782 */
783void StorageController::i_unshare()
784{
785 /* sanity */
786 AutoCaller autoCaller(this);
787 AssertComRCReturnVoid(autoCaller.hrc());
788
789 /* sanity too */
790 AutoCaller peerCaller(m->pPeer);
791 AssertComRCReturnVoid(peerCaller.hrc());
792
793 /* peer is not modified, lock it for reading (m->pPeer is "master" so locked
794 * first) */
795 AutoReadLock rl(m->pPeer COMMA_LOCKVAL_SRC_POS);
796 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
797
798 if (m->bd.isShared())
799 {
800 if (!m->bd.isBackedUp())
801 m->bd.backup();
802
803 m->bd.commit();
804 }
805
806 unconst(m->pPeer) = NULL;
807}
808
809Machine* StorageController::i_getMachine()
810{
811 return m->pParent;
812}
813
814ComObjPtr<StorageController> StorageController::i_getPeer()
815{
816 return m->pPeer;
817}
818
819// private methods
820/////////////////////////////////////////////////////////////////////////////
821
822
823/* 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