VirtualBox

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

Last change on this file since 107597 was 107555, checked in by vboxsync, 3 weeks ago

Main/src-server/StorageControllerImpl.cpp: Missing error check, bugref:3409

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.7 KB
Line 
1/* $Id: StorageControllerImpl.cpp 107555 2025-01-09 08:42:38Z vboxsync $ */
2/** @file
3 * Implementation of IStorageController.
4 */
5
6/*
7 * Copyright (C) 2008-2024 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 ChipsetType_T chipsetType;
113 HRESULT hrc = aParent->i_getPlatform()->COMGETTER(ChipsetType)(&chipsetType);
114 AssertComRCReturnRC(hrc);
115
116 ULONG maxInstances;
117 hrc = aParent->i_getPlatformProperties()->GetMaxInstancesOfStorageBus(chipsetType, aStorageBus, &maxInstances);
118 AssertComRCReturnRC(hrc);
119
120 if (aInstance >= maxInstances)
121 return setError(E_INVALIDARG,
122 tr("Too many storage controllers of this type"));
123
124 /* Enclose the state transition NotReady->InInit->Ready */
125 AutoInitSpan autoInitSpan(this);
126 AssertReturn(autoInitSpan.isOk(), E_FAIL);
127
128 m = new Data(aParent);
129
130 /* m->pPeer is left null */
131
132 m->bd.allocate();
133
134 m->bd->strName = aName;
135 m->bd->ulInstance = aInstance;
136 m->bd->fBootable = fBootable;
137 m->bd->storageBus = aStorageBus;
138 if ( aStorageBus != StorageBus_IDE
139 && aStorageBus != StorageBus_Floppy)
140 m->bd->fUseHostIOCache = false;
141 else
142 m->bd->fUseHostIOCache = true;
143
144 switch (aStorageBus)
145 {
146 case StorageBus_IDE:
147 m->bd->ulPortCount = 2;
148 m->bd->controllerType = StorageControllerType_PIIX4;
149 break;
150 case StorageBus_SATA:
151 m->bd->ulPortCount = 30;
152 m->bd->controllerType = StorageControllerType_IntelAhci;
153 break;
154 case StorageBus_SCSI:
155 m->bd->ulPortCount = 16;
156 m->bd->controllerType = StorageControllerType_LsiLogic;
157 break;
158 case StorageBus_Floppy:
159 m->bd->ulPortCount = 1;
160 m->bd->controllerType = StorageControllerType_I82078;
161 break;
162 case StorageBus_SAS:
163 m->bd->ulPortCount = 8;
164 m->bd->controllerType = StorageControllerType_LsiLogicSas;
165 break;
166 case StorageBus_USB:
167 m->bd->ulPortCount = 8;
168 m->bd->controllerType = StorageControllerType_USB;
169 break;
170 case StorageBus_PCIe:
171 m->bd->ulPortCount = 1;
172 m->bd->controllerType = StorageControllerType_NVMe;
173 break;
174 case StorageBus_VirtioSCSI:
175 m->bd->ulPortCount = 1;
176 m->bd->controllerType = StorageControllerType_VirtioSCSI;
177 break;
178 case StorageBus_Null: break; /* Shut up MSC. */
179#ifdef VBOX_WITH_XPCOM_CPP_ENUM_HACK
180 case StorageBus_32BitHack: break; /* Shut up GCC. */
181#endif
182 }
183
184 /* Confirm a successful initialization */
185 autoInitSpan.setSucceeded();
186
187 return S_OK;
188}
189
190/**
191 * Initializes the object given another object
192 * (a kind of copy constructor). This object shares data with
193 * the object passed as an argument.
194 *
195 * @param aParent Pointer to our parent object.
196 * @param aThat
197 * @param aReshare
198 * When false, the original object will remain a data owner.
199 * Otherwise, data ownership will be transferred from the original
200 * object to this one.
201 *
202 * @note This object must be destroyed before the original object
203 * it shares data with is destroyed.
204 *
205 * @note Locks @a aThat object for writing if @a aReshare is @c true, or for
206 * reading if @a aReshare is false.
207 */
208HRESULT StorageController::init(Machine *aParent,
209 StorageController *aThat,
210 bool aReshare /* = false */)
211{
212 LogFlowThisFunc(("aParent=%p, aThat=%p, aReshare=%RTbool\n",
213 aParent, aThat, aReshare));
214
215 ComAssertRet(aParent && aThat, E_INVALIDARG);
216
217 /* Enclose the state transition NotReady->InInit->Ready */
218 AutoInitSpan autoInitSpan(this);
219 AssertReturn(autoInitSpan.isOk(), E_FAIL);
220
221 m = new Data(aParent);
222
223 /* sanity */
224 AutoCaller thatCaller(aThat);
225 AssertComRCReturnRC(thatCaller.hrc());
226
227 if (aReshare)
228 {
229 AutoWriteLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
230
231 unconst(aThat->m->pPeer) = this;
232 m->bd.attach(aThat->m->bd);
233 }
234 else
235 {
236 unconst(m->pPeer) = aThat;
237
238 AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
239 m->bd.share(aThat->m->bd);
240 }
241
242 /* Confirm successful initialization */
243 autoInitSpan.setSucceeded();
244
245 return S_OK;
246}
247
248/**
249 * Initializes the storage controller object given another guest object
250 * (a kind of copy constructor). This object makes a private copy of data
251 * of the original object passed as an argument.
252 */
253HRESULT StorageController::initCopy(Machine *aParent, StorageController *aThat)
254{
255 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
256
257 ComAssertRet(aParent && aThat, E_INVALIDARG);
258
259 /* Enclose the state transition NotReady->InInit->Ready */
260 AutoInitSpan autoInitSpan(this);
261 AssertReturn(autoInitSpan.isOk(), E_FAIL);
262
263 m = new Data(aParent);
264 /* m->pPeer is left null */
265
266 AutoCaller thatCaller(aThat);
267 AssertComRCReturnRC(thatCaller.hrc());
268
269 AutoReadLock thatlock(aThat COMMA_LOCKVAL_SRC_POS);
270 m->bd.attachCopy(aThat->m->bd);
271
272 /* Confirm a successful initialization */
273 autoInitSpan.setSucceeded();
274
275 return S_OK;
276}
277
278
279/**
280 * Uninitializes the instance and sets the ready flag to FALSE.
281 * Called either from FinalRelease() or by the parent when it gets destroyed.
282 */
283void StorageController::uninit()
284{
285 LogFlowThisFunc(("\n"));
286
287 /* Enclose the state transition Ready->InUninit->NotReady */
288 AutoUninitSpan autoUninitSpan(this);
289 if (autoUninitSpan.uninitDone())
290 return;
291
292 m->bd.free();
293
294 unconst(m->pPeer) = NULL;
295 unconst(m->pParent) = NULL;
296
297 delete m;
298 m = NULL;
299}
300
301
302// IStorageController properties
303HRESULT StorageController::getName(com::Utf8Str &aName)
304{
305 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
306
307 aName = m->bd->strName;
308
309 return S_OK;
310}
311
312HRESULT StorageController::setName(const com::Utf8Str &aName)
313{
314 /* the machine needs to be mutable */
315 AutoMutableStateDependency adep(m->pParent);
316 if (FAILED(adep.hrc())) return adep.hrc();
317
318 AutoMultiWriteLock2 alock(m->pParent, this COMMA_LOCKVAL_SRC_POS);
319
320 if (m->bd->strName != aName)
321 {
322 ComObjPtr<StorageController> ctrl;
323 HRESULT hrc = m->pParent->i_getStorageControllerByName(aName, ctrl, false /* aSetError */);
324 if (SUCCEEDED(hrc))
325 return setError(VBOX_E_OBJECT_IN_USE,
326 tr("Storage controller named '%s' already exists"),
327 aName.c_str());
328
329 Machine::MediumAttachmentList atts;
330 hrc = m->pParent->i_getMediumAttachmentsOfController(m->bd->strName, atts);
331 if (FAILED(hrc))
332 return setError(hrc,
333 tr("Querying attachments of storage controller named '%s' failed"),
334 m->bd->strName.c_str());
335
336 for (Machine::MediumAttachmentList::const_iterator
337 it = atts.begin();
338 it != atts.end();
339 ++it)
340 {
341 IMediumAttachment *iA = *it;
342 MediumAttachment *pAttach = static_cast<MediumAttachment *>(iA);
343 AutoWriteLock attlock(pAttach COMMA_LOCKVAL_SRC_POS);
344 pAttach->i_updateName(aName);
345 }
346
347
348 m->bd.backup();
349 m->bd->strName = aName;
350
351 m->pParent->i_setModified(Machine::IsModified_Storage);
352 alock.release();
353
354 m->pParent->i_onStorageControllerChange(m->pParent->i_getId(), aName);
355 }
356
357 return S_OK;
358}
359
360HRESULT StorageController::getBus(StorageBus_T *aBus)
361{
362 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
363
364 *aBus = m->bd->storageBus;
365
366 return S_OK;
367}
368
369HRESULT StorageController::getControllerType(StorageControllerType_T *aControllerType)
370{
371 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
372
373 *aControllerType = m->bd->controllerType;
374
375 return S_OK;
376}
377
378HRESULT StorageController::setControllerType(StorageControllerType_T aControllerType)
379{
380 /* the machine needs to be mutable */
381 AutoMutableStateDependency adep(m->pParent);
382 if (FAILED(adep.hrc())) return adep.hrc();
383
384 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
385
386 HRESULT hrc = S_OK;
387 switch (m->bd->storageBus)
388 {
389 case StorageBus_IDE:
390 if ( (aControllerType != StorageControllerType_PIIX3)
391 && (aControllerType != StorageControllerType_PIIX4)
392 && (aControllerType != StorageControllerType_ICH6))
393 hrc = E_INVALIDARG;
394 break;
395 case StorageBus_SATA:
396 if (aControllerType != StorageControllerType_IntelAhci)
397 hrc = E_INVALIDARG;
398 break;
399 case StorageBus_SCSI:
400 if ( (aControllerType != StorageControllerType_LsiLogic)
401 && (aControllerType != StorageControllerType_BusLogic))
402 hrc = E_INVALIDARG;
403 break;
404 case StorageBus_Floppy:
405 if (aControllerType != StorageControllerType_I82078)
406 hrc = E_INVALIDARG;
407 break;
408 case StorageBus_SAS:
409 if (aControllerType != StorageControllerType_LsiLogicSas)
410 hrc = E_INVALIDARG;
411 break;
412 case StorageBus_USB:
413 if (aControllerType != StorageControllerType_USB)
414 hrc = E_INVALIDARG;
415 break;
416 case StorageBus_PCIe:
417 if (aControllerType != StorageControllerType_NVMe)
418 hrc = E_INVALIDARG;
419 break;
420 case StorageBus_VirtioSCSI:
421 if (aControllerType != StorageControllerType_VirtioSCSI)
422 hrc = E_INVALIDARG;
423 break;
424 default:
425 AssertMsgFailed(("Invalid controller type %d\n", m->bd->storageBus));
426 hrc = E_INVALIDARG;
427 break;
428 }
429
430 if (!SUCCEEDED(hrc))
431 return setError(hrc, tr("Invalid controller type %d"), aControllerType);
432
433 if (m->bd->controllerType != aControllerType)
434 {
435 m->bd.backup();
436 m->bd->controllerType = aControllerType;
437
438 alock.release();
439 AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS); // m->pParent is const, needs no locking
440 m->pParent->i_setModified(Machine::IsModified_Storage);
441 mlock.release();
442
443 m->pParent->i_onStorageControllerChange(m->pParent->i_getId(), m->bd->strName);
444 }
445
446 return S_OK;
447}
448
449HRESULT StorageController::getMaxDevicesPerPortCount(ULONG *aMaxDevicesPerPortCount)
450{
451 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
452 return m->pParent->i_getPlatformProperties()->GetMaxDevicesPerPortForStorageBus(m->bd->storageBus, aMaxDevicesPerPortCount);
453}
454
455HRESULT StorageController::getMinPortCount(ULONG *aMinPortCount)
456{
457 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
458 return m->pParent->i_getPlatformProperties()->GetMinPortCountForStorageBus(m->bd->storageBus, aMinPortCount);
459}
460
461HRESULT StorageController::getMaxPortCount(ULONG *aMaxPortCount)
462{
463 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
464 return m->pParent->i_getPlatformProperties()->GetMaxPortCountForStorageBus(m->bd->storageBus, aMaxPortCount);
465}
466
467HRESULT StorageController::getPortCount(ULONG *aPortCount)
468{
469 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
470
471 *aPortCount = m->bd->ulPortCount;
472
473 return S_OK;
474}
475
476HRESULT StorageController::setPortCount(ULONG aPortCount)
477{
478 /* the machine needs to be mutable */
479 AutoMutableStateDependency adep(m->pParent);
480 if (FAILED(adep.hrc())) return adep.hrc();
481
482 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
483
484 switch (m->bd->storageBus)
485 {
486 case StorageBus_SATA:
487 {
488 /* AHCI SATA supports a maximum of 30 ports. */
489 if (aPortCount < 1 || aPortCount > 30)
490 return setError(E_INVALIDARG,
491 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
492 aPortCount, 1, 30);
493 break;
494 }
495 case StorageBus_SCSI:
496 {
497 /*
498 * SCSI does not support setting different ports.
499 * (doesn't make sense here either).
500 * The maximum and minimum is 16 and unless the callee
501 * tries to set a different value we return an error.
502 */
503 if (aPortCount != 16)
504 return setError(E_INVALIDARG,
505 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
506 aPortCount, 16, 16);
507 break;
508 }
509 case StorageBus_IDE:
510 {
511 /*
512 * The port count is fixed to 2.
513 */
514 if (aPortCount != 2)
515 return setError(E_INVALIDARG,
516 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
517 aPortCount, 2, 2);
518 break;
519 }
520 case StorageBus_Floppy:
521 {
522 /*
523 * The port count is fixed to 1.
524 */
525 if (aPortCount != 1)
526 return setError(E_INVALIDARG,
527 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
528 aPortCount, 1, 1);
529 break;
530 }
531 case StorageBus_SAS:
532 {
533 /* SAS supports a maximum of 255 ports. */
534 if (aPortCount < 1 || aPortCount > 255)
535 return setError(E_INVALIDARG,
536 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
537 aPortCount, 1, 255);
538 break;
539 }
540 case StorageBus_USB:
541 {
542 /*
543 * The port count is fixed to 8.
544 */
545 if (aPortCount != 8)
546 return setError(E_INVALIDARG,
547 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
548 aPortCount, 8, 8);
549 break;
550 }
551 case StorageBus_PCIe:
552 {
553 /*
554 * PCIe (NVMe in particular) supports theoretically 2^32 - 1
555 * different namespaces, limit the amount artifically here.
556 */
557 if (aPortCount < 1 || aPortCount > 255)
558 return setError(E_INVALIDARG,
559 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
560 aPortCount, 1, 255);
561 break;
562 }
563 case StorageBus_VirtioSCSI:
564 {
565 /*
566 * virtio-scsi supports 256 targets (with 16384 LUNs each).
567 */
568 if (aPortCount < 1 || aPortCount > 256)
569 return setError(E_INVALIDARG,
570 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
571 aPortCount, 1, 256);
572 break;
573 }
574 default:
575 AssertMsgFailed(("Invalid controller type %d\n", m->bd->storageBus));
576 }
577
578 if (m->bd->ulPortCount != aPortCount)
579 {
580 m->bd.backup();
581 m->bd->ulPortCount = aPortCount;
582
583 alock.release();
584 AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS); // m->pParent is const, needs no locking
585 m->pParent->i_setModified(Machine::IsModified_Storage);
586 mlock.release();
587
588 m->pParent->i_onStorageControllerChange(m->pParent->i_getId(), m->bd->strName);
589 }
590
591 return S_OK;
592}
593
594HRESULT StorageController::getInstance(ULONG *aInstance)
595{
596 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
597
598 *aInstance = m->bd->ulInstance;
599
600 return S_OK;
601}
602
603HRESULT StorageController::setInstance(ULONG aInstance)
604{
605 /* the machine needs to be mutable */
606 AutoMutableStateDependency adep(m->pParent);
607 if (FAILED(adep.hrc())) return adep.hrc();
608
609 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
610
611 if (m->bd->ulInstance != aInstance)
612 {
613 m->bd.backup();
614 m->bd->ulInstance = aInstance;
615
616 alock.release();
617 AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS); // m->pParent is const, needs no locking
618 m->pParent->i_setModified(Machine::IsModified_Storage);
619 mlock.release();
620
621 m->pParent->i_onStorageControllerChange(m->pParent->i_getId(), m->bd->strName);
622 }
623
624 return S_OK;
625}
626
627HRESULT StorageController::getUseHostIOCache(BOOL *fUseHostIOCache)
628{
629 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
630
631 *fUseHostIOCache = m->bd->fUseHostIOCache;
632
633 return S_OK;
634}
635
636HRESULT StorageController::setUseHostIOCache(BOOL fUseHostIOCache)
637{
638 /* the machine needs to be mutable */
639 AutoMutableStateDependency adep(m->pParent);
640 if (FAILED(adep.hrc())) return adep.hrc();
641
642 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
643
644 if (m->bd->fUseHostIOCache != !!fUseHostIOCache)
645 {
646 m->bd.backup();
647 m->bd->fUseHostIOCache = !!fUseHostIOCache;
648
649 alock.release();
650 AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS); // m->pParent is const, needs no locking
651 m->pParent->i_setModified(Machine::IsModified_Storage);
652 mlock.release();
653
654 m->pParent->i_onStorageControllerChange(m->pParent->i_getId(), m->bd->strName);
655 }
656
657 return S_OK;
658}
659
660HRESULT StorageController::getBootable(BOOL *fBootable)
661{
662 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
663
664 *fBootable = m->bd->fBootable;
665
666 return S_OK;
667}
668
669// public methods only for internal purposes
670/////////////////////////////////////////////////////////////////////////////
671
672const Utf8Str& StorageController::i_getName() const
673{
674 return m->bd->strName;
675}
676
677StorageControllerType_T StorageController::i_getControllerType() const
678{
679 return m->bd->controllerType;
680}
681
682StorageBus_T StorageController::i_getStorageBus() const
683{
684 return m->bd->storageBus;
685}
686
687ULONG StorageController::i_getInstance() const
688{
689 return m->bd->ulInstance;
690}
691
692bool StorageController::i_getBootable() const
693{
694 return !!m->bd->fBootable;
695}
696
697/**
698 * Checks the validity of a port and device number.
699 *
700 * @retval S_OK If the given port and device numbers are within the range
701 * supported by this controller.
702 * @retval E_INVALIDARG If not. Sets an error.
703 * @param aControllerPort Controller port number.
704 * @param aDevice Device number.
705 */
706HRESULT StorageController::i_checkPortAndDeviceValid(LONG aControllerPort,
707 LONG aDevice)
708{
709 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
710
711 ULONG portCount = m->bd->ulPortCount;
712 ULONG devicesPerPort;
713 HRESULT hrc = m->pParent->i_getPlatformProperties()->GetMaxDevicesPerPortForStorageBus(m->bd->storageBus, &devicesPerPort);
714 if (FAILED(hrc)) return hrc;
715
716 if ( aControllerPort < 0
717 || aControllerPort >= (LONG)portCount
718 || aDevice < 0
719 || aDevice >= (LONG)devicesPerPort
720 )
721 return setError(E_INVALIDARG,
722 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])"),
723 (int)aControllerPort, (int)portCount-1, (int)aDevice, (int)devicesPerPort-1);
724
725 return S_OK;
726}
727
728/** @note Locks objects for writing! */
729void StorageController::i_setBootable(BOOL fBootable)
730{
731 AutoCaller autoCaller(this);
732 AssertComRCReturnVoid(autoCaller.hrc());
733
734 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
735
736 m->bd.backup();
737 m->bd->fBootable = RT_BOOL(fBootable);
738}
739
740/** @note Locks objects for writing! */
741void StorageController::i_rollback()
742{
743 AutoCaller autoCaller(this);
744 AssertComRCReturnVoid(autoCaller.hrc());
745
746 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
747
748 m->bd.rollback();
749}
750
751/**
752 * @note Locks this object for writing, together with the peer object (also
753 * for writing) if there is one.
754 */
755void StorageController::i_commit()
756{
757 /* sanity */
758 AutoCaller autoCaller(this);
759 AssertComRCReturnVoid(autoCaller.hrc());
760
761 /* sanity too */
762 AutoCaller peerCaller(m->pPeer);
763 AssertComRCReturnVoid(peerCaller.hrc());
764
765 /* lock both for writing since we modify both (m->pPeer is "master" so locked
766 * first) */
767 AutoMultiWriteLock2 alock(m->pPeer, this COMMA_LOCKVAL_SRC_POS);
768
769 if (m->bd.isBackedUp())
770 {
771 m->bd.commit();
772 if (m->pPeer)
773 {
774 // attach new data to the peer and reshare it
775 m->pPeer->m->bd.attach(m->bd);
776 }
777 }
778}
779
780/**
781 * Cancels sharing (if any) by making an independent copy of data.
782 * This operation also resets this object's peer to NULL.
783 *
784 * @note Locks this object for writing, together with the peer object
785 * represented by @a aThat (locked for reading).
786 */
787void StorageController::i_unshare()
788{
789 /* sanity */
790 AutoCaller autoCaller(this);
791 AssertComRCReturnVoid(autoCaller.hrc());
792
793 /* sanity too */
794 AutoCaller peerCaller(m->pPeer);
795 AssertComRCReturnVoid(peerCaller.hrc());
796
797 /* peer is not modified, lock it for reading (m->pPeer is "master" so locked
798 * first) */
799 AutoReadLock rl(m->pPeer COMMA_LOCKVAL_SRC_POS);
800 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
801
802 if (m->bd.isShared())
803 {
804 if (!m->bd.isBackedUp())
805 m->bd.backup();
806
807 m->bd.commit();
808 }
809
810 unconst(m->pPeer) = NULL;
811}
812
813/**
814 * Returns a controller name from a given storage bus type.
815 *
816 * @return Controller name.
817 * @param aBusType Bus type to get controller name for.
818 */
819/* static */
820com::Utf8Str StorageController::i_controllerNameFromBusType(StorageBus_T aBusType)
821{
822 com::Utf8Str strControllerName = "Unknown";
823 switch (aBusType)
824 {
825 case StorageBus_IDE:
826 {
827 strControllerName = "IDE";
828 break;
829 }
830 case StorageBus_SATA:
831 {
832 strControllerName = "SATA";
833 break;
834 }
835 case StorageBus_SCSI:
836 {
837 strControllerName = "SCSI";
838 break;
839 }
840 case StorageBus_Floppy:
841 {
842 strControllerName = "Floppy";
843 break;
844 }
845 case StorageBus_SAS:
846 {
847 strControllerName = "SAS";
848 break;
849 }
850 case StorageBus_USB:
851 {
852 strControllerName = "USB";
853 break;
854 }
855 case StorageBus_PCIe:
856 {
857 strControllerName = "PCIe";
858 break;
859 }
860 case StorageBus_VirtioSCSI:
861 {
862 strControllerName = "VirtioSCSI";
863 break;
864 }
865 default:
866 AssertFailed(); /* Catch missing case above. */
867 break;
868 }
869 return strControllerName;
870}
871
872Machine* StorageController::i_getMachine()
873{
874 return m->pParent;
875}
876
877ComObjPtr<StorageController> StorageController::i_getPeer()
878{
879 return m->pPeer;
880}
881
882// private methods
883/////////////////////////////////////////////////////////////////////////////
884
885
886/* 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