VirtualBox

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

Last change on this file since 103131 was 101220, checked in by vboxsync, 13 months ago

Main: Moved i_controllerNameFromBusType() from Machine to StorageController, also now as a static function, and use this also in the Unattended installer, to avoid code duplication.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.4 KB
Line 
1/* $Id: StorageControllerImpl.cpp 101220 2023-09-21 10:51:17Z 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 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 for (Machine::MediumAttachmentList::const_iterator
332 it = atts.begin();
333 it != atts.end();
334 ++it)
335 {
336 IMediumAttachment *iA = *it;
337 MediumAttachment *pAttach = static_cast<MediumAttachment *>(iA);
338 AutoWriteLock attlock(pAttach COMMA_LOCKVAL_SRC_POS);
339 pAttach->i_updateName(aName);
340 }
341
342
343 m->bd.backup();
344 m->bd->strName = aName;
345
346 m->pParent->i_setModified(Machine::IsModified_Storage);
347 alock.release();
348
349 m->pParent->i_onStorageControllerChange(m->pParent->i_getId(), aName);
350 }
351
352 return S_OK;
353}
354
355HRESULT StorageController::getBus(StorageBus_T *aBus)
356{
357 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
358
359 *aBus = m->bd->storageBus;
360
361 return S_OK;
362}
363
364HRESULT StorageController::getControllerType(StorageControllerType_T *aControllerType)
365{
366 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
367
368 *aControllerType = m->bd->controllerType;
369
370 return S_OK;
371}
372
373HRESULT StorageController::setControllerType(StorageControllerType_T aControllerType)
374{
375 /* the machine needs to be mutable */
376 AutoMutableStateDependency adep(m->pParent);
377 if (FAILED(adep.hrc())) return adep.hrc();
378
379 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
380
381 HRESULT hrc = S_OK;
382 switch (m->bd->storageBus)
383 {
384 case StorageBus_IDE:
385 if ( (aControllerType != StorageControllerType_PIIX3)
386 && (aControllerType != StorageControllerType_PIIX4)
387 && (aControllerType != StorageControllerType_ICH6))
388 hrc = E_INVALIDARG;
389 break;
390 case StorageBus_SATA:
391 if (aControllerType != StorageControllerType_IntelAhci)
392 hrc = E_INVALIDARG;
393 break;
394 case StorageBus_SCSI:
395 if ( (aControllerType != StorageControllerType_LsiLogic)
396 && (aControllerType != StorageControllerType_BusLogic))
397 hrc = E_INVALIDARG;
398 break;
399 case StorageBus_Floppy:
400 if (aControllerType != StorageControllerType_I82078)
401 hrc = E_INVALIDARG;
402 break;
403 case StorageBus_SAS:
404 if (aControllerType != StorageControllerType_LsiLogicSas)
405 hrc = E_INVALIDARG;
406 break;
407 case StorageBus_USB:
408 if (aControllerType != StorageControllerType_USB)
409 hrc = E_INVALIDARG;
410 break;
411 case StorageBus_PCIe:
412 if (aControllerType != StorageControllerType_NVMe)
413 hrc = E_INVALIDARG;
414 break;
415 case StorageBus_VirtioSCSI:
416 if (aControllerType != StorageControllerType_VirtioSCSI)
417 hrc = E_INVALIDARG;
418 break;
419 default:
420 AssertMsgFailed(("Invalid controller type %d\n", m->bd->storageBus));
421 hrc = E_INVALIDARG;
422 break;
423 }
424
425 if (!SUCCEEDED(hrc))
426 return setError(hrc, tr("Invalid controller type %d"), aControllerType);
427
428 if (m->bd->controllerType != aControllerType)
429 {
430 m->bd.backup();
431 m->bd->controllerType = aControllerType;
432
433 alock.release();
434 AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS); // m->pParent is const, needs no locking
435 m->pParent->i_setModified(Machine::IsModified_Storage);
436 mlock.release();
437
438 m->pParent->i_onStorageControllerChange(m->pParent->i_getId(), m->bd->strName);
439 }
440
441 return S_OK;
442}
443
444HRESULT StorageController::getMaxDevicesPerPortCount(ULONG *aMaxDevicesPerPortCount)
445{
446 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
447 return m->pParent->i_getPlatformProperties()->GetMaxDevicesPerPortForStorageBus(m->bd->storageBus, aMaxDevicesPerPortCount);
448}
449
450HRESULT StorageController::getMinPortCount(ULONG *aMinPortCount)
451{
452 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
453 return m->pParent->i_getPlatformProperties()->GetMinPortCountForStorageBus(m->bd->storageBus, aMinPortCount);
454}
455
456HRESULT StorageController::getMaxPortCount(ULONG *aMaxPortCount)
457{
458 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
459 return m->pParent->i_getPlatformProperties()->GetMaxPortCountForStorageBus(m->bd->storageBus, aMaxPortCount);
460}
461
462HRESULT StorageController::getPortCount(ULONG *aPortCount)
463{
464 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
465
466 *aPortCount = m->bd->ulPortCount;
467
468 return S_OK;
469}
470
471HRESULT StorageController::setPortCount(ULONG aPortCount)
472{
473 /* the machine needs to be mutable */
474 AutoMutableStateDependency adep(m->pParent);
475 if (FAILED(adep.hrc())) return adep.hrc();
476
477 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
478
479 switch (m->bd->storageBus)
480 {
481 case StorageBus_SATA:
482 {
483 /* AHCI SATA supports a maximum of 30 ports. */
484 if (aPortCount < 1 || aPortCount > 30)
485 return setError(E_INVALIDARG,
486 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
487 aPortCount, 1, 30);
488 break;
489 }
490 case StorageBus_SCSI:
491 {
492 /*
493 * SCSI does not support setting different ports.
494 * (doesn't make sense here either).
495 * The maximum and minimum is 16 and unless the callee
496 * tries to set a different value we return an error.
497 */
498 if (aPortCount != 16)
499 return setError(E_INVALIDARG,
500 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
501 aPortCount, 16, 16);
502 break;
503 }
504 case StorageBus_IDE:
505 {
506 /*
507 * The port count is fixed to 2.
508 */
509 if (aPortCount != 2)
510 return setError(E_INVALIDARG,
511 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
512 aPortCount, 2, 2);
513 break;
514 }
515 case StorageBus_Floppy:
516 {
517 /*
518 * The port count is fixed to 1.
519 */
520 if (aPortCount != 1)
521 return setError(E_INVALIDARG,
522 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
523 aPortCount, 1, 1);
524 break;
525 }
526 case StorageBus_SAS:
527 {
528 /* SAS supports a maximum of 255 ports. */
529 if (aPortCount < 1 || aPortCount > 255)
530 return setError(E_INVALIDARG,
531 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
532 aPortCount, 1, 255);
533 break;
534 }
535 case StorageBus_USB:
536 {
537 /*
538 * The port count is fixed to 8.
539 */
540 if (aPortCount != 8)
541 return setError(E_INVALIDARG,
542 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
543 aPortCount, 8, 8);
544 break;
545 }
546 case StorageBus_PCIe:
547 {
548 /*
549 * PCIe (NVMe in particular) supports theoretically 2^32 - 1
550 * different namespaces, limit the amount artifically here.
551 */
552 if (aPortCount < 1 || aPortCount > 255)
553 return setError(E_INVALIDARG,
554 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
555 aPortCount, 1, 255);
556 break;
557 }
558 case StorageBus_VirtioSCSI:
559 {
560 /*
561 * virtio-scsi supports 256 targets (with 16384 LUNs each).
562 */
563 if (aPortCount < 1 || aPortCount > 256)
564 return setError(E_INVALIDARG,
565 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
566 aPortCount, 1, 256);
567 break;
568 }
569 default:
570 AssertMsgFailed(("Invalid controller type %d\n", m->bd->storageBus));
571 }
572
573 if (m->bd->ulPortCount != aPortCount)
574 {
575 m->bd.backup();
576 m->bd->ulPortCount = aPortCount;
577
578 alock.release();
579 AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS); // m->pParent is const, needs no locking
580 m->pParent->i_setModified(Machine::IsModified_Storage);
581 mlock.release();
582
583 m->pParent->i_onStorageControllerChange(m->pParent->i_getId(), m->bd->strName);
584 }
585
586 return S_OK;
587}
588
589HRESULT StorageController::getInstance(ULONG *aInstance)
590{
591 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
592
593 *aInstance = m->bd->ulInstance;
594
595 return S_OK;
596}
597
598HRESULT StorageController::setInstance(ULONG aInstance)
599{
600 /* the machine needs to be mutable */
601 AutoMutableStateDependency adep(m->pParent);
602 if (FAILED(adep.hrc())) return adep.hrc();
603
604 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
605
606 if (m->bd->ulInstance != aInstance)
607 {
608 m->bd.backup();
609 m->bd->ulInstance = aInstance;
610
611 alock.release();
612 AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS); // m->pParent is const, needs no locking
613 m->pParent->i_setModified(Machine::IsModified_Storage);
614 mlock.release();
615
616 m->pParent->i_onStorageControllerChange(m->pParent->i_getId(), m->bd->strName);
617 }
618
619 return S_OK;
620}
621
622HRESULT StorageController::getUseHostIOCache(BOOL *fUseHostIOCache)
623{
624 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
625
626 *fUseHostIOCache = m->bd->fUseHostIOCache;
627
628 return S_OK;
629}
630
631HRESULT StorageController::setUseHostIOCache(BOOL fUseHostIOCache)
632{
633 /* the machine needs to be mutable */
634 AutoMutableStateDependency adep(m->pParent);
635 if (FAILED(adep.hrc())) return adep.hrc();
636
637 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
638
639 if (m->bd->fUseHostIOCache != !!fUseHostIOCache)
640 {
641 m->bd.backup();
642 m->bd->fUseHostIOCache = !!fUseHostIOCache;
643
644 alock.release();
645 AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS); // m->pParent is const, needs no locking
646 m->pParent->i_setModified(Machine::IsModified_Storage);
647 mlock.release();
648
649 m->pParent->i_onStorageControllerChange(m->pParent->i_getId(), m->bd->strName);
650 }
651
652 return S_OK;
653}
654
655HRESULT StorageController::getBootable(BOOL *fBootable)
656{
657 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
658
659 *fBootable = m->bd->fBootable;
660
661 return S_OK;
662}
663
664// public methods only for internal purposes
665/////////////////////////////////////////////////////////////////////////////
666
667const Utf8Str& StorageController::i_getName() const
668{
669 return m->bd->strName;
670}
671
672StorageControllerType_T StorageController::i_getControllerType() const
673{
674 return m->bd->controllerType;
675}
676
677StorageBus_T StorageController::i_getStorageBus() const
678{
679 return m->bd->storageBus;
680}
681
682ULONG StorageController::i_getInstance() const
683{
684 return m->bd->ulInstance;
685}
686
687bool StorageController::i_getBootable() const
688{
689 return !!m->bd->fBootable;
690}
691
692/**
693 * Checks the validity of a port and device number.
694 *
695 * @retval S_OK If the given port and device numbers are within the range
696 * supported by this controller.
697 * @retval E_INVALIDARG If not. Sets an error.
698 * @param aControllerPort Controller port number.
699 * @param aDevice Device number.
700 */
701HRESULT StorageController::i_checkPortAndDeviceValid(LONG aControllerPort,
702 LONG aDevice)
703{
704 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
705
706 ULONG portCount = m->bd->ulPortCount;
707 ULONG devicesPerPort;
708 HRESULT hrc = m->pParent->i_getPlatformProperties()->GetMaxDevicesPerPortForStorageBus(m->bd->storageBus, &devicesPerPort);
709 if (FAILED(hrc)) return hrc;
710
711 if ( aControllerPort < 0
712 || aControllerPort >= (LONG)portCount
713 || aDevice < 0
714 || aDevice >= (LONG)devicesPerPort
715 )
716 return setError(E_INVALIDARG,
717 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])"),
718 (int)aControllerPort, (int)portCount-1, (int)aDevice, (int)devicesPerPort-1);
719
720 return S_OK;
721}
722
723/** @note Locks objects for writing! */
724void StorageController::i_setBootable(BOOL fBootable)
725{
726 AutoCaller autoCaller(this);
727 AssertComRCReturnVoid(autoCaller.hrc());
728
729 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
730
731 m->bd.backup();
732 m->bd->fBootable = RT_BOOL(fBootable);
733}
734
735/** @note Locks objects for writing! */
736void StorageController::i_rollback()
737{
738 AutoCaller autoCaller(this);
739 AssertComRCReturnVoid(autoCaller.hrc());
740
741 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
742
743 m->bd.rollback();
744}
745
746/**
747 * @note Locks this object for writing, together with the peer object (also
748 * for writing) if there is one.
749 */
750void StorageController::i_commit()
751{
752 /* sanity */
753 AutoCaller autoCaller(this);
754 AssertComRCReturnVoid(autoCaller.hrc());
755
756 /* sanity too */
757 AutoCaller peerCaller(m->pPeer);
758 AssertComRCReturnVoid(peerCaller.hrc());
759
760 /* lock both for writing since we modify both (m->pPeer is "master" so locked
761 * first) */
762 AutoMultiWriteLock2 alock(m->pPeer, this COMMA_LOCKVAL_SRC_POS);
763
764 if (m->bd.isBackedUp())
765 {
766 m->bd.commit();
767 if (m->pPeer)
768 {
769 // attach new data to the peer and reshare it
770 m->pPeer->m->bd.attach(m->bd);
771 }
772 }
773}
774
775/**
776 * Cancels sharing (if any) by making an independent copy of data.
777 * This operation also resets this object's peer to NULL.
778 *
779 * @note Locks this object for writing, together with the peer object
780 * represented by @a aThat (locked for reading).
781 */
782void StorageController::i_unshare()
783{
784 /* sanity */
785 AutoCaller autoCaller(this);
786 AssertComRCReturnVoid(autoCaller.hrc());
787
788 /* sanity too */
789 AutoCaller peerCaller(m->pPeer);
790 AssertComRCReturnVoid(peerCaller.hrc());
791
792 /* peer is not modified, lock it for reading (m->pPeer is "master" so locked
793 * first) */
794 AutoReadLock rl(m->pPeer COMMA_LOCKVAL_SRC_POS);
795 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
796
797 if (m->bd.isShared())
798 {
799 if (!m->bd.isBackedUp())
800 m->bd.backup();
801
802 m->bd.commit();
803 }
804
805 unconst(m->pPeer) = NULL;
806}
807
808/**
809 * Returns a controller name from a given storage bus type.
810 *
811 * @return Controller name.
812 * @param aBusType Bus type to get controller name for.
813 */
814/* static */
815com::Utf8Str StorageController::i_controllerNameFromBusType(StorageBus_T aBusType)
816{
817 com::Utf8Str strControllerName = "Unknown";
818 switch (aBusType)
819 {
820 case StorageBus_IDE:
821 {
822 strControllerName = "IDE";
823 break;
824 }
825 case StorageBus_SATA:
826 {
827 strControllerName = "SATA";
828 break;
829 }
830 case StorageBus_SCSI:
831 {
832 strControllerName = "SCSI";
833 break;
834 }
835 case StorageBus_Floppy:
836 {
837 strControllerName = "Floppy";
838 break;
839 }
840 case StorageBus_SAS:
841 {
842 strControllerName = "SAS";
843 break;
844 }
845 case StorageBus_USB:
846 {
847 strControllerName = "USB";
848 break;
849 }
850 case StorageBus_PCIe:
851 {
852 strControllerName = "PCIe";
853 break;
854 }
855 case StorageBus_VirtioSCSI:
856 {
857 strControllerName = "VirtioSCSI";
858 break;
859 }
860 default:
861 AssertFailed(); /* Catch missing case above. */
862 break;
863 }
864 return strControllerName;
865}
866
867Machine* StorageController::i_getMachine()
868{
869 return m->pParent;
870}
871
872ComObjPtr<StorageController> StorageController::i_getPeer()
873{
874 return m->pPeer;
875}
876
877// private methods
878/////////////////////////////////////////////////////////////////////////////
879
880
881/* 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