VirtualBox

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

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

scm copyright and license note update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 16.9 KB
Line 
1/* $Id: MediumAttachmentImpl.cpp 96407 2022-08-22 17:43:14Z vboxsync $ */
2/** @file
3 * VirtualBox COM class implementation
4 */
5
6/*
7 * Copyright (C) 2006-2022 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28#define LOG_GROUP LOG_GROUP_MAIN_MEDIUMATTACHMENT
29#include "MediumAttachmentImpl.h"
30#include "MachineImpl.h"
31#include "MediumImpl.h"
32#include "Global.h"
33#include "StringifyEnums.h"
34
35#include "AutoCaller.h"
36#include "LoggingNew.h"
37
38#include <iprt/cpp/utils.h>
39
40////////////////////////////////////////////////////////////////////////////////
41//
42// private member data definition
43//
44////////////////////////////////////////////////////////////////////////////////
45
46struct BackupableMediumAttachmentData
47{
48 BackupableMediumAttachmentData()
49 : fImplicit(false)
50 { }
51
52 ComObjPtr<Medium> pMedium;
53 /* Since MediumAttachment is not a first class citizen when it
54 * comes to managing settings, having a reference to the storage
55 * controller will not work - when settings are changed it will point
56 * to the old, uninitialized instance. Changing this requires
57 * substantial changes to MediumImpl.cpp. */
58 /* Same counts for the assigned bandwidth group */
59 bool fImplicit;
60 const Utf8Str strControllerName;
61 settings::AttachedDevice mData;
62};
63
64struct MediumAttachment::Data
65{
66 Data(Machine * const aMachine = NULL)
67 : pMachine(aMachine),
68 fIsEjected(false)
69 { }
70
71 /** Reference to Machine object, for checking mutable state. */
72 Machine * const pMachine;
73 /* later: const ComObjPtr<MediumAttachment> mPeer; */
74 bool fIsEjected;
75 Backupable<BackupableMediumAttachmentData> bd;
76};
77
78// constructor / destructor
79/////////////////////////////////////////////////////////////////////////////
80
81DEFINE_EMPTY_CTOR_DTOR(MediumAttachment)
82
83HRESULT MediumAttachment::FinalConstruct()
84{
85 LogFlowThisFunc(("\n"));
86 return BaseFinalConstruct();
87}
88
89void MediumAttachment::FinalRelease()
90{
91 LogFlowThisFuncEnter();
92 uninit();
93 BaseFinalRelease();
94 LogFlowThisFuncLeave();
95}
96
97// public initializer/uninitializer for internal purposes only
98/////////////////////////////////////////////////////////////////////////////
99
100/**
101 * Initializes the medium attachment object.
102 *
103 * @param aParent Machine object.
104 * @param aMedium Medium object.
105 * @param aControllerName Controller the hard disk is attached to.
106 * @param aPort Port number.
107 * @param aDevice Device number on the port.
108 * @param aType Device type.
109 * @param aImplicit
110 * @param aPassthrough Whether accesses are directly passed to the host drive.
111 * @param aTempEject Whether guest-triggered eject results in unmounting the medium.
112 * @param aNonRotational Whether this medium is non-rotational (aka SSD).
113 * @param aDiscard Whether this medium supports discarding unused blocks.
114 * @param aHotPluggable Whether this medium is hot-pluggable.
115 * @param strBandwidthGroup Bandwidth group.
116 */
117HRESULT MediumAttachment::init(Machine *aParent,
118 Medium *aMedium,
119 const Utf8Str &aControllerName,
120 LONG aPort,
121 LONG aDevice,
122 DeviceType_T aType,
123 bool aImplicit,
124 bool aPassthrough,
125 bool aTempEject,
126 bool aNonRotational,
127 bool aDiscard,
128 bool aHotPluggable,
129 const Utf8Str &strBandwidthGroup)
130{
131 LogFlowThisFuncEnter();
132 LogFlowThisFunc(("aParent=%p aMedium=%p aControllerName=%s aPort=%d aDevice=%d aType=%d aImplicit=%d aPassthrough=%d aTempEject=%d aNonRotational=%d aDiscard=%d aHotPluggable=%d strBandwithGroup=%s\n", aParent, aMedium, aControllerName.c_str(), aPort, aDevice, aType, aImplicit, aPassthrough, aTempEject, aNonRotational, aDiscard, aHotPluggable, strBandwidthGroup.c_str()));
133
134 if (aType == DeviceType_HardDisk)
135 AssertReturn(aMedium, E_INVALIDARG);
136
137 /* Enclose the state transition NotReady->InInit->Ready */
138 AutoInitSpan autoInitSpan(this);
139 AssertReturn(autoInitSpan.isOk(), E_FAIL);
140
141 m = new Data();
142
143 unconst(m->pMachine) = aParent;
144
145 m->bd.allocate();
146 m->bd->pMedium = aMedium;
147 m->bd->mData.strBwGroup = strBandwidthGroup;
148 unconst(m->bd->strControllerName) = aControllerName;
149 m->bd->mData.lPort = aPort;
150 m->bd->mData.lDevice = aDevice;
151 m->bd->mData.deviceType = aType;
152
153 m->bd->mData.fPassThrough = aPassthrough;
154 m->bd->mData.fTempEject = aTempEject;
155 m->bd->mData.fNonRotational = aNonRotational;
156 m->bd->mData.fDiscard = aDiscard;
157 m->bd->fImplicit = aImplicit;
158 m->bd->mData.fHotPluggable = aHotPluggable;
159
160 /* Confirm a successful initialization when it's the case */
161 autoInitSpan.setSucceeded();
162
163 /* Construct a short log name for this attachment. */
164 i_updateLogName();
165
166 LogFlowThisFunc(("LEAVE - %s\n", i_getLogName()));
167 return S_OK;
168}
169
170/**
171 * Initializes the medium attachment object given another guest object
172 * (a kind of copy constructor). This object makes a private copy of data
173 * of the original object passed as an argument.
174 */
175HRESULT MediumAttachment::initCopy(Machine *aParent, MediumAttachment *aThat)
176{
177 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
178
179 ComAssertRet(aParent && aThat, E_INVALIDARG);
180
181 /* Enclose the state transition NotReady->InInit->Ready */
182 AutoInitSpan autoInitSpan(this);
183 AssertReturn(autoInitSpan.isOk(), E_FAIL);
184
185 m = new Data(aParent);
186 /* m->pPeer is left null */
187
188 AutoCaller thatCaller(aThat);
189 AssertComRCReturnRC(thatCaller.rc());
190
191 AutoReadLock thatlock(aThat COMMA_LOCKVAL_SRC_POS);
192 m->bd.attachCopy(aThat->m->bd);
193
194 /* Confirm a successful initialization */
195 autoInitSpan.setSucceeded();
196
197 /* Construct a short log name for this attachment. */
198 i_updateLogName();
199
200 LogFlowThisFunc(("LEAVE - %s\n", i_getLogName()));
201 return S_OK;
202}
203
204/**
205 * Uninitializes the instance.
206 * Called from FinalRelease().
207 */
208void MediumAttachment::uninit()
209{
210 LogFlowThisFunc(("ENTER - %s\n", i_getLogName()));
211
212 /* Enclose the state transition Ready->InUninit->NotReady */
213 AutoUninitSpan autoUninitSpan(this);
214 if (autoUninitSpan.uninitDone())
215 return;
216
217 m->bd.free();
218
219 unconst(m->pMachine) = NULL;
220
221 delete m;
222 m = NULL;
223
224 LogFlowThisFuncLeave();
225}
226
227// IHardDiskAttachment properties
228/////////////////////////////////////////////////////////////////////////////
229
230
231HRESULT MediumAttachment::getMachine(ComPtr<IMachine> &aMachine)
232{
233 LogFlowThisFuncEnter();
234
235 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
236
237 ComObjPtr<Machine> pMachine(m->pMachine);
238 pMachine.queryInterfaceTo(aMachine.asOutParam());
239
240 LogFlowThisFuncLeave();
241 return S_OK;
242}
243
244
245HRESULT MediumAttachment::getMedium(ComPtr<IMedium> &aHardDisk)
246{
247 LogFlowThisFuncEnter();
248
249 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
250
251 aHardDisk = m->bd->pMedium;
252
253 LogFlowThisFuncLeave();
254 return S_OK;
255}
256
257
258HRESULT MediumAttachment::getController(com::Utf8Str &aController)
259{
260 LogFlowThisFuncEnter();
261
262 /* m->controller is constant during life time, no need to lock */
263 aController = Utf8Str(m->bd->strControllerName);
264
265 LogFlowThisFuncLeave();
266 return S_OK;
267}
268
269
270HRESULT MediumAttachment::getPort(LONG *aPort)
271{
272 LogFlowThisFuncEnter();
273
274 /* m->bd->port is constant during life time, no need to lock */
275 *aPort = m->bd->mData.lPort;
276
277 LogFlowThisFuncLeave();
278 return S_OK;
279}
280
281HRESULT MediumAttachment::getDevice(LONG *aDevice)
282{
283 LogFlowThisFuncEnter();
284
285 /* m->bd->device is constant during life time, no need to lock */
286 *aDevice = m->bd->mData.lDevice;
287
288 LogFlowThisFuncLeave();
289 return S_OK;
290}
291
292HRESULT MediumAttachment::getType(DeviceType_T *aType)
293{
294 LogFlowThisFuncEnter();
295
296 /* m->bd->type is constant during life time, no need to lock */
297 *aType = m->bd->mData.deviceType;
298
299 LogFlowThisFuncLeave();
300 return S_OK;
301}
302
303
304HRESULT MediumAttachment::getPassthrough(BOOL *aPassthrough)
305{
306 LogFlowThisFuncEnter();
307
308 AutoReadLock lock(this COMMA_LOCKVAL_SRC_POS);
309
310 *aPassthrough = m->bd->mData.fPassThrough;
311
312 LogFlowThisFuncLeave();
313 return S_OK;
314}
315
316
317HRESULT MediumAttachment::getTemporaryEject(BOOL *aTemporaryEject)
318{
319 LogFlowThisFuncEnter();
320
321 AutoReadLock lock(this COMMA_LOCKVAL_SRC_POS);
322
323 *aTemporaryEject = m->bd->mData.fTempEject;
324
325 LogFlowThisFuncLeave();
326 return S_OK;
327}
328
329
330HRESULT MediumAttachment::getIsEjected(BOOL *aEjected)
331{
332 LogFlowThisFuncEnter();
333
334 AutoReadLock lock(this COMMA_LOCKVAL_SRC_POS);
335
336 *aEjected = m->fIsEjected;
337
338 LogFlowThisFuncLeave();
339 return S_OK;
340}
341
342
343HRESULT MediumAttachment::getNonRotational(BOOL *aNonRotational)
344{
345 LogFlowThisFuncEnter();
346
347 AutoReadLock lock(this COMMA_LOCKVAL_SRC_POS);
348
349 *aNonRotational = m->bd->mData.fNonRotational;
350
351 LogFlowThisFuncLeave();
352 return S_OK;
353}
354
355HRESULT MediumAttachment::getDiscard(BOOL *aDiscard)
356{
357 LogFlowThisFuncEnter();
358
359 AutoReadLock lock(this COMMA_LOCKVAL_SRC_POS);
360
361 *aDiscard = m->bd->mData.fDiscard;
362
363 LogFlowThisFuncLeave();
364 return S_OK;
365}
366
367
368HRESULT MediumAttachment::getBandwidthGroup(ComPtr<IBandwidthGroup> &aBandwidthGroup)
369{
370 LogFlowThisFuncEnter();
371
372 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
373
374 HRESULT hrc = S_OK;
375 if (m->bd->mData.strBwGroup.isNotEmpty())
376 {
377 ComObjPtr<BandwidthGroup> pBwGroup;
378 hrc = m->pMachine->i_getBandwidthGroup(m->bd->mData.strBwGroup, pBwGroup, true /* fSetError */);
379
380 Assert(SUCCEEDED(hrc)); /* This is not allowed to fail because the existence of the
381 group was checked when it was attached. */
382
383 if (SUCCEEDED(hrc))
384 pBwGroup.queryInterfaceTo(aBandwidthGroup.asOutParam());
385 }
386
387 LogFlowThisFuncLeave();
388 return hrc;
389}
390
391HRESULT MediumAttachment::getHotPluggable(BOOL *aHotPluggable)
392{
393 LogFlowThisFuncEnter();
394
395 AutoReadLock lock(this COMMA_LOCKVAL_SRC_POS);
396
397 *aHotPluggable = m->bd->mData.fHotPluggable;
398
399 LogFlowThisFuncLeave();
400 return S_OK;
401}
402
403/**
404 * @note Locks this object for writing.
405 */
406void MediumAttachment::i_rollback()
407{
408 LogFlowThisFunc(("ENTER - %s\n", i_getLogName()));
409
410 /* sanity */
411 AutoCaller autoCaller(this);
412 AssertComRCReturnVoid(autoCaller.rc());
413
414 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
415
416 m->bd.rollback();
417
418 LogFlowThisFunc(("LEAVE - %s\n", i_getLogName()));
419}
420
421/**
422 * @note Locks this object for writing.
423 */
424void MediumAttachment::i_commit()
425{
426 LogFlowThisFunc(("ENTER - %s\n", i_getLogName()));
427
428 /* sanity */
429 AutoCaller autoCaller(this);
430 AssertComRCReturnVoid(autoCaller.rc());
431
432 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
433
434 if (m->bd.isBackedUp())
435 m->bd.commit();
436
437 LogFlowThisFunc(("LEAVE - %s\n", i_getLogName()));
438}
439
440bool MediumAttachment::i_isImplicit() const
441{
442 return m->bd->fImplicit;
443}
444
445void MediumAttachment::i_setImplicit(bool aImplicit)
446{
447 Assert(!m->pMachine->i_isSnapshotMachine());
448 m->bd->fImplicit = aImplicit;
449
450 /* Construct a short log name for this attachment. */
451 i_updateLogName();
452}
453
454const ComObjPtr<Medium>& MediumAttachment::i_getMedium() const
455{
456 return m->bd->pMedium;
457}
458
459const Utf8Str &MediumAttachment::i_getControllerName() const
460{
461 return m->bd->strControllerName;
462}
463
464LONG MediumAttachment::i_getPort() const
465{
466 return m->bd->mData.lPort;
467}
468
469LONG MediumAttachment::i_getDevice() const
470{
471 return m->bd->mData.lDevice;
472}
473
474DeviceType_T MediumAttachment::i_getType() const
475{
476 return m->bd->mData.deviceType;
477}
478
479bool MediumAttachment::i_getPassthrough() const
480{
481 AutoReadLock lock(this COMMA_LOCKVAL_SRC_POS);
482 return m->bd->mData.fPassThrough;
483}
484
485bool MediumAttachment::i_getTempEject() const
486{
487 AutoReadLock lock(this COMMA_LOCKVAL_SRC_POS);
488 return m->bd->mData.fTempEject;
489}
490
491bool MediumAttachment::i_getNonRotational() const
492{
493 AutoReadLock lock(this COMMA_LOCKVAL_SRC_POS);
494 return m->bd->mData.fNonRotational;
495}
496
497bool MediumAttachment::i_getDiscard() const
498{
499 AutoReadLock lock(this COMMA_LOCKVAL_SRC_POS);
500 return m->bd->mData.fDiscard;
501}
502
503bool MediumAttachment::i_getHotPluggable() const
504{
505 AutoReadLock lock(this COMMA_LOCKVAL_SRC_POS);
506 return m->bd->mData.fHotPluggable;
507}
508
509Utf8Str& MediumAttachment::i_getBandwidthGroup() const
510{
511 return m->bd->mData.strBwGroup;
512}
513
514bool MediumAttachment::i_matches(const Utf8Str &aControllerName, LONG aPort, LONG aDevice)
515{
516 return ( aControllerName == m->bd->strControllerName
517 && aPort == m->bd->mData.lPort
518 && aDevice == m->bd->mData.lDevice);
519}
520
521/** Must be called from under this object's write lock. */
522void MediumAttachment::i_updateName(const Utf8Str &aName)
523{
524 Assert(isWriteLockOnCurrentThread());
525 Assert(!m->pMachine->i_isSnapshotMachine());
526
527 m->bd.backup();
528 unconst(m->bd->strControllerName) = aName;
529
530 /* Construct a short log name for this attachment. */
531 i_updateLogName();
532}
533
534/**
535 * Sets the medium of this attachment and unsets the "implicit" flag.
536 * @param aMedium
537 */
538void MediumAttachment::i_updateMedium(const ComObjPtr<Medium> &aMedium)
539{
540 Assert(isWriteLockOnCurrentThread());
541 /* No assertion for a snapshot. Method used in deleting snapshot. */
542
543 m->bd.backup();
544 m->bd->pMedium = aMedium;
545 m->bd->fImplicit = false;
546 m->fIsEjected = false;
547}
548
549/** Must be called from under this object's write lock. */
550void MediumAttachment::i_updatePassthrough(bool aPassthrough)
551{
552 Assert(isWriteLockOnCurrentThread());
553 Assert(!m->pMachine->i_isSnapshotMachine());
554
555 m->bd.backup();
556 m->bd->mData.fPassThrough = aPassthrough;
557}
558
559/** Must be called from under this object's write lock. */
560void MediumAttachment::i_updateTempEject(bool aTempEject)
561{
562 Assert(isWriteLockOnCurrentThread());
563 Assert(!m->pMachine->i_isSnapshotMachine());
564
565 m->bd.backup();
566 m->bd->mData.fTempEject = aTempEject;
567}
568
569/** Must be called from under this object's write lock. */
570void MediumAttachment::i_updateEjected()
571{
572 Assert(isWriteLockOnCurrentThread());
573 Assert(!m->pMachine->i_isSnapshotMachine());
574
575 m->fIsEjected = true;
576}
577
578/** Must be called from under this object's write lock. */
579void MediumAttachment::i_updateNonRotational(bool aNonRotational)
580{
581 Assert(isWriteLockOnCurrentThread());
582 Assert(!m->pMachine->i_isSnapshotMachine());
583
584 m->bd.backup();
585 m->bd->mData.fNonRotational = aNonRotational;
586}
587
588/** Must be called from under this object's write lock. */
589void MediumAttachment::i_updateDiscard(bool aDiscard)
590{
591 Assert(isWriteLockOnCurrentThread());
592 Assert(!m->pMachine->i_isSnapshotMachine());
593
594 m->bd.backup();
595 m->bd->mData.fDiscard = aDiscard;
596}
597
598/** Must be called from under this object's write lock. */
599void MediumAttachment::i_updateHotPluggable(bool aHotPluggable)
600{
601 Assert(isWriteLockOnCurrentThread());
602 Assert(!m->pMachine->i_isSnapshotMachine());
603
604 m->bd.backup();
605 m->bd->mData.fHotPluggable = aHotPluggable;
606}
607
608void MediumAttachment::i_updateBandwidthGroup(const Utf8Str &aBandwidthGroup)
609{
610 LogFlowThisFuncEnter();
611 Assert(isWriteLockOnCurrentThread());
612 Assert(!m->pMachine->i_isSnapshotMachine());
613
614 m->bd.backup();
615 m->bd->mData.strBwGroup = aBandwidthGroup;
616
617 LogFlowThisFuncLeave();
618}
619
620void MediumAttachment::i_updateParentMachine(Machine * const pMachine)
621{
622 LogFlowThisFunc(("ENTER - %s\n", i_getLogName()));
623 /* sanity */
624 AutoCaller autoCaller(this);
625 AssertComRCReturnVoid(autoCaller.rc());
626 Assert(!m->pMachine->i_isSnapshotMachine());
627
628 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
629
630 unconst(m->pMachine) = pMachine;
631
632 LogFlowThisFunc(("LEAVE - %s\n", i_getLogName()));
633}
634
635void MediumAttachment::i_updateLogName()
636{
637 const char *pszName = m->bd->strControllerName.c_str();
638 const char *pszEndNick = strpbrk(pszName, " \t:-");
639 mLogName = Utf8StrFmt("MA%p[%.*s:%u:%u:%s%s]",
640 this,
641 pszEndNick ? pszEndNick - pszName : 4, pszName,
642 m->bd->mData.lPort, m->bd->mData.lDevice, ::stringifyDeviceType(m->bd->mData.deviceType),
643 m->bd->fImplicit ? ":I" : "");
644}
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