VirtualBox

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

Last change on this file since 37768 was 37709, checked in by vboxsync, 14 years ago

Main/MediumAttachment+Machine: add a setting which controls the guest-triggered medium eject behavior, fix handling "implicit" media, and corresponding VBoxManage and documentation updates

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 12.9 KB
Line 
1/** @file
2 *
3 * VirtualBox COM class implementation
4 */
5
6/*
7 * Copyright (C) 2006-2011 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include "MediumAttachmentImpl.h"
19#include "MachineImpl.h"
20#include "MediumImpl.h"
21#include "Global.h"
22
23#include "AutoStateDep.h"
24#include "AutoCaller.h"
25#include "Logging.h"
26
27#include <iprt/cpp/utils.h>
28
29////////////////////////////////////////////////////////////////////////////////
30//
31// private member data definition
32//
33////////////////////////////////////////////////////////////////////////////////
34
35struct BackupableMediumAttachmentData
36{
37 BackupableMediumAttachmentData()
38 : lPort(0),
39 lDevice(0),
40 type(DeviceType_Null),
41 fPassthrough(false),
42 fTempEject(false),
43 fImplicit(false)
44 { }
45
46 ComObjPtr<Medium> pMedium;
47 /* Since MediumAttachment is not a first class citizen when it
48 * comes to managing settings, having a reference to the storage
49 * controller will not work - when settings are changed it will point
50 * to the old, uninitialized instance. Changing this requires
51 * substantial changes to MediumImpl.cpp. */
52 const Bstr bstrControllerName;
53 /* Same counts for the assigned bandwidth group */
54 Utf8Str strBandwidthGroup;
55 const LONG lPort;
56 const LONG lDevice;
57 const DeviceType_T type;
58 bool fPassthrough;
59 bool fTempEject;
60 bool fImplicit;
61};
62
63struct MediumAttachment::Data
64{
65 Data()
66 : pMachine(NULL),
67 fIsEjected(false)
68 { }
69
70 /** Reference to Machine object, for checking mutable state. */
71 Machine * const pMachine;
72 /* later: const ComObjPtr<MediumAttachment> mPeer; */
73
74 bool fIsEjected;
75
76 Backupable<BackupableMediumAttachmentData> bd;
77};
78
79// constructor / destructor
80/////////////////////////////////////////////////////////////////////////////
81
82HRESULT MediumAttachment::FinalConstruct()
83{
84 LogFlowThisFunc(("\n"));
85 return BaseFinalConstruct();
86}
87
88void MediumAttachment::FinalRelease()
89{
90 LogFlowThisFuncEnter();
91 uninit();
92 BaseFinalRelease();
93 LogFlowThisFuncLeave();
94}
95
96// public initializer/uninitializer for internal purposes only
97/////////////////////////////////////////////////////////////////////////////
98
99/**
100 * Initializes the medium attachment object.
101 *
102 * @param aParent Machine object.
103 * @param aMedium Medium object.
104 * @param aController Controller the hard disk is attached to.
105 * @param aPort Port number.
106 * @param aDevice Device number on the port.
107 * @param aPassthrough Whether accesses are directly passed to the host drive.
108 * @param aBandwidthLimit Bandwidth limit in Mbps
109 */
110HRESULT MediumAttachment::init(Machine *aParent,
111 Medium *aMedium,
112 const Bstr &aControllerName,
113 LONG aPort,
114 LONG aDevice,
115 DeviceType_T aType,
116 bool aImplicit,
117 bool aPassthrough,
118 bool aTempEject,
119 const Utf8Str &strBandwidthGroup)
120{
121 LogFlowThisFuncEnter();
122 LogFlowThisFunc(("aParent=%p aMedium=%p aControllerName=%ls aPort=%d aDevice=%d aType=%d aImplicit=%d aPassthrough=%d aTempEject=%d\n", aParent, aMedium, aControllerName.raw(), aPort, aDevice, aType, aImplicit, aPassthrough, aTempEject));
123
124 if (aType == DeviceType_HardDisk)
125 AssertReturn(aMedium, E_INVALIDARG);
126
127 /* Enclose the state transition NotReady->InInit->Ready */
128 AutoInitSpan autoInitSpan(this);
129 AssertReturn(autoInitSpan.isOk(), E_FAIL);
130
131 m = new Data();
132
133 unconst(m->pMachine) = aParent;
134
135 m->bd.allocate();
136 m->bd->pMedium = aMedium;
137 unconst(m->bd->strBandwidthGroup) = strBandwidthGroup;
138 unconst(m->bd->bstrControllerName) = aControllerName;
139 unconst(m->bd->lPort) = aPort;
140 unconst(m->bd->lDevice) = aDevice;
141 unconst(m->bd->type) = aType;
142
143 m->bd->fPassthrough = aPassthrough;
144 m->bd->fTempEject = aTempEject;
145 m->bd->fImplicit = aImplicit;
146
147 /* Confirm a successful initialization when it's the case */
148 autoInitSpan.setSucceeded();
149
150 /* Construct a short log name for this attachment. */
151 Utf8Str ctlName(aControllerName);
152 const char *psz = strpbrk(ctlName.c_str(), " \t:-");
153 mLogName = Utf8StrFmt("MA%p[%.*s:%u:%u:%s%s]",
154 this,
155 psz ? psz - ctlName.c_str() : 4, ctlName.c_str(),
156 aPort, aDevice, Global::stringifyDeviceType(aType),
157 m->bd->fImplicit ? ":I" : "");
158
159 LogFlowThisFunc(("LEAVE - %s\n", getLogName()));
160 return S_OK;
161}
162
163/**
164 * Uninitializes the instance.
165 * Called from FinalRelease().
166 */
167void MediumAttachment::uninit()
168{
169 LogFlowThisFunc(("ENTER - %s\n", getLogName()));
170
171 /* Enclose the state transition Ready->InUninit->NotReady */
172 AutoUninitSpan autoUninitSpan(this);
173 if (autoUninitSpan.uninitDone())
174 return;
175
176 m->bd.free();
177
178 unconst(m->pMachine) = NULL;
179
180 delete m;
181 m = NULL;
182
183 LogFlowThisFuncLeave();
184}
185
186// IHardDiskAttachment properties
187/////////////////////////////////////////////////////////////////////////////
188
189STDMETHODIMP MediumAttachment::COMGETTER(Medium)(IMedium **aHardDisk)
190{
191 LogFlowThisFuncEnter();
192
193 CheckComArgOutPointerValid(aHardDisk);
194
195 AutoCaller autoCaller(this);
196 if (FAILED(autoCaller.rc())) return autoCaller.rc();
197
198 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
199
200 m->bd->pMedium.queryInterfaceTo(aHardDisk);
201
202 LogFlowThisFuncLeave();
203 return S_OK;
204}
205
206STDMETHODIMP MediumAttachment::COMGETTER(Controller)(BSTR *aController)
207{
208 LogFlowThisFuncEnter();
209
210 CheckComArgOutPointerValid(aController);
211
212 AutoCaller autoCaller(this);
213 if (FAILED(autoCaller.rc())) return autoCaller.rc();
214
215 /* m->controller is constant during life time, no need to lock */
216 m->bd->bstrControllerName.cloneTo(aController);
217
218 LogFlowThisFuncLeave();
219 return S_OK;
220}
221
222STDMETHODIMP MediumAttachment::COMGETTER(Port)(LONG *aPort)
223{
224 LogFlowThisFuncEnter();
225
226 CheckComArgOutPointerValid(aPort);
227
228 AutoCaller autoCaller(this);
229 if (FAILED(autoCaller.rc())) return autoCaller.rc();
230
231 /* m->bd->port is constant during life time, no need to lock */
232 *aPort = m->bd->lPort;
233
234 LogFlowThisFuncLeave();
235 return S_OK;
236}
237
238STDMETHODIMP MediumAttachment::COMGETTER(Device)(LONG *aDevice)
239{
240 LogFlowThisFuncEnter();
241
242 CheckComArgOutPointerValid(aDevice);
243
244 AutoCaller autoCaller(this);
245 if (FAILED(autoCaller.rc())) return autoCaller.rc();
246
247 /* m->bd->device is constant during life time, no need to lock */
248 *aDevice = m->bd->lDevice;
249
250 LogFlowThisFuncLeave();
251 return S_OK;
252}
253
254STDMETHODIMP MediumAttachment::COMGETTER(Type)(DeviceType_T *aType)
255{
256 LogFlowThisFuncEnter();
257
258 CheckComArgOutPointerValid(aType);
259
260 AutoCaller autoCaller(this);
261 if (FAILED(autoCaller.rc())) return autoCaller.rc();
262
263 /* m->bd->type is constant during life time, no need to lock */
264 *aType = m->bd->type;
265
266 LogFlowThisFuncLeave();
267 return S_OK;
268}
269
270STDMETHODIMP MediumAttachment::COMGETTER(Passthrough)(BOOL *aPassthrough)
271{
272 LogFlowThisFuncEnter();
273
274 CheckComArgOutPointerValid(aPassthrough);
275
276 AutoCaller autoCaller(this);
277 if (FAILED(autoCaller.rc())) return autoCaller.rc();
278
279 AutoReadLock lock(this COMMA_LOCKVAL_SRC_POS);
280
281 *aPassthrough = m->bd->fPassthrough;
282
283 LogFlowThisFuncLeave();
284 return S_OK;
285}
286
287STDMETHODIMP MediumAttachment::COMGETTER(TemporaryEject)(BOOL *aTemporaryEject)
288{
289 LogFlowThisFuncEnter();
290
291 CheckComArgOutPointerValid(aTemporaryEject);
292
293 AutoCaller autoCaller(this);
294 if (FAILED(autoCaller.rc())) return autoCaller.rc();
295
296 AutoReadLock lock(this COMMA_LOCKVAL_SRC_POS);
297
298 *aTemporaryEject = m->bd->fTempEject;
299
300 LogFlowThisFuncLeave();
301 return S_OK;
302}
303
304STDMETHODIMP MediumAttachment::COMGETTER(IsEjected)(BOOL *aEjected)
305{
306 LogFlowThisFuncEnter();
307
308 CheckComArgOutPointerValid(aEjected);
309
310 AutoCaller autoCaller(this);
311 if (FAILED(autoCaller.rc())) return autoCaller.rc();
312
313 AutoReadLock lock(this COMMA_LOCKVAL_SRC_POS);
314
315 *aEjected = m->fIsEjected;
316
317 LogFlowThisFuncLeave();
318 return S_OK;
319}
320
321STDMETHODIMP MediumAttachment::COMGETTER(BandwidthGroup) (IBandwidthGroup **aBwGroup)
322{
323 LogFlowThisFuncEnter();
324 CheckComArgOutPointerValid(aBwGroup);
325
326 AutoCaller autoCaller(this);
327 if (FAILED(autoCaller.rc())) return autoCaller.rc();
328
329 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
330
331 HRESULT hrc = S_OK;
332 if (m->bd->strBandwidthGroup.isNotEmpty())
333 {
334 ComObjPtr<BandwidthGroup> pBwGroup;
335 hrc = m->pMachine->getBandwidthGroup(m->bd->strBandwidthGroup, pBwGroup, true /* fSetError */);
336
337 Assert(SUCCEEDED(hrc)); /* This is not allowed to fail because the existence of the group was checked when it was attached. */
338
339 if (SUCCEEDED(hrc))
340 pBwGroup.queryInterfaceTo(aBwGroup);
341 }
342
343 LogFlowThisFuncLeave();
344 return hrc;
345}
346
347/**
348 * @note Locks this object for writing.
349 */
350void MediumAttachment::rollback()
351{
352 LogFlowThisFunc(("ENTER - %s\n", getLogName()));
353
354 /* sanity */
355 AutoCaller autoCaller(this);
356 AssertComRCReturnVoid(autoCaller.rc());
357
358 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
359
360 m->bd.rollback();
361
362 LogFlowThisFunc(("LEAVE - %s\n", getLogName()));
363}
364
365/**
366 * @note Locks this object for writing.
367 */
368void MediumAttachment::commit()
369{
370 LogFlowThisFunc(("ENTER - %s\n", getLogName()));
371
372 /* sanity */
373 AutoCaller autoCaller(this);
374 AssertComRCReturnVoid (autoCaller.rc());
375
376 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
377
378 if (m->bd.isBackedUp())
379 m->bd.commit();
380
381 LogFlowThisFunc(("LEAVE - %s\n", getLogName()));
382}
383
384bool MediumAttachment::isImplicit() const
385{
386 return m->bd->fImplicit;
387}
388
389void MediumAttachment::setImplicit(bool aImplicit)
390{
391 m->bd->fImplicit = aImplicit;
392}
393
394const ComObjPtr<Medium>& MediumAttachment::getMedium() const
395{
396 return m->bd->pMedium;
397}
398
399Bstr MediumAttachment::getControllerName() const
400{
401 return m->bd->bstrControllerName;
402}
403
404LONG MediumAttachment::getPort() const
405{
406 return m->bd->lPort;
407}
408
409LONG MediumAttachment::getDevice() const
410{
411 return m->bd->lDevice;
412}
413
414DeviceType_T MediumAttachment::getType() const
415{
416 return m->bd->type;
417}
418
419bool MediumAttachment::getPassthrough() const
420{
421 AutoReadLock lock(this COMMA_LOCKVAL_SRC_POS);
422 return m->bd->fPassthrough;
423}
424
425bool MediumAttachment::getTempEject() const
426{
427 AutoReadLock lock(this COMMA_LOCKVAL_SRC_POS);
428 return m->bd->fTempEject;
429}
430
431const Utf8Str& MediumAttachment::getBandwidthGroup() const
432{
433 return m->bd->strBandwidthGroup;
434}
435
436bool MediumAttachment::matches(CBSTR aControllerName, LONG aPort, LONG aDevice)
437{
438 return ( aControllerName == m->bd->bstrControllerName
439 && aPort == m->bd->lPort
440 && aDevice == m->bd->lDevice);
441}
442
443/**
444 * Sets the medium of this attachment and unsets the "implicit" flag.
445 * @param aMedium
446 */
447void MediumAttachment::updateMedium(const ComObjPtr<Medium> &aMedium)
448{
449 Assert(isWriteLockOnCurrentThread());
450
451 m->bd.backup();
452 m->bd->pMedium = aMedium;
453 m->bd->fImplicit = false;
454 m->fIsEjected = false;
455}
456
457/** Must be called from under this object's write lock. */
458void MediumAttachment::updatePassthrough(bool aPassthrough)
459{
460 Assert(isWriteLockOnCurrentThread());
461
462 m->bd.backup();
463 m->bd->fPassthrough = aPassthrough;
464}
465
466/** Must be called from under this object's write lock. */
467void MediumAttachment::updateTempEject(bool aTempEject)
468{
469 Assert(isWriteLockOnCurrentThread());
470
471 m->bd.backup();
472 m->bd->fTempEject = aTempEject;
473}
474
475/** Must be called from under this object's write lock. */
476void MediumAttachment::updateEjected()
477{
478 Assert(isWriteLockOnCurrentThread());
479
480 m->fIsEjected = true;
481}
482
483void MediumAttachment::updateBandwidthGroup(const Utf8Str &aBandwidthGroup)
484{
485 LogFlowThisFuncEnter();
486 Assert(isWriteLockOnCurrentThread());
487
488 m->bd.backup();
489 m->bd->strBandwidthGroup = aBandwidthGroup;
490
491 LogFlowThisFuncLeave();
492}
493
494void MediumAttachment::updateParentMachine(Machine * const pMachine)
495{
496 LogFlowThisFunc(("ENTER - %s\n", getLogName()));
497
498 /* sanity */
499 AutoCaller autoCaller(this);
500 AssertComRCReturnVoid (autoCaller.rc());
501
502 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
503
504 unconst(m->pMachine) = pMachine;
505
506 LogFlowThisFunc(("LEAVE - %s\n", getLogName()));
507}
508
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette