VirtualBox

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

Last change on this file since 38869 was 38718, checked in by vboxsync, 13 years ago

Main: Fix wrong medium attachment references after "Restore Snapshot" by making a depth copy of them

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 14.8 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 fNonRotational(false),
44 fImplicit(false)
45 { }
46
47 ComObjPtr<Medium> pMedium;
48 /* Since MediumAttachment is not a first class citizen when it
49 * comes to managing settings, having a reference to the storage
50 * controller will not work - when settings are changed it will point
51 * to the old, uninitialized instance. Changing this requires
52 * substantial changes to MediumImpl.cpp. */
53 const Bstr bstrControllerName;
54 /* Same counts for the assigned bandwidth group */
55 Utf8Str strBandwidthGroup;
56 const LONG lPort;
57 const LONG lDevice;
58 const DeviceType_T type;
59 bool fPassthrough;
60 bool fTempEject;
61 bool fNonRotational;
62 bool fImplicit;
63};
64
65struct MediumAttachment::Data
66{
67 Data(Machine * const aMachine = NULL)
68 : pMachine(aMachine),
69 fIsEjected(false)
70 { }
71
72 /** Reference to Machine object, for checking mutable state. */
73 Machine * const pMachine;
74 /* later: const ComObjPtr<MediumAttachment> mPeer; */
75
76 bool fIsEjected;
77
78 Backupable<BackupableMediumAttachmentData> bd;
79};
80
81// constructor / destructor
82/////////////////////////////////////////////////////////////////////////////
83
84HRESULT MediumAttachment::FinalConstruct()
85{
86 LogFlowThisFunc(("\n"));
87 return BaseFinalConstruct();
88}
89
90void MediumAttachment::FinalRelease()
91{
92 LogFlowThisFuncEnter();
93 uninit();
94 BaseFinalRelease();
95 LogFlowThisFuncLeave();
96}
97
98// public initializer/uninitializer for internal purposes only
99/////////////////////////////////////////////////////////////////////////////
100
101/**
102 * Initializes the medium attachment object.
103 *
104 * @param aParent Machine object.
105 * @param aMedium Medium object.
106 * @param aController Controller the hard disk is attached to.
107 * @param aPort Port number.
108 * @param aDevice Device number on the port.
109 * @param aPassthrough Whether accesses are directly passed to the host drive.
110 * @param aBandwidthLimit Bandwidth limit in Mbps
111 */
112HRESULT MediumAttachment::init(Machine *aParent,
113 Medium *aMedium,
114 const Bstr &aControllerName,
115 LONG aPort,
116 LONG aDevice,
117 DeviceType_T aType,
118 bool aImplicit,
119 bool aPassthrough,
120 bool aTempEject,
121 bool aNonRotational,
122 const Utf8Str &strBandwidthGroup)
123{
124 LogFlowThisFuncEnter();
125 LogFlowThisFunc(("aParent=%p aMedium=%p aControllerName=%ls aPort=%d aDevice=%d aType=%d aImplicit=%d aPassthrough=%d aTempEject=%d aNonRotational=%d strBandwithGroup=%s\n", aParent, aMedium, aControllerName.raw(), aPort, aDevice, aType, aImplicit, aPassthrough, aTempEject, aNonRotational, strBandwidthGroup.c_str()));
126
127 if (aType == DeviceType_HardDisk)
128 AssertReturn(aMedium, E_INVALIDARG);
129
130 /* Enclose the state transition NotReady->InInit->Ready */
131 AutoInitSpan autoInitSpan(this);
132 AssertReturn(autoInitSpan.isOk(), E_FAIL);
133
134 m = new Data();
135
136 unconst(m->pMachine) = aParent;
137
138 m->bd.allocate();
139 m->bd->pMedium = aMedium;
140 unconst(m->bd->strBandwidthGroup) = strBandwidthGroup;
141 unconst(m->bd->bstrControllerName) = aControllerName;
142 unconst(m->bd->lPort) = aPort;
143 unconst(m->bd->lDevice) = aDevice;
144 unconst(m->bd->type) = aType;
145
146 m->bd->fPassthrough = aPassthrough;
147 m->bd->fTempEject = aTempEject;
148 m->bd->fNonRotational = aNonRotational;
149 m->bd->fImplicit = aImplicit;
150
151 /* Confirm a successful initialization when it's the case */
152 autoInitSpan.setSucceeded();
153
154 /* Construct a short log name for this attachment. */
155 Utf8Str ctlName(aControllerName);
156 const char *psz = strpbrk(ctlName.c_str(), " \t:-");
157 mLogName = Utf8StrFmt("MA%p[%.*s:%u:%u:%s%s]",
158 this,
159 psz ? psz - ctlName.c_str() : 4, ctlName.c_str(),
160 aPort, aDevice, Global::stringifyDeviceType(aType),
161 m->bd->fImplicit ? ":I" : "");
162
163 LogFlowThisFunc(("LEAVE - %s\n", getLogName()));
164 return S_OK;
165}
166
167/**
168 * Initializes the medium attachment object given another guest object
169 * (a kind of copy constructor). This object makes a private copy of data
170 * of the original object passed as an argument.
171 */
172HRESULT MediumAttachment::initCopy(Machine *aParent, MediumAttachment *aThat)
173{
174 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
175
176 ComAssertRet(aParent && aThat, E_INVALIDARG);
177
178 /* Enclose the state transition NotReady->InInit->Ready */
179 AutoInitSpan autoInitSpan(this);
180 AssertReturn(autoInitSpan.isOk(), E_FAIL);
181
182 m = new Data(aParent);
183 /* m->pPeer is left null */
184
185 AutoCaller thatCaller(aThat);
186 AssertComRCReturnRC(thatCaller.rc());
187
188 AutoReadLock thatlock(aThat COMMA_LOCKVAL_SRC_POS);
189 m->bd.attachCopy(aThat->m->bd);
190
191 /* Confirm a successful initialization */
192 autoInitSpan.setSucceeded();
193
194 return S_OK;
195}
196
197/**
198 * Uninitializes the instance.
199 * Called from FinalRelease().
200 */
201void MediumAttachment::uninit()
202{
203 LogFlowThisFunc(("ENTER - %s\n", getLogName()));
204
205 /* Enclose the state transition Ready->InUninit->NotReady */
206 AutoUninitSpan autoUninitSpan(this);
207 if (autoUninitSpan.uninitDone())
208 return;
209
210 m->bd.free();
211
212 unconst(m->pMachine) = NULL;
213
214 delete m;
215 m = NULL;
216
217 LogFlowThisFuncLeave();
218}
219
220// IHardDiskAttachment properties
221/////////////////////////////////////////////////////////////////////////////
222
223STDMETHODIMP MediumAttachment::COMGETTER(Medium)(IMedium **aHardDisk)
224{
225 LogFlowThisFuncEnter();
226
227 CheckComArgOutPointerValid(aHardDisk);
228
229 AutoCaller autoCaller(this);
230 if (FAILED(autoCaller.rc())) return autoCaller.rc();
231
232 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
233
234 m->bd->pMedium.queryInterfaceTo(aHardDisk);
235
236 LogFlowThisFuncLeave();
237 return S_OK;
238}
239
240STDMETHODIMP MediumAttachment::COMGETTER(Controller)(BSTR *aController)
241{
242 LogFlowThisFuncEnter();
243
244 CheckComArgOutPointerValid(aController);
245
246 AutoCaller autoCaller(this);
247 if (FAILED(autoCaller.rc())) return autoCaller.rc();
248
249 /* m->controller is constant during life time, no need to lock */
250 m->bd->bstrControllerName.cloneTo(aController);
251
252 LogFlowThisFuncLeave();
253 return S_OK;
254}
255
256STDMETHODIMP MediumAttachment::COMGETTER(Port)(LONG *aPort)
257{
258 LogFlowThisFuncEnter();
259
260 CheckComArgOutPointerValid(aPort);
261
262 AutoCaller autoCaller(this);
263 if (FAILED(autoCaller.rc())) return autoCaller.rc();
264
265 /* m->bd->port is constant during life time, no need to lock */
266 *aPort = m->bd->lPort;
267
268 LogFlowThisFuncLeave();
269 return S_OK;
270}
271
272STDMETHODIMP MediumAttachment::COMGETTER(Device)(LONG *aDevice)
273{
274 LogFlowThisFuncEnter();
275
276 CheckComArgOutPointerValid(aDevice);
277
278 AutoCaller autoCaller(this);
279 if (FAILED(autoCaller.rc())) return autoCaller.rc();
280
281 /* m->bd->device is constant during life time, no need to lock */
282 *aDevice = m->bd->lDevice;
283
284 LogFlowThisFuncLeave();
285 return S_OK;
286}
287
288STDMETHODIMP MediumAttachment::COMGETTER(Type)(DeviceType_T *aType)
289{
290 LogFlowThisFuncEnter();
291
292 CheckComArgOutPointerValid(aType);
293
294 AutoCaller autoCaller(this);
295 if (FAILED(autoCaller.rc())) return autoCaller.rc();
296
297 /* m->bd->type is constant during life time, no need to lock */
298 *aType = m->bd->type;
299
300 LogFlowThisFuncLeave();
301 return S_OK;
302}
303
304STDMETHODIMP MediumAttachment::COMGETTER(Passthrough)(BOOL *aPassthrough)
305{
306 LogFlowThisFuncEnter();
307
308 CheckComArgOutPointerValid(aPassthrough);
309
310 AutoCaller autoCaller(this);
311 if (FAILED(autoCaller.rc())) return autoCaller.rc();
312
313 AutoReadLock lock(this COMMA_LOCKVAL_SRC_POS);
314
315 *aPassthrough = m->bd->fPassthrough;
316
317 LogFlowThisFuncLeave();
318 return S_OK;
319}
320
321STDMETHODIMP MediumAttachment::COMGETTER(TemporaryEject)(BOOL *aTemporaryEject)
322{
323 LogFlowThisFuncEnter();
324
325 CheckComArgOutPointerValid(aTemporaryEject);
326
327 AutoCaller autoCaller(this);
328 if (FAILED(autoCaller.rc())) return autoCaller.rc();
329
330 AutoReadLock lock(this COMMA_LOCKVAL_SRC_POS);
331
332 *aTemporaryEject = m->bd->fTempEject;
333
334 LogFlowThisFuncLeave();
335 return S_OK;
336}
337
338STDMETHODIMP MediumAttachment::COMGETTER(IsEjected)(BOOL *aEjected)
339{
340 LogFlowThisFuncEnter();
341
342 CheckComArgOutPointerValid(aEjected);
343
344 AutoCaller autoCaller(this);
345 if (FAILED(autoCaller.rc())) return autoCaller.rc();
346
347 AutoReadLock lock(this COMMA_LOCKVAL_SRC_POS);
348
349 *aEjected = m->fIsEjected;
350
351 LogFlowThisFuncLeave();
352 return S_OK;
353}
354
355STDMETHODIMP MediumAttachment::COMGETTER(NonRotational)(BOOL *aNonRotational)
356{
357 LogFlowThisFuncEnter();
358
359 CheckComArgOutPointerValid(aNonRotational);
360
361 AutoCaller autoCaller(this);
362 if (FAILED(autoCaller.rc())) return autoCaller.rc();
363
364 AutoReadLock lock(this COMMA_LOCKVAL_SRC_POS);
365
366 *aNonRotational = m->bd->fNonRotational;
367
368 LogFlowThisFuncLeave();
369 return S_OK;
370}
371
372STDMETHODIMP MediumAttachment::COMGETTER(BandwidthGroup) (IBandwidthGroup **aBwGroup)
373{
374 LogFlowThisFuncEnter();
375 CheckComArgOutPointerValid(aBwGroup);
376
377 AutoCaller autoCaller(this);
378 if (FAILED(autoCaller.rc())) return autoCaller.rc();
379
380 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
381
382 HRESULT hrc = S_OK;
383 if (m->bd->strBandwidthGroup.isNotEmpty())
384 {
385 ComObjPtr<BandwidthGroup> pBwGroup;
386 hrc = m->pMachine->getBandwidthGroup(m->bd->strBandwidthGroup, pBwGroup, true /* fSetError */);
387
388 Assert(SUCCEEDED(hrc)); /* This is not allowed to fail because the existence of the group was checked when it was attached. */
389
390 if (SUCCEEDED(hrc))
391 pBwGroup.queryInterfaceTo(aBwGroup);
392 }
393
394 LogFlowThisFuncLeave();
395 return hrc;
396}
397
398/**
399 * @note Locks this object for writing.
400 */
401void MediumAttachment::rollback()
402{
403 LogFlowThisFunc(("ENTER - %s\n", getLogName()));
404
405 /* sanity */
406 AutoCaller autoCaller(this);
407 AssertComRCReturnVoid(autoCaller.rc());
408
409 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
410
411 m->bd.rollback();
412
413 LogFlowThisFunc(("LEAVE - %s\n", getLogName()));
414}
415
416/**
417 * @note Locks this object for writing.
418 */
419void MediumAttachment::commit()
420{
421 LogFlowThisFunc(("ENTER - %s\n", getLogName()));
422
423 /* sanity */
424 AutoCaller autoCaller(this);
425 AssertComRCReturnVoid (autoCaller.rc());
426
427 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
428
429 if (m->bd.isBackedUp())
430 m->bd.commit();
431
432 LogFlowThisFunc(("LEAVE - %s\n", getLogName()));
433}
434
435bool MediumAttachment::isImplicit() const
436{
437 return m->bd->fImplicit;
438}
439
440void MediumAttachment::setImplicit(bool aImplicit)
441{
442 m->bd->fImplicit = aImplicit;
443}
444
445const ComObjPtr<Medium>& MediumAttachment::getMedium() const
446{
447 return m->bd->pMedium;
448}
449
450Bstr MediumAttachment::getControllerName() const
451{
452 return m->bd->bstrControllerName;
453}
454
455LONG MediumAttachment::getPort() const
456{
457 return m->bd->lPort;
458}
459
460LONG MediumAttachment::getDevice() const
461{
462 return m->bd->lDevice;
463}
464
465DeviceType_T MediumAttachment::getType() const
466{
467 return m->bd->type;
468}
469
470bool MediumAttachment::getPassthrough() const
471{
472 AutoReadLock lock(this COMMA_LOCKVAL_SRC_POS);
473 return m->bd->fPassthrough;
474}
475
476bool MediumAttachment::getTempEject() const
477{
478 AutoReadLock lock(this COMMA_LOCKVAL_SRC_POS);
479 return m->bd->fTempEject;
480}
481
482bool MediumAttachment::getNonRotational() const
483{
484 AutoReadLock lock(this COMMA_LOCKVAL_SRC_POS);
485 return m->bd->fNonRotational;
486}
487
488const Utf8Str& MediumAttachment::getBandwidthGroup() const
489{
490 return m->bd->strBandwidthGroup;
491}
492
493bool MediumAttachment::matches(CBSTR aControllerName, LONG aPort, LONG aDevice)
494{
495 return ( aControllerName == m->bd->bstrControllerName
496 && aPort == m->bd->lPort
497 && aDevice == m->bd->lDevice);
498}
499
500/**
501 * Sets the medium of this attachment and unsets the "implicit" flag.
502 * @param aMedium
503 */
504void MediumAttachment::updateMedium(const ComObjPtr<Medium> &aMedium)
505{
506 Assert(isWriteLockOnCurrentThread());
507
508 m->bd.backup();
509 m->bd->pMedium = aMedium;
510 m->bd->fImplicit = false;
511 m->fIsEjected = false;
512}
513
514/** Must be called from under this object's write lock. */
515void MediumAttachment::updatePassthrough(bool aPassthrough)
516{
517 Assert(isWriteLockOnCurrentThread());
518
519 m->bd.backup();
520 m->bd->fPassthrough = aPassthrough;
521}
522
523/** Must be called from under this object's write lock. */
524void MediumAttachment::updateTempEject(bool aTempEject)
525{
526 Assert(isWriteLockOnCurrentThread());
527
528 m->bd.backup();
529 m->bd->fTempEject = aTempEject;
530}
531
532/** Must be called from under this object's write lock. */
533void MediumAttachment::updateEjected()
534{
535 Assert(isWriteLockOnCurrentThread());
536
537 m->fIsEjected = true;
538}
539
540/** Must be called from under this object's write lock. */
541void MediumAttachment::updateNonRotational(bool aNonRotational)
542{
543 Assert(isWriteLockOnCurrentThread());
544
545 m->bd.backup();
546 m->bd->fNonRotational = aNonRotational;
547}
548
549void MediumAttachment::updateBandwidthGroup(const Utf8Str &aBandwidthGroup)
550{
551 LogFlowThisFuncEnter();
552 Assert(isWriteLockOnCurrentThread());
553
554 m->bd.backup();
555 m->bd->strBandwidthGroup = aBandwidthGroup;
556
557 LogFlowThisFuncLeave();
558}
559
560void MediumAttachment::updateParentMachine(Machine * const pMachine)
561{
562 LogFlowThisFunc(("ENTER - %s\n", getLogName()));
563
564 /* sanity */
565 AutoCaller autoCaller(this);
566 AssertComRCReturnVoid (autoCaller.rc());
567
568 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
569
570 unconst(m->pMachine) = pMachine;
571
572 LogFlowThisFunc(("LEAVE - %s\n", getLogName()));
573}
574
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