VirtualBox

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

Last change on this file since 37952 was 37824, checked in by vboxsync, 13 years ago

Main/Machine+MediumAttachment+Console: add method for marking a 'hard disk' as non-rotational, which optimizes performance in modern guest OSes
Frontends/VBoxManage+VirtualBox: support the new method
ChangeLog: add quite a few forgotten improvements and fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 13.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 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()
68 : pMachine(NULL),
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 * Uninitializes the instance.
169 * Called from FinalRelease().
170 */
171void MediumAttachment::uninit()
172{
173 LogFlowThisFunc(("ENTER - %s\n", getLogName()));
174
175 /* Enclose the state transition Ready->InUninit->NotReady */
176 AutoUninitSpan autoUninitSpan(this);
177 if (autoUninitSpan.uninitDone())
178 return;
179
180 m->bd.free();
181
182 unconst(m->pMachine) = NULL;
183
184 delete m;
185 m = NULL;
186
187 LogFlowThisFuncLeave();
188}
189
190// IHardDiskAttachment properties
191/////////////////////////////////////////////////////////////////////////////
192
193STDMETHODIMP MediumAttachment::COMGETTER(Medium)(IMedium **aHardDisk)
194{
195 LogFlowThisFuncEnter();
196
197 CheckComArgOutPointerValid(aHardDisk);
198
199 AutoCaller autoCaller(this);
200 if (FAILED(autoCaller.rc())) return autoCaller.rc();
201
202 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
203
204 m->bd->pMedium.queryInterfaceTo(aHardDisk);
205
206 LogFlowThisFuncLeave();
207 return S_OK;
208}
209
210STDMETHODIMP MediumAttachment::COMGETTER(Controller)(BSTR *aController)
211{
212 LogFlowThisFuncEnter();
213
214 CheckComArgOutPointerValid(aController);
215
216 AutoCaller autoCaller(this);
217 if (FAILED(autoCaller.rc())) return autoCaller.rc();
218
219 /* m->controller is constant during life time, no need to lock */
220 m->bd->bstrControllerName.cloneTo(aController);
221
222 LogFlowThisFuncLeave();
223 return S_OK;
224}
225
226STDMETHODIMP MediumAttachment::COMGETTER(Port)(LONG *aPort)
227{
228 LogFlowThisFuncEnter();
229
230 CheckComArgOutPointerValid(aPort);
231
232 AutoCaller autoCaller(this);
233 if (FAILED(autoCaller.rc())) return autoCaller.rc();
234
235 /* m->bd->port is constant during life time, no need to lock */
236 *aPort = m->bd->lPort;
237
238 LogFlowThisFuncLeave();
239 return S_OK;
240}
241
242STDMETHODIMP MediumAttachment::COMGETTER(Device)(LONG *aDevice)
243{
244 LogFlowThisFuncEnter();
245
246 CheckComArgOutPointerValid(aDevice);
247
248 AutoCaller autoCaller(this);
249 if (FAILED(autoCaller.rc())) return autoCaller.rc();
250
251 /* m->bd->device is constant during life time, no need to lock */
252 *aDevice = m->bd->lDevice;
253
254 LogFlowThisFuncLeave();
255 return S_OK;
256}
257
258STDMETHODIMP MediumAttachment::COMGETTER(Type)(DeviceType_T *aType)
259{
260 LogFlowThisFuncEnter();
261
262 CheckComArgOutPointerValid(aType);
263
264 AutoCaller autoCaller(this);
265 if (FAILED(autoCaller.rc())) return autoCaller.rc();
266
267 /* m->bd->type is constant during life time, no need to lock */
268 *aType = m->bd->type;
269
270 LogFlowThisFuncLeave();
271 return S_OK;
272}
273
274STDMETHODIMP MediumAttachment::COMGETTER(Passthrough)(BOOL *aPassthrough)
275{
276 LogFlowThisFuncEnter();
277
278 CheckComArgOutPointerValid(aPassthrough);
279
280 AutoCaller autoCaller(this);
281 if (FAILED(autoCaller.rc())) return autoCaller.rc();
282
283 AutoReadLock lock(this COMMA_LOCKVAL_SRC_POS);
284
285 *aPassthrough = m->bd->fPassthrough;
286
287 LogFlowThisFuncLeave();
288 return S_OK;
289}
290
291STDMETHODIMP MediumAttachment::COMGETTER(TemporaryEject)(BOOL *aTemporaryEject)
292{
293 LogFlowThisFuncEnter();
294
295 CheckComArgOutPointerValid(aTemporaryEject);
296
297 AutoCaller autoCaller(this);
298 if (FAILED(autoCaller.rc())) return autoCaller.rc();
299
300 AutoReadLock lock(this COMMA_LOCKVAL_SRC_POS);
301
302 *aTemporaryEject = m->bd->fTempEject;
303
304 LogFlowThisFuncLeave();
305 return S_OK;
306}
307
308STDMETHODIMP MediumAttachment::COMGETTER(IsEjected)(BOOL *aEjected)
309{
310 LogFlowThisFuncEnter();
311
312 CheckComArgOutPointerValid(aEjected);
313
314 AutoCaller autoCaller(this);
315 if (FAILED(autoCaller.rc())) return autoCaller.rc();
316
317 AutoReadLock lock(this COMMA_LOCKVAL_SRC_POS);
318
319 *aEjected = m->fIsEjected;
320
321 LogFlowThisFuncLeave();
322 return S_OK;
323}
324
325STDMETHODIMP MediumAttachment::COMGETTER(NonRotational)(BOOL *aNonRotational)
326{
327 LogFlowThisFuncEnter();
328
329 CheckComArgOutPointerValid(aNonRotational);
330
331 AutoCaller autoCaller(this);
332 if (FAILED(autoCaller.rc())) return autoCaller.rc();
333
334 AutoReadLock lock(this COMMA_LOCKVAL_SRC_POS);
335
336 *aNonRotational = m->bd->fNonRotational;
337
338 LogFlowThisFuncLeave();
339 return S_OK;
340}
341
342STDMETHODIMP MediumAttachment::COMGETTER(BandwidthGroup) (IBandwidthGroup **aBwGroup)
343{
344 LogFlowThisFuncEnter();
345 CheckComArgOutPointerValid(aBwGroup);
346
347 AutoCaller autoCaller(this);
348 if (FAILED(autoCaller.rc())) return autoCaller.rc();
349
350 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
351
352 HRESULT hrc = S_OK;
353 if (m->bd->strBandwidthGroup.isNotEmpty())
354 {
355 ComObjPtr<BandwidthGroup> pBwGroup;
356 hrc = m->pMachine->getBandwidthGroup(m->bd->strBandwidthGroup, pBwGroup, true /* fSetError */);
357
358 Assert(SUCCEEDED(hrc)); /* This is not allowed to fail because the existence of the group was checked when it was attached. */
359
360 if (SUCCEEDED(hrc))
361 pBwGroup.queryInterfaceTo(aBwGroup);
362 }
363
364 LogFlowThisFuncLeave();
365 return hrc;
366}
367
368/**
369 * @note Locks this object for writing.
370 */
371void MediumAttachment::rollback()
372{
373 LogFlowThisFunc(("ENTER - %s\n", getLogName()));
374
375 /* sanity */
376 AutoCaller autoCaller(this);
377 AssertComRCReturnVoid(autoCaller.rc());
378
379 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
380
381 m->bd.rollback();
382
383 LogFlowThisFunc(("LEAVE - %s\n", getLogName()));
384}
385
386/**
387 * @note Locks this object for writing.
388 */
389void MediumAttachment::commit()
390{
391 LogFlowThisFunc(("ENTER - %s\n", getLogName()));
392
393 /* sanity */
394 AutoCaller autoCaller(this);
395 AssertComRCReturnVoid (autoCaller.rc());
396
397 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
398
399 if (m->bd.isBackedUp())
400 m->bd.commit();
401
402 LogFlowThisFunc(("LEAVE - %s\n", getLogName()));
403}
404
405bool MediumAttachment::isImplicit() const
406{
407 return m->bd->fImplicit;
408}
409
410void MediumAttachment::setImplicit(bool aImplicit)
411{
412 m->bd->fImplicit = aImplicit;
413}
414
415const ComObjPtr<Medium>& MediumAttachment::getMedium() const
416{
417 return m->bd->pMedium;
418}
419
420Bstr MediumAttachment::getControllerName() const
421{
422 return m->bd->bstrControllerName;
423}
424
425LONG MediumAttachment::getPort() const
426{
427 return m->bd->lPort;
428}
429
430LONG MediumAttachment::getDevice() const
431{
432 return m->bd->lDevice;
433}
434
435DeviceType_T MediumAttachment::getType() const
436{
437 return m->bd->type;
438}
439
440bool MediumAttachment::getPassthrough() const
441{
442 AutoReadLock lock(this COMMA_LOCKVAL_SRC_POS);
443 return m->bd->fPassthrough;
444}
445
446bool MediumAttachment::getTempEject() const
447{
448 AutoReadLock lock(this COMMA_LOCKVAL_SRC_POS);
449 return m->bd->fTempEject;
450}
451
452bool MediumAttachment::getNonRotational() const
453{
454 AutoReadLock lock(this COMMA_LOCKVAL_SRC_POS);
455 return m->bd->fNonRotational;
456}
457
458const Utf8Str& MediumAttachment::getBandwidthGroup() const
459{
460 return m->bd->strBandwidthGroup;
461}
462
463bool MediumAttachment::matches(CBSTR aControllerName, LONG aPort, LONG aDevice)
464{
465 return ( aControllerName == m->bd->bstrControllerName
466 && aPort == m->bd->lPort
467 && aDevice == m->bd->lDevice);
468}
469
470/**
471 * Sets the medium of this attachment and unsets the "implicit" flag.
472 * @param aMedium
473 */
474void MediumAttachment::updateMedium(const ComObjPtr<Medium> &aMedium)
475{
476 Assert(isWriteLockOnCurrentThread());
477
478 m->bd.backup();
479 m->bd->pMedium = aMedium;
480 m->bd->fImplicit = false;
481 m->fIsEjected = false;
482}
483
484/** Must be called from under this object's write lock. */
485void MediumAttachment::updatePassthrough(bool aPassthrough)
486{
487 Assert(isWriteLockOnCurrentThread());
488
489 m->bd.backup();
490 m->bd->fPassthrough = aPassthrough;
491}
492
493/** Must be called from under this object's write lock. */
494void MediumAttachment::updateTempEject(bool aTempEject)
495{
496 Assert(isWriteLockOnCurrentThread());
497
498 m->bd.backup();
499 m->bd->fTempEject = aTempEject;
500}
501
502/** Must be called from under this object's write lock. */
503void MediumAttachment::updateEjected()
504{
505 Assert(isWriteLockOnCurrentThread());
506
507 m->fIsEjected = true;
508}
509
510/** Must be called from under this object's write lock. */
511void MediumAttachment::updateNonRotational(bool aNonRotational)
512{
513 Assert(isWriteLockOnCurrentThread());
514
515 m->bd.backup();
516 m->bd->fNonRotational = aNonRotational;
517}
518
519void MediumAttachment::updateBandwidthGroup(const Utf8Str &aBandwidthGroup)
520{
521 LogFlowThisFuncEnter();
522 Assert(isWriteLockOnCurrentThread());
523
524 m->bd.backup();
525 m->bd->strBandwidthGroup = aBandwidthGroup;
526
527 LogFlowThisFuncLeave();
528}
529
530void MediumAttachment::updateParentMachine(Machine * const pMachine)
531{
532 LogFlowThisFunc(("ENTER - %s\n", getLogName()));
533
534 /* sanity */
535 AutoCaller autoCaller(this);
536 AssertComRCReturnVoid (autoCaller.rc());
537
538 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
539
540 unconst(m->pMachine) = pMachine;
541
542 LogFlowThisFunc(("LEAVE - %s\n", getLogName()));
543}
544
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