VirtualBox

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

Last change on this file since 36986 was 36181, checked in by vboxsync, 14 years ago

Main: Fix crashes when starting a VM with a bandwidth group caused by a stale parent machine pointer

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 11.5 KB
Line 
1/** @file
2 *
3 * VirtualBox COM class implementation
4 */
5
6/*
7 * Copyright (C) 2006-2009 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 fImplicit(false)
43 { }
44
45 ComObjPtr<Medium> pMedium;
46 /* Since MediumAttachment is not a first class citizen when it
47 * comes to managing settings, having a reference to the storage
48 * controller will not work - when settings are changed it will point
49 * to the old, uninitialized instance. Changing this requires
50 * substantial changes to MediumImpl.cpp. */
51 const Bstr bstrControllerName;
52 /* Same counts for the assigned bandwidth group */
53 Utf8Str strBandwidthGroup;
54 const LONG lPort;
55 const LONG lDevice;
56 const DeviceType_T type;
57 bool fPassthrough;
58 bool fImplicit;
59};
60
61struct MediumAttachment::Data
62{
63 Data()
64 : pMachine(NULL)
65 { }
66
67 /** Reference to Machine object, for checking mutable state. */
68 Machine * const pMachine;
69 /* later: const ComObjPtr<MediumAttachment> mPeer; */
70
71 Backupable<BackupableMediumAttachmentData> bd;
72};
73
74// constructor / destructor
75/////////////////////////////////////////////////////////////////////////////
76
77HRESULT MediumAttachment::FinalConstruct()
78{
79 LogFlowThisFunc(("\n"));
80 return BaseFinalConstruct();
81}
82
83void MediumAttachment::FinalRelease()
84{
85 LogFlowThisFuncEnter();
86 uninit();
87 BaseFinalRelease();
88 LogFlowThisFuncLeave();
89}
90
91// public initializer/uninitializer for internal purposes only
92/////////////////////////////////////////////////////////////////////////////
93
94/**
95 * Initializes the medium attachment object.
96 *
97 * @param aParent Machine object.
98 * @param aMedium Medium object.
99 * @param aController Controller the hard disk is attached to.
100 * @param aPort Port number.
101 * @param aDevice Device number on the port.
102 * @param aPassthrough Whether accesses are directly passed to the host drive.
103 * @param aBandwidthLimit Bandwidth limit in Mbps
104 */
105HRESULT MediumAttachment::init(Machine *aParent,
106 Medium *aMedium,
107 const Bstr &aControllerName,
108 LONG aPort,
109 LONG aDevice,
110 DeviceType_T aType,
111 bool aPassthrough,
112 const Utf8Str &strBandwidthGroup)
113{
114 LogFlowThisFuncEnter();
115 LogFlowThisFunc(("aParent=%p aMedium=%p aControllerName=%ls aPort=%d aDevice=%d aType=%d aPassthrough=%d\n", aParent, aMedium, aControllerName.raw(), aPort, aDevice, aType, aPassthrough));
116
117 if (aType == DeviceType_HardDisk)
118 AssertReturn(aMedium, E_INVALIDARG);
119
120 /* Enclose the state transition NotReady->InInit->Ready */
121 AutoInitSpan autoInitSpan(this);
122 AssertReturn(autoInitSpan.isOk(), E_FAIL);
123
124 m = new Data();
125
126 unconst(m->pMachine) = aParent;
127
128 m->bd.allocate();
129 m->bd->pMedium = aMedium;
130 unconst(m->bd->strBandwidthGroup) = strBandwidthGroup;
131 unconst(m->bd->bstrControllerName) = aControllerName;
132 unconst(m->bd->lPort) = aPort;
133 unconst(m->bd->lDevice) = aDevice;
134 unconst(m->bd->type) = aType;
135
136 m->bd->fPassthrough = aPassthrough;
137 /* Newly created attachments never have an implicitly created medium
138 * associated with them. Implicit diff image creation happens later. */
139 m->bd->fImplicit = false;
140
141 /* Confirm a successful initialization when it's the case */
142 autoInitSpan.setSucceeded();
143
144 /* Construct a short log name for this attachment. */
145 Utf8Str ctlName(aControllerName);
146 const char *psz = strpbrk(ctlName.c_str(), " \t:-");
147 mLogName = Utf8StrFmt("MA%p[%.*s:%u:%u:%s%s]",
148 this,
149 psz ? psz - ctlName.c_str() : 4, ctlName.c_str(),
150 aPort, aDevice, Global::stringifyDeviceType(aType),
151 m->bd->fImplicit ? ":I" : "");
152
153 LogFlowThisFunc(("LEAVE - %s\n", getLogName()));
154 return S_OK;
155}
156
157/**
158 * Uninitializes the instance.
159 * Called from FinalRelease().
160 */
161void MediumAttachment::uninit()
162{
163 LogFlowThisFunc(("ENTER - %s\n", getLogName()));
164
165 /* Enclose the state transition Ready->InUninit->NotReady */
166 AutoUninitSpan autoUninitSpan(this);
167 if (autoUninitSpan.uninitDone())
168 return;
169
170 m->bd.free();
171
172 unconst(m->pMachine) = NULL;
173
174 delete m;
175 m = NULL;
176
177 LogFlowThisFuncLeave();
178}
179
180// IHardDiskAttachment properties
181/////////////////////////////////////////////////////////////////////////////
182
183STDMETHODIMP MediumAttachment::COMGETTER(Medium)(IMedium **aHardDisk)
184{
185 LogFlowThisFuncEnter();
186
187 CheckComArgOutPointerValid(aHardDisk);
188
189 AutoCaller autoCaller(this);
190 if (FAILED(autoCaller.rc())) return autoCaller.rc();
191
192 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
193
194 m->bd->pMedium.queryInterfaceTo(aHardDisk);
195
196 LogFlowThisFuncLeave();
197 return S_OK;
198}
199
200STDMETHODIMP MediumAttachment::COMGETTER(Controller)(BSTR *aController)
201{
202 LogFlowThisFuncEnter();
203
204 CheckComArgOutPointerValid(aController);
205
206 AutoCaller autoCaller(this);
207 if (FAILED(autoCaller.rc())) return autoCaller.rc();
208
209 /* m->controller is constant during life time, no need to lock */
210 m->bd->bstrControllerName.cloneTo(aController);
211
212 LogFlowThisFuncLeave();
213 return S_OK;
214}
215
216STDMETHODIMP MediumAttachment::COMGETTER(Port)(LONG *aPort)
217{
218 LogFlowThisFuncEnter();
219
220 CheckComArgOutPointerValid(aPort);
221
222 AutoCaller autoCaller(this);
223 if (FAILED(autoCaller.rc())) return autoCaller.rc();
224
225 /* m->bd->port is constant during life time, no need to lock */
226 *aPort = m->bd->lPort;
227
228 LogFlowThisFuncLeave();
229 return S_OK;
230}
231
232STDMETHODIMP MediumAttachment::COMGETTER(Device)(LONG *aDevice)
233{
234 LogFlowThisFuncEnter();
235
236 CheckComArgOutPointerValid(aDevice);
237
238 AutoCaller autoCaller(this);
239 if (FAILED(autoCaller.rc())) return autoCaller.rc();
240
241 /* m->bd->device is constant during life time, no need to lock */
242 *aDevice = m->bd->lDevice;
243
244 LogFlowThisFuncLeave();
245 return S_OK;
246}
247
248STDMETHODIMP MediumAttachment::COMGETTER(Type)(DeviceType_T *aType)
249{
250 LogFlowThisFuncEnter();
251
252 CheckComArgOutPointerValid(aType);
253
254 AutoCaller autoCaller(this);
255 if (FAILED(autoCaller.rc())) return autoCaller.rc();
256
257 /* m->bd->type is constant during life time, no need to lock */
258 *aType = m->bd->type;
259
260 LogFlowThisFuncLeave();
261 return S_OK;
262}
263
264STDMETHODIMP MediumAttachment::COMGETTER(Passthrough)(BOOL *aPassthrough)
265{
266 LogFlowThisFuncEnter();
267
268 CheckComArgOutPointerValid(aPassthrough);
269
270 AutoCaller autoCaller(this);
271 if (FAILED(autoCaller.rc())) return autoCaller.rc();
272
273 AutoReadLock lock(this COMMA_LOCKVAL_SRC_POS);
274
275 *aPassthrough = m->bd->fPassthrough;
276
277 LogFlowThisFuncLeave();
278 return S_OK;
279}
280
281STDMETHODIMP MediumAttachment::COMGETTER(BandwidthGroup) (IBandwidthGroup **aBwGroup)
282{
283 LogFlowThisFuncEnter();
284 CheckComArgOutPointerValid(aBwGroup);
285
286 AutoCaller autoCaller(this);
287 if (FAILED(autoCaller.rc())) return autoCaller.rc();
288
289 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
290
291 HRESULT hrc = S_OK;
292 if (m->bd->strBandwidthGroup.isNotEmpty())
293 {
294 ComObjPtr<BandwidthGroup> pBwGroup;
295 hrc = m->pMachine->getBandwidthGroup(m->bd->strBandwidthGroup, pBwGroup, true /* fSetError */);
296
297 Assert(SUCCEEDED(hrc)); /* This is not allowed to fail because the existence of the group was checked when it was attached. */
298
299 if (SUCCEEDED(hrc))
300 pBwGroup.queryInterfaceTo(aBwGroup);
301 }
302
303 LogFlowThisFuncLeave();
304 return hrc;
305}
306
307/**
308 * @note Locks this object for writing.
309 */
310void MediumAttachment::rollback()
311{
312 LogFlowThisFunc(("ENTER - %s\n", getLogName()));
313
314 /* sanity */
315 AutoCaller autoCaller(this);
316 AssertComRCReturnVoid(autoCaller.rc());
317
318 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
319
320 m->bd.rollback();
321
322 LogFlowThisFunc(("LEAVE - %s\n", getLogName()));
323}
324
325/**
326 * @note Locks this object for writing.
327 */
328void MediumAttachment::commit()
329{
330 LogFlowThisFunc(("ENTER - %s\n", getLogName()));
331
332 /* sanity */
333 AutoCaller autoCaller(this);
334 AssertComRCReturnVoid (autoCaller.rc());
335
336 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
337
338 if (m->bd.isBackedUp())
339 m->bd.commit();
340
341 LogFlowThisFunc(("LEAVE - %s\n", getLogName()));
342}
343
344bool MediumAttachment::isImplicit() const
345{
346 return m->bd->fImplicit;
347}
348
349void MediumAttachment::setImplicit(bool aImplicit)
350{
351 m->bd->fImplicit = aImplicit;
352}
353
354const ComObjPtr<Medium>& MediumAttachment::getMedium() const
355{
356 return m->bd->pMedium;
357}
358
359Bstr MediumAttachment::getControllerName() const
360{
361 return m->bd->bstrControllerName;
362}
363
364LONG MediumAttachment::getPort() const
365{
366 return m->bd->lPort;
367}
368
369LONG MediumAttachment::getDevice() const
370{
371 return m->bd->lDevice;
372}
373
374DeviceType_T MediumAttachment::getType() const
375{
376 return m->bd->type;
377}
378
379bool MediumAttachment::getPassthrough() const
380{
381 AutoReadLock lock(this COMMA_LOCKVAL_SRC_POS);
382 return m->bd->fPassthrough;
383}
384
385const Utf8Str& MediumAttachment::getBandwidthGroup() const
386{
387 return m->bd->strBandwidthGroup;
388}
389
390bool MediumAttachment::matches(CBSTR aControllerName, LONG aPort, LONG aDevice)
391{
392 return ( aControllerName == m->bd->bstrControllerName
393 && aPort == m->bd->lPort
394 && aDevice == m->bd->lDevice);
395}
396
397/**
398 * Sets the medium of this attachment and unsets the "implicit" flag.
399 * @param aMedium
400 */
401void MediumAttachment::updateMedium(const ComObjPtr<Medium> &aMedium)
402{
403 Assert(isWriteLockOnCurrentThread());
404
405 m->bd.backup();
406 m->bd->pMedium = aMedium;
407 m->bd->fImplicit = false;
408}
409
410/** Must be called from under this object's write lock. */
411void MediumAttachment::updatePassthrough(bool aPassthrough)
412{
413 Assert(isWriteLockOnCurrentThread());
414
415 m->bd.backup();
416 m->bd->fPassthrough = aPassthrough;
417}
418
419void MediumAttachment::updateBandwidthGroup(const Utf8Str &aBandwidthGroup)
420{
421 LogFlowThisFuncEnter();
422 Assert(isWriteLockOnCurrentThread());
423
424 m->bd.backup();
425 m->bd->strBandwidthGroup = aBandwidthGroup;
426
427 LogFlowThisFuncLeave();
428}
429
430void MediumAttachment::updateParentMachine(Machine * const pMachine)
431{
432 LogFlowThisFunc(("ENTER - %s\n", getLogName()));
433
434 /* sanity */
435 AutoCaller autoCaller(this);
436 AssertComRCReturnVoid (autoCaller.rc());
437
438 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
439
440 unconst(m->pMachine) = pMachine;
441
442 LogFlowThisFunc(("LEAVE - %s\n", getLogName()));
443}
444
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