VirtualBox

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

Last change on this file since 40257 was 38873, checked in by vboxsync, 13 years ago

Main: Add API to set the discard flag for harddisks

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