VirtualBox

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

Last change on this file since 56035 was 56035, checked in by vboxsync, 9 years ago

Main/Machine+USBController+StorageController: Mix of deleting useless functionality, fixing of missing sanity checks and adding some additional functionality. The removed functionality is the possibility to specify patters of guest properties which will trigger notifications, which wasn't useful as it is per VM, sabotaging other API clients (e.g. the VM process assumes it gets the notifications it needs). The storage controller setters were lacking a lot of state and consistency sanity checking, which is now fixed. Both the USB and storage controllers can now be renamed (no API client uses this functionality though), all with very pessimistic assumptions (only when the VM is powered off).

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