VirtualBox

source: vbox/trunk/src/VBox/Main/MediumAttachmentImpl.cpp@ 34645

Last change on this file since 34645 was 34587, checked in by vboxsync, 14 years ago

Main: Bandwidth groups for disks (and later network)

This introduces two new interfaces. The first one named IBandwidthGroup
represents one I/O limit and can be assigned to several mediums which
share this limit (which works only for harddisk images with the disabled
host cache).
The second one IBandwdithControl manages the groups and can create new ones
and destroy them if not required anymore.

VBoxManage: commands to access the bandwidth groups

Syntax:
VBoxManage storageattach <uuid|vmname>

...
--bandwidthgroup <name>

--bandwidthgroup assigns the specified device to the given group.

VBoxManage bandwidthctl <uuid|vmname>

--name <name>
--add disk|network
--limit <megabytes per second>
--delete

The --name parameter gives the name of the bandwidth group.
--add creates a new group of the given type (only disk is implemented so far)

with the given name.

--limit sets the limit to the given amount of MB/s

Note that limit can be changed while the VM is running. The VM
will immediately pick up the new limit for the given group name.

--delete deletes the group with the given name if it isn't used anymore.

Trying to delete a still used group will result in an error.

Example:

VBoxManage bandwidthctl "Test VM" --name Limit --add disk --limit 20
Creates a group named Test having a 20 MB/s limit.

VBoxManage storageattach "Test VM" --storagectl "SATA Controller" --port 0 --device 0 --type hdd --medium test.vdi --bandwidthgroup Limit
Adds a new disk to the SATA controller and assigns the bandwidth group Limit to it.

VBoxManage storageattach "Test VM" --storagectl "SATA Controller" --port 0 --device 0 --type hdd --medium test.vdi --bandwidthgroup none
Removes the bandwidth limit from the disk.

VBoxManage bandwidthctl "Test VM" --name Limit --add disk --limit 10
Changes the limit of bandwidth group Limit to 10 MB/s. If the VM is running the limit will be picked up
immediately.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 10.7 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 "BandwidthGroupImpl.h"
22#include "Global.h"
23
24#include "AutoStateDep.h"
25#include "AutoCaller.h"
26#include "Logging.h"
27
28#include <iprt/cpp/utils.h>
29
30////////////////////////////////////////////////////////////////////////////////
31//
32// private member data definition
33//
34////////////////////////////////////////////////////////////////////////////////
35
36struct BackupableMediumAttachmentData
37{
38 BackupableMediumAttachmentData()
39 : lPort(0),
40 lDevice(0),
41 type(DeviceType_Null),
42 fPassthrough(false),
43 fImplicit(false)
44 { }
45
46 ComObjPtr<Medium> pMedium;
47 ComObjPtr<BandwidthGroup> pBwGroup;
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 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 S_OK;
81}
82
83void MediumAttachment::FinalRelease()
84{
85 LogFlowThisFuncEnter();
86 uninit();
87 LogFlowThisFuncLeave();
88}
89
90// public initializer/uninitializer for internal purposes only
91/////////////////////////////////////////////////////////////////////////////
92
93/**
94 * Initializes the medium attachment object.
95 *
96 * @param aParent Machine object.
97 * @param aMedium Medium object.
98 * @param aController Controller the hard disk is attached to.
99 * @param aPort Port number.
100 * @param aDevice Device number on the port.
101 * @param aPassthrough Whether accesses are directly passed to the host drive.
102 * @param aBandwidthLimit Bandwidth limit in Mbps
103 */
104HRESULT MediumAttachment::init(Machine *aParent,
105 Medium *aMedium,
106 const Bstr &aControllerName,
107 LONG aPort,
108 LONG aDevice,
109 DeviceType_T aType,
110 bool aPassthrough,
111 BandwidthGroup *aBandwidthGroup)
112{
113 LogFlowThisFuncEnter();
114 LogFlowThisFunc(("aParent=%p aMedium=%p aControllerName=%ls aPort=%d aDevice=%d aType=%d aPassthrough=%d\n", aParent, aMedium, aControllerName.raw(), aPort, aDevice, aType, aPassthrough));
115
116 if (aType == DeviceType_HardDisk)
117 AssertReturn(aMedium, E_INVALIDARG);
118
119 /* Enclose the state transition NotReady->InInit->Ready */
120 AutoInitSpan autoInitSpan(this);
121 AssertReturn(autoInitSpan.isOk(), E_FAIL);
122
123 m = new Data();
124
125 unconst(m->pMachine) = aParent;
126
127 m->bd.allocate();
128 m->bd->pMedium = aMedium;
129 if (aBandwidthGroup)
130 aBandwidthGroup->reference();
131 m->bd->pBwGroup = aBandwidthGroup;
132 unconst(m->bd->bstrControllerName) = aControllerName;
133 unconst(m->bd->lPort) = aPort;
134 unconst(m->bd->lDevice) = aDevice;
135 unconst(m->bd->type) = aType;
136
137 m->bd->fPassthrough = aPassthrough;
138 /* Newly created attachments never have an implicitly created medium
139 * associated with them. Implicit diff image creation happens later. */
140 m->bd->fImplicit = false;
141
142 /* Confirm a successful initialization when it's the case */
143 autoInitSpan.setSucceeded();
144
145 /* Construct a short log name for this attachment. */
146 Utf8Str ctlName(aControllerName);
147 const char *psz = strpbrk(ctlName.c_str(), " \t:-");
148 mLogName = Utf8StrFmt("MA%p[%.*s:%u:%u:%s%s]",
149 this,
150 psz ? psz - ctlName.c_str() : 4, ctlName.c_str(),
151 aPort, aDevice, Global::stringifyDeviceType(aType),
152 m->bd->fImplicit ? ":I" : "");
153
154 LogFlowThisFunc(("LEAVE - %s\n", getLogName()));
155 return S_OK;
156}
157
158/**
159 * Uninitializes the instance.
160 * Called from FinalRelease().
161 */
162void MediumAttachment::uninit()
163{
164 LogFlowThisFunc(("ENTER - %s\n", getLogName()));
165
166 /* Enclose the state transition Ready->InUninit->NotReady */
167 AutoUninitSpan autoUninitSpan(this);
168 if (autoUninitSpan.uninitDone())
169 return;
170
171 m->bd.free();
172
173 unconst(m->pMachine) = NULL;
174
175 delete m;
176 m = NULL;
177
178 LogFlowThisFuncLeave();
179}
180
181// IHardDiskAttachment properties
182/////////////////////////////////////////////////////////////////////////////
183
184STDMETHODIMP MediumAttachment::COMGETTER(Medium)(IMedium **aHardDisk)
185{
186 LogFlowThisFuncEnter();
187
188 CheckComArgOutPointerValid(aHardDisk);
189
190 AutoCaller autoCaller(this);
191 if (FAILED(autoCaller.rc())) return autoCaller.rc();
192
193 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
194
195 m->bd->pMedium.queryInterfaceTo(aHardDisk);
196
197 LogFlowThisFuncLeave();
198 return S_OK;
199}
200
201STDMETHODIMP MediumAttachment::COMGETTER(Controller)(BSTR *aController)
202{
203 LogFlowThisFuncEnter();
204
205 CheckComArgOutPointerValid(aController);
206
207 AutoCaller autoCaller(this);
208 if (FAILED(autoCaller.rc())) return autoCaller.rc();
209
210 /* m->controller is constant during life time, no need to lock */
211 m->bd->bstrControllerName.cloneTo(aController);
212
213 LogFlowThisFuncLeave();
214 return S_OK;
215}
216
217STDMETHODIMP MediumAttachment::COMGETTER(Port)(LONG *aPort)
218{
219 LogFlowThisFuncEnter();
220
221 CheckComArgOutPointerValid(aPort);
222
223 AutoCaller autoCaller(this);
224 if (FAILED(autoCaller.rc())) return autoCaller.rc();
225
226 /* m->bd->port is constant during life time, no need to lock */
227 *aPort = m->bd->lPort;
228
229 LogFlowThisFuncLeave();
230 return S_OK;
231}
232
233STDMETHODIMP MediumAttachment::COMGETTER(Device)(LONG *aDevice)
234{
235 LogFlowThisFuncEnter();
236
237 CheckComArgOutPointerValid(aDevice);
238
239 AutoCaller autoCaller(this);
240 if (FAILED(autoCaller.rc())) return autoCaller.rc();
241
242 /* m->bd->device is constant during life time, no need to lock */
243 *aDevice = m->bd->lDevice;
244
245 LogFlowThisFuncLeave();
246 return S_OK;
247}
248
249STDMETHODIMP MediumAttachment::COMGETTER(Type)(DeviceType_T *aType)
250{
251 LogFlowThisFuncEnter();
252
253 CheckComArgOutPointerValid(aType);
254
255 AutoCaller autoCaller(this);
256 if (FAILED(autoCaller.rc())) return autoCaller.rc();
257
258 /* m->bd->type is constant during life time, no need to lock */
259 *aType = m->bd->type;
260
261 LogFlowThisFuncLeave();
262 return S_OK;
263}
264
265STDMETHODIMP MediumAttachment::COMGETTER(Passthrough)(BOOL *aPassthrough)
266{
267 LogFlowThisFuncEnter();
268
269 CheckComArgOutPointerValid(aPassthrough);
270
271 AutoCaller autoCaller(this);
272 if (FAILED(autoCaller.rc())) return autoCaller.rc();
273
274 AutoReadLock lock(this COMMA_LOCKVAL_SRC_POS);
275
276 *aPassthrough = m->bd->fPassthrough;
277
278 LogFlowThisFuncLeave();
279 return S_OK;
280}
281
282STDMETHODIMP MediumAttachment::COMGETTER(BandwidthGroup) (IBandwidthGroup **aBwGroup)
283{
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 m->bd->pBwGroup.queryInterfaceTo(aBwGroup);
292
293 return S_OK;
294}
295
296/**
297 * @note Locks this object for writing.
298 */
299void MediumAttachment::rollback()
300{
301 LogFlowThisFunc(("ENTER - %s\n", getLogName()));
302
303 /* sanity */
304 AutoCaller autoCaller(this);
305 AssertComRCReturnVoid(autoCaller.rc());
306
307 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
308
309 m->bd.rollback();
310
311 LogFlowThisFunc(("LEAVE - %s\n", getLogName()));
312}
313
314/**
315 * @note Locks this object for writing.
316 */
317void MediumAttachment::commit()
318{
319 LogFlowThisFuncEnter();
320
321 /* sanity */
322 AutoCaller autoCaller(this);
323 AssertComRCReturnVoid (autoCaller.rc());
324
325 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
326
327 if (m->bd.isBackedUp())
328 m->bd.commit();
329
330 LogFlowThisFuncLeave();
331}
332
333bool MediumAttachment::isImplicit() const
334{
335 return m->bd->fImplicit;
336}
337
338void MediumAttachment::setImplicit(bool aImplicit)
339{
340 m->bd->fImplicit = aImplicit;
341}
342
343const ComObjPtr<Medium>& MediumAttachment::getMedium() const
344{
345 return m->bd->pMedium;
346}
347
348Bstr MediumAttachment::getControllerName() const
349{
350 return m->bd->bstrControllerName;
351}
352
353LONG MediumAttachment::getPort() const
354{
355 return m->bd->lPort;
356}
357
358LONG MediumAttachment::getDevice() const
359{
360 return m->bd->lDevice;
361}
362
363DeviceType_T MediumAttachment::getType() const
364{
365 return m->bd->type;
366}
367
368bool MediumAttachment::getPassthrough() const
369{
370 AutoReadLock lock(this COMMA_LOCKVAL_SRC_POS);
371 return m->bd->fPassthrough;
372}
373
374const ComObjPtr<BandwidthGroup>& MediumAttachment::getBandwidthGroup() const
375{
376 return m->bd->pBwGroup;
377}
378
379bool MediumAttachment::matches(CBSTR aControllerName, LONG aPort, LONG aDevice)
380{
381 return ( aControllerName == m->bd->bstrControllerName
382 && aPort == m->bd->lPort
383 && aDevice == m->bd->lDevice);
384}
385
386/**
387 * Sets the medium of this attachment and unsets the "implicit" flag.
388 * @param aMedium
389 */
390void MediumAttachment::updateMedium(const ComObjPtr<Medium> &aMedium)
391{
392 Assert(isWriteLockOnCurrentThread());
393
394 m->bd.backup();
395 m->bd->pMedium = aMedium;
396 m->bd->fImplicit = false;
397}
398
399/** Must be called from under this object's write lock. */
400void MediumAttachment::updatePassthrough(bool aPassthrough)
401{
402 Assert(isWriteLockOnCurrentThread());
403
404 m->bd.backup();
405 m->bd->fPassthrough = aPassthrough;
406}
407
408void MediumAttachment::updateBandwidthGroup(const ComObjPtr<BandwidthGroup> &aBandwidthGroup)
409{
410 Assert(isWriteLockOnCurrentThread());
411
412 m->bd.backup();
413 if (!aBandwidthGroup.isNull())
414 aBandwidthGroup->reference();
415
416 if (!m->bd->pBwGroup.isNull())
417 {
418 m->bd->pBwGroup->release();
419 }
420 m->bd->pBwGroup = aBandwidthGroup;
421}
422
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