[libvirt] [RFC PATCH 0/8 v3] Summary on block IO throttle
by Lei Li
Changes since V2
- Implement the Python binding support for setting blkio throttling.
- Implement --current --live --config options support to unify the libvirt API.
- Add changes in docs and tests.
- Some changes suggested by Adam Litke, Eric Blake, Daniel P. Berrange.
- Change the XML schema.
- API name to virDomain{Set, Get}BlockIoTune.
- Parameters changed to make them more self-explanatory.
- virsh command name to blkdeviotune.
- And other fixups.
Changes since V1
- Implement the support to get the block io throttling for
a device as read only connection - QMP/HMP.
- Split virDomainBlockIoThrottle into two separate functions
virDomainSetBlockIoThrottle - Set block I/O limits for a device
- Requires a connection in 'write' mode.
- Limits (info) structure passed as an input parameter
virDomainGetBlockIoThrottle - Get the current block I/O limits for a device
- Works on a read-only connection.
- Current limits are written to the output parameter (reply).
- And Other fixups suggested by Adam Litke, Daniel P. Berrange.
- For dynamically allocate the blkiothrottle struct, I will fix
it when implement --current --live --config options support.
Today libvirt supports the cgroups blkio-controller, which handles
proportional shares and throughput/iops limits on host block devices.
blkio-controller does not support network file systems (NFS) or other
QEMU remote block drivers (curl, Ceph/rbd, sheepdog) since they are
not host block devices. QEMU I/O throttling works with all types of
drive and can be applied independently to each drive attached to
a guest and supports throughput/iops limits.
To help add QEMU I/O throttling support to libvirt, we plan to complete
it with add new API virDomain{Set, Get}BlockIoThrottle(), new command 'blkdeviotune'
and Python bindings.
Notes: Now all the planed features were implemented (#1#2 were implemented by
Zhi Yong Wu), the previous comments were all fixed up too. And the qemu part patches
have been accepted upstream just now and are expected to be part of the QEMU 1.1
release, git tree from Zhi Yong:
http://repo.or.cz/w/qemu/kevin.git/shortlog/refs/heads/block
1) Enable the blkio throttling in xml when guest is starting up.
Add blkio throttling in xml as follows:
<disk type='file' device='disk'>
...
<iotune>
<total_bytes_sec>nnn</total_bytes_sec>
...
</iotune>
...
</disk>
2) Enable blkio throttling setting at guest running time.
virsh blkdeviotune <domain> <device> [--total_bytes_sec<number>] [--read_bytes_sec<number>] \
[--write_bytes_sec<number>] [--total_iops_sec<number>] [--read_iops_sec<number>]
[--write_iops_sec<number>]
3) The support to get the current block i/o throttling for a device - HMP/QMP.
virsh blkiothrottle <domain> <device>
total_bytes_sec:
read_bytes_sec:
write_bytes_sec:
total_iops_sec:
read_iops_sec:
write_iops_sec:
4) Python binding support for setting blkio throttling.
5) --current --live --config options support to unify the libvirt API.
virsh blkdeviotune <domain> <device> [--total_bytes_sec <number>] [--read_bytes_sec <number>]
[--write_bytes_sec <number>] [--total_iops_sec <number>] [--read_iops_sec <number>]
[--write_iops_sec <number>] [--config] [--live] [--current]
daemon/remote.c | 87 +++++++
docs/formatdomain.html.in | 30 ++
docs/schemas/domaincommon.rng | 24 +
include/libvirt/libvirt.h.in | 25 ++
python/generator.py | 2
python/libvirt-override-api.xml | 16 +
python/libvirt-override.c | 85 +++++++
src/conf/domain_conf.c | 101 ++++++++
src/conf/domain_conf.h | 12
src/driver.h | 18 +
src/libvirt.c | 115 +++++++++
src/libvirt_public.syms | 2
src/qemu/qemu_command.c | 33 ++
src/qemu/qemu_driver.c | 217 ++++++++++++++++++
src/qemu/qemu_monitor.c | 36 ++
src/qemu/qemu_monitor.h | 10
src/qemu/qemu_monitor_json.c | 191 +++++++++++++++
src/qemu/qemu_monitor_json.h | 10
src/qemu/qemu_monitor_text.c | 152 ++++++++++++
src/qemu/qemu_monitor_text.h | 10
src/remote/remote_driver.c | 81 ++++++
src/remote/remote_protocol.x | 39 +++
src/remote_protocol-structs | 34 ++
src/util/xml.h | 3
tests/qemuxml2argvdata/qemuxml2argv-blkdeviotune.args | 4
tests/qemuxml2argvdata/qemuxml2argv-blkdeviotune.xml | 36 ++
tests/qemuxml2argvtest.c | 2
tests/qemuxml2xmltest.c | 2
tools/virsh.c | 146 ++++++++++++
tools/virsh.pod | 23 +
30 files changed, 1540 insertions(+), 6 deletions(-)
--
Lei
13 years
[libvirt] Problem with listDomains() in Xen
by PREETHI RAMESH
This question concerns the usage of the listDomains(). When I run this
piece of code in KVM, it works perfectly fine but throws an array out of
bounds exception in Xen.
Connect conn=null;
conn = new Connect("xen:///", true);
int[] id = conn.listDomains();
System.out.println("lD of VM " +id[0]);
Answer I'd got:
Well, your code assumes that id.length is >= 1, but listDomains() can
return an empty array when there are no active domains known to
libvirt. So you need to check id.length before accessing any element
in the array.
Follow up- I tried accessing the length of the array and it's 0 all the
time. And there are active domains available.
In fact, I'm able to getUUID from the domain name. Other functions work
fine too.
Am I missing something?Can someone please help me? Thanks!
13 years
[libvirt] [PATCH 7/8] Support virDomain{Set, Get}BlockIoThrottle in the python API
by Lei Li
Python support for both set and get block I/O throttle.
Signed-off-by: Zhi Yong Wu <wuzhy(a)linux.vnet.ibm.com>
Signed-off-by: Lei Li <lilei(a)linux.vnet.ibm.com>
---
python/generator.py | 2 +
python/libvirt-override-api.xml | 16 +++++++
python/libvirt-override.c | 85 +++++++++++++++++++++++++++++++++++++++
3 files changed, 103 insertions(+), 0 deletions(-)
diff --git a/python/generator.py b/python/generator.py
index 71afdb7..88c52b9 100755
--- a/python/generator.py
+++ b/python/generator.py
@@ -414,6 +414,8 @@ skip_impl = (
'virDomainGetBlockJobInfo',
'virDomainMigrateGetMaxSpeed',
'virDomainBlockStatsFlags',
+ 'virDomainSetBlockIoTune',
+ 'virDomainGetBlockIoTune',
)
qemu_skip_impl = (
diff --git a/python/libvirt-override-api.xml b/python/libvirt-override-api.xml
index ef02f34..e8d9138 100644
--- a/python/libvirt-override-api.xml
+++ b/python/libvirt-override-api.xml
@@ -375,5 +375,21 @@
<arg name='flags' type='unsigned int' info='flags, currently unused, pass 0.'/>
<return type='unsigned long' info='current max migration speed, or None in case of error'/>
</function>
+ <function name='virDomainSetBlockIoTune' file='python'>
+ <info>Change the I/O throttle for a block device</info>
+ <arg name='dom' type='virDomainPtr' info='pointer to the domain'/>
+ <arg name='disk' type='const char *' info='disk name'/>
+ <arg name='info' type='virDomainBlockIoTuneInfoPtr' info='io throttle limits'/>
+ <arg name='flags' type='unsigned int' info='an OR'ed set of virDomainModificationImpact'/>
+ <return type='virDomainSetBlockIoTuneInfo' info='0 in case of operation has started, -1 in case of failure'/>
+ </function>
+ <function name='virDomainGetBlockIoTune' file='python'>
+ <info>Get the I/O throttle a block device</info>
+ <arg name='dom' type='virDomainPtr' info='pointer to the domain'/>
+ <arg name='disk' type='const char *' info='disk name'/>
+ <arg name='reply' type='virDomainBlockIoTuneInfoPtr' info='io throttle info'/>
+ <arg name='flags' type='unsigned int' info='an OR'ed set of virDomainModificationImpact'/>
+ <return type='virDomainGetBlockIoTuneInfo' info='A dictionary containing block I/O limits information.'/>
+ </function>
</symbols>
</api>
diff --git a/python/libvirt-override.c b/python/libvirt-override.c
index 1759bae..d4b023a 100644
--- a/python/libvirt-override.c
+++ b/python/libvirt-override.c
@@ -3195,6 +3195,89 @@ LIBVIRT_END_ALLOW_THREADS;
return ret;
}
+static PyObject *
+libvirt_virDomainSetBlockIoTune(PyObject *self ATTRIBUTE_UNUSED,
+ PyObject *args)
+{
+ virDomainPtr domain;
+ PyObject *pyobj_domain, *pyinfo;
+ const char *disk;
+ unsigned int flags;
+ virDomainBlockIoTuneInfo info;
+ int c_ret;
+ PyObject *ret;
+
+ if (!PyArg_ParseTuple(args, (char *)"Ozi:virDomainSetBlockIoTune",
+ &pyobj_domain, &disk, &pyinfo, &flags))
+ return(NULL);
+ domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
+
+ info.total_bytes_sec = (unsigned long long)PyLong_AsLongLong(PyDict_GetItem(pyinfo,
+ libvirt_constcharPtrWrap("bps")));
+ info.read_bytes_sec = (unsigned long long)PyLong_AsLongLong(PyDict_GetItem(pyinfo,
+ libvirt_constcharPtrWrap("bps_rd")));
+ info.write_bytes_sec = (unsigned long long)PyLong_AsLongLong(PyDict_GetItem(pyinfo,
+ libvirt_constcharPtrWrap("bps_wr")));
+ info.total_iops_sec = (unsigned long long)PyLong_AsLongLong(PyDict_GetItem(pyinfo,
+ libvirt_constcharPtrWrap("iops")));
+ info.read_iops_sec = (unsigned long long)PyLong_AsLongLong(PyDict_GetItem(pyinfo,
+ libvirt_constcharPtrWrap("iops_rd")));
+ info.write_iops_sec = (unsigned long long)PyLong_AsLongLong(PyDict_GetItem(pyinfo,
+ libvirt_constcharPtrWrap("iops_wr")));
+
+ LIBVIRT_BEGIN_ALLOW_THREADS;
+ c_ret = virDomainSetBlockIoTune(domain, disk, &info, flags);
+ LIBVIRT_END_ALLOW_THREADS;
+
+ if (c_ret < 0) {
+ return VIR_PY_NONE;
+ }
+
+ return VIR_PY_INT_SUCCESS;
+}
+
+static PyObject *
+libvirt_virDomainGetBlockIoTune(PyObject *self ATTRIBUTE_UNUSED,
+ PyObject *args)
+{
+ virDomainPtr domain;
+ PyObject *pyobj_domain;
+ const char *disk;
+ unsigned int flags;
+ virDomainBlockIoTuneInfo reply;
+ int c_ret;
+ PyObject *ret;
+
+ if (!PyArg_ParseTuple(args, (char *)"Oi:virDomainGetBlockIoTune",
+ &pyobj_domain, &disk, &flags))
+ return(NULL);
+ domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
+
+ LIBVIRT_BEGIN_ALLOW_THREADS;
+ c_ret = virDomainGetBlockIoTune(domain, disk, &reply, flags);
+ LIBVIRT_END_ALLOW_THREADS;
+
+ if (c_ret < 0)
+ return VIR_PY_NONE;
+
+ if ((ret = PyDict_New()) == NULL)
+ return VIR_PY_NONE;
+
+ PyDict_SetItem(ret, libvirt_constcharPtrWrap("total_bytes_sec"),
+ libvirt_ulonglongWrap(reply.total_bytes_sec));
+ PyDict_SetItem(ret, libvirt_constcharPtrWrap("read_bytes_sec"),
+ libvirt_ulonglongWrap(reply.read_bytes_sec));
+ PyDict_SetItem(ret, libvirt_constcharPtrWrap("write_bytes_sec"),
+ libvirt_ulonglongWrap(reply.write_bytes_sec));
+ PyDict_SetItem(ret, libvirt_constcharPtrWrap("total_iops_sec"),
+ libvirt_ulonglongWrap(reply.total_iops_sec));
+ PyDict_SetItem(ret, libvirt_constcharPtrWrap("read_iops_sec"),
+ libvirt_ulonglongWrap(reply.read_iops_sec));
+ PyDict_SetItem(ret, libvirt_constcharPtrWrap("write_iops_sec"),
+ libvirt_ulonglongWrap(reply.write_iops_sec));
+ return ret;
+}
+
/*******************************************
* Helper functions to avoid importing modules
* for every callback
@@ -4837,6 +4920,8 @@ static PyMethodDef libvirtMethods[] = {
{(char *) "virDomainSnapshotListNames", libvirt_virDomainSnapshotListNames, METH_VARARGS, NULL},
{(char *) "virDomainRevertToSnapshot", libvirt_virDomainRevertToSnapshot, METH_VARARGS, NULL},
{(char *) "virDomainGetBlockJobInfo", libvirt_virDomainGetBlockJobInfo, METH_VARARGS, NULL},
+ {(char *) "virDomainSetBlockIoTune", libvirt_virDomainSetBlockIoTune, METH_VARARGS, NULL},
+ {(char *) "virDomainGetBlockIoTune", libvirt_virDomainGetBlockIoTune, METH_VARARGS, NULL},
{(char *) "virDomainSendKey", libvirt_virDomainSendKey, METH_VARARGS, NULL},
{(char *) "virDomainMigrateGetMaxSpeed", libvirt_virDomainMigrateGetMaxSpeed, METH_VARARGS, NULL},
{NULL, NULL, 0, NULL}
--
1.7.1
13 years
[libvirt] [PATCH 5/8] Enable the blkdeviotune command in virsh
by Lei Li
Support virsh command blkdeviotune. Can set or query a block disk
I/O throttle setting.
Signed-off-by: Zhi Yong Wu <wuzhy(a)linux.vnet.ibm.com>
Signed-off-by: Lei Li <lilei(a)linux.vnet.ibm.com>
---
tools/virsh.c | 146 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
tools/virsh.pod | 23 +++++++++
2 files changed, 169 insertions(+), 0 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c
index 83dc3c7..df2b399 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -6023,6 +6023,151 @@ cmdBlockJob(vshControl *ctl, const vshCmd *cmd)
return true;
}
+/*
+ * "blkdeviotune" command
+ */
+static const vshCmdInfo info_blkdeviotune[] = {
+ {"help", N_("Set or query a block disk I/O throttle setting.")},
+ {"desc", N_("Set or query a block disk I/O throttle setting.\n" \
+ " To query the block disk I/O throttle setting use the following" \
+ " command: \n\n" \
+ " virsh # blkdeviotune <domain> <device>")},
+ {NULL, NULL}
+};
+
+static const vshCmdOptDef opts_blkdeviotune[] = {
+ {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
+ {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("block device")},
+ {"total_bytes_sec", VSH_OT_INT, VSH_OFLAG_NONE, N_("total throughput limit in bytes per second/s")},
+ {"read_bytes_sec", VSH_OT_INT, VSH_OFLAG_NONE, N_("read throughput limit in bytes per second/s")},
+ {"write_bytes_sec", VSH_OT_INT, VSH_OFLAG_NONE, N_("write throughput limit in bytes per second/s")},
+ {"total_iops_sec", VSH_OT_INT, VSH_OFLAG_NONE, N_("total I/O operations limit per second/s")},
+ {"read_iops_sec", VSH_OT_INT, VSH_OFLAG_NONE, N_("read I/O operations limit per second/s")},
+ {"write_iops_sec", VSH_OT_INT, VSH_OFLAG_NONE, N_("write I/O operations limit per second/s")},
+ {"config", VSH_OT_BOOL, 0, N_("affect next boot")},
+ {"live", VSH_OT_BOOL, 0, N_("affect running domain")},
+ {"current", VSH_OT_BOOL, 0, N_("affect current domain")},
+ {NULL, 0, 0, NULL}
+};
+
+static bool
+cmdBlkdeviotune(vshControl *ctl, const vshCmd *cmd)
+{
+ virDomainPtr dom = NULL;
+ const char *name, *disk;
+ virDomainBlockIoTuneInfo info;
+ virDomainBlockIoTuneInfo reply;
+ unsigned int flags = 0;
+ int ret = -1;
+ int rv = 0;
+ int set = 0;
+ int current = vshCommandOptBool(cmd, "current");
+ int config = vshCommandOptBool(cmd, "config");
+ int live = vshCommandOptBool(cmd, "live");
+
+ if (current) {
+ if (live || config) {
+ vshError(ctl, "%s", _("--current must be specified exclusively"));
+ return false;
+ }
+ flags = VIR_DOMAIN_AFFECT_CURRENT;
+ } else {
+ if (config)
+ flags |= VIR_DOMAIN_AFFECT_CONFIG;
+ if (live)
+ flags |= VIR_DOMAIN_AFFECT_LIVE;
+ }
+
+ memset(&info, 0, sizeof(info));
+
+ if (!vshConnectionUsability(ctl, ctl->conn))
+ goto out;
+
+ if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
+ goto out;
+
+ if (vshCommandOptString(cmd, "device", &disk) < 0)
+ goto out;
+
+ if ((rv = vshCommandOptULongLong(cmd, "total_bytes_sec", &info.total_bytes_sec)) < 0) {
+ vshError(ctl, "%s",
+ _("Unable to parse integer parameter"));
+ goto out;
+ } else if (rv > 0) {
+ set++;
+ }
+
+ if ((rv = vshCommandOptULongLong(cmd, "read_bytes_sec", &info.read_bytes_sec)) < 0) {
+ vshError(ctl, "%s",
+ _("Unable to parse integer parameter"));
+ goto out;
+ } else if (rv > 0) {
+ set++;
+ }
+
+ if ((rv = vshCommandOptULongLong(cmd, "write_bytes_sec", &info.write_bytes_sec)) < 0) {
+ vshError(ctl, "%s",
+ _("Unable to parse integer parameter"));
+ goto out;
+ } else if (rv > 0) {
+ set++;
+ }
+
+ if ((rv = vshCommandOptULongLong(cmd, "total_iops_sec", &info.total_iops_sec)) < 0) {
+ vshError(ctl, "%s",
+ _("Unable to parse integer parameter"));
+ goto out;
+ } else if (rv > 0) {
+ set++;
+ }
+
+ if ((rv = vshCommandOptULongLong(cmd, "read_iops_sec", &info.read_iops_sec)) < 0) {
+ vshError(ctl, "%s",
+ _("Unable to parse integer parameter"));
+ goto out;
+ } else if (rv > 0) {
+ set++;
+ }
+
+ if ((rv = vshCommandOptULongLong(cmd, "write_iops_sec", &info.write_iops_sec)) < 0) {
+ vshError(ctl, "%s",
+ _("Unable to parse integer parameter"));
+ goto out;
+ } else if (rv > 0) {
+ set++;
+ }
+
+ if (!set) {
+
+ ret = virDomainGetBlockIoTune(dom, disk, &reply, flags);
+
+ if (ret != 0)
+ goto out;
+
+ vshPrint(ctl, "%-15s %llu\n", _("total_bytes_sec:"), reply.total_bytes_sec);
+ vshPrint(ctl, "%-15s %llu\n", _("read_bytes_sec:"), reply.read_bytes_sec);
+ vshPrint(ctl, "%-15s %llu\n", _("write_bytes_sec:"), reply.write_bytes_sec);
+ vshPrint(ctl, "%-15s %llu\n", _("total_iops_sec:"), reply.total_iops_sec);
+ vshPrint(ctl, "%-15s %llu\n", _("read_iops_sec:"), reply.read_iops_sec);
+ vshPrint(ctl, "%-15s %llu\n", _("write_iops_sec:"), reply.write_iops_sec);
+
+ virDomainFree(dom);
+ return true;
+ } else {
+
+ ret = virDomainSetBlockIoTune(dom, disk, &info, flags);
+
+ if (ret == 0) {
+ virDomainFree(dom);
+ return true;
+ }
+ }
+
+out:
+ virDomainFree(dom);
+ return false;
+}
+
/*
* "net-autostart" command
@@ -14023,6 +14168,7 @@ static const vshCmdDef domManagementCmds[] = {
{"blkiotune", cmdBlkiotune, opts_blkiotune, info_blkiotune, 0},
{"blockpull", cmdBlockPull, opts_block_pull, info_block_pull, 0},
{"blockjob", cmdBlockJob, opts_block_job, info_block_job, 0},
+ {"blkdeviotune", cmdBlkdeviotune, opts_blkdeviotune, info_blkdeviotune, 0},
#ifndef WIN32
{"console", cmdConsole, opts_console, info_console, 0},
#endif
diff --git a/tools/virsh.pod b/tools/virsh.pod
index 775d302..58fcb51 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -572,6 +572,29 @@ operation can be checked with B<blockjob>.
I<path> specifies fully-qualified path of the disk.
I<bandwidth> specifies copying bandwidth limit in Mbps.
+=item B<blkdeviotune> I<domain> I<device> [[I<--total_bytes_sec> B<total_bytes_sec>]
+| [[I<--read_bytes_sec> B<read_bytes_sec>] [I<--write_bytes_sec> B<write_bytes_sec>]]
+[[I<--total_iops_sec> B<total_iops_sec>] | [[I<--read_iops_sec> B<read_iops_sec>]
+[I<--write_iops_sec> B<write_iops_sec>]] [[I<--config>] [I<--live>] | [I<--current>]]
+
+Set or query the block disk io limits settting.
+I<path> specifies block disk name.
+I<--total_bytes_sec> specifies total throughput limit in bytes per second/s.
+I<--read_bytes_sec> specifies read throughput limit in bytes per second/s.
+I<--write_bytes_sec> specifies write throughput limit in bytes per second/s.
+I<--total_iops_sec> specifies total I/O operations limit per second/s.
+I<--read_iops_sec> specifies read I/O operations limit per second/s.
+I<--write_iops_sec> specifies write I/O operations limit per second/s.
+
+If I<--live> is specified, affect a running guest.
+If I<--config> is specified, affect the next boot of a persistent guest.
+If I<--current> is specified, affect the current guest state.
+Both I<--live> and I<--current> flags may be given, but I<--current> is
+exclusive. If no flag is specified, behavior is different depending
+on hypervisor.
+
+If no limit is specified, it will query current I/O limits setting.
+
=item B<blockjob> I<domain> I<path> [I<--abort>] [I<--info>] [I<bandwidth>]
Manage active block operations.
--
1.7.1
13 years
[libvirt] [PATCH 4/8] Support block I/O throtte in XML
by Lei Li
Enable block I/O throttle for per-disk in XML.
Signed-off-by: Zhi Yong Wu <wuzhy(a)linux.vnet.ibm.com>
Signed-off-by: Lei Li <lilei(a)linux.vnet.ibm.com>
---
src/conf/domain_conf.c | 101 +++++++++++++++++++++++++++++++++++++++++++++-
src/conf/domain_conf.h | 12 ++++++
src/qemu/qemu_command.c | 33 +++++++++++++++
src/util/xml.h | 2 +
4 files changed, 145 insertions(+), 3 deletions(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 58f4d0f..564914e 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -2318,7 +2318,8 @@ static virDomainDiskDefPtr
virDomainDiskDefParseXML(virCapsPtr caps,
xmlNodePtr node,
virBitmapPtr bootMap,
- unsigned int flags)
+ unsigned int flags,
+ xmlXPathContextPtr ctxt)
{
virDomainDiskDefPtr def;
xmlNodePtr cur, child;
@@ -2517,6 +2518,62 @@ virDomainDiskDefParseXML(virCapsPtr caps,
}
child = child->next;
}
+ } else if (xmlStrEqual(cur->name, BAD_CAST "iotune")) {
+ if (virXPathULongLong("string(./devices/disk/iotune/total_bytes_sec)",
+ ctxt, &def->blkdeviotune.total_bytes_sec) < 0) {
+ def->blkdeviotune.total_bytes_sec = 0;
+ } else {
+ def->blkdeviotune.mark = 1;
+ }
+
+ if (virXPathULongLong("string(./devices/disk/iotune/read_bytes_sec)",
+ ctxt, &def->blkdeviotune.read_bytes_sec) < 0) {
+ def->blkdeviotune.read_bytes_sec = 0;
+ } else {
+ def->blkdeviotune.mark = 1;
+ }
+
+ if (virXPathULongLong("string(./devices/disk/iotune/write_bytes_sec)",
+ ctxt, &def->blkdeviotune.write_bytes_sec) < 0) {
+ def->blkdeviotune.write_bytes_sec = 0;
+ } else {
+ def->blkdeviotune.mark = 1;
+ }
+
+ if (virXPathULongLong("string(./devices/disk/iotune/total_iops_sec)",
+ ctxt, &def->blkdeviotune.total_iops_sec) < 0) {
+ def->blkdeviotune.total_iops_sec = 0;
+ } else {
+ def->blkdeviotune.mark = 1;
+ }
+
+ if (virXPathULongLong("string(./devices/disk/iotune/read_iops_sec)",
+ ctxt, &def->blkdeviotune.read_iops_sec) < 0) {
+ def->blkdeviotune.read_iops_sec = 0;
+ } else {
+ def->blkdeviotune.mark = 1;
+ }
+
+ if (virXPathULongLong("string(./devices/disk/iotune/write_iops_sec)",
+ ctxt, &def->blkdeviotune.write_iops_sec) < 0) {
+ def->blkdeviotune.write_iops_sec = 0;
+ } else {
+ def->blkdeviotune.mark = 1;
+ }
+
+ if ((def->blkdeviotune.total_bytes_sec && def->blkdeviotune.read_bytes_sec)
+ || (def->blkdeviotune.total_bytes_sec && def->blkdeviotune.write_bytes_sec)) {
+ virDomainReportError(VIR_ERR_XML_ERROR,
+ _("bps and bps_rd/bps_wr cannot be set at the same time"));
+ goto error;
+ }
+
+ if ((def->blkdeviotune.total_iops_sec && def->blkdeviotune.read_iops_sec)
+ || (def->blkdeviotune.total_iops_sec && def->blkdeviotune.write_iops_sec)) {
+ virDomainReportError(VIR_ERR_XML_ERROR,
+ _("iops and iops_rd/iops_wr cannot be set at the same time"));
+ goto error;
+ }
} else if (xmlStrEqual(cur->name, BAD_CAST "readonly")) {
def->readonly = 1;
} else if (xmlStrEqual(cur->name, BAD_CAST "shareable")) {
@@ -6003,7 +6060,7 @@ virDomainDeviceDefPtr virDomainDeviceDefParse(virCapsPtr caps,
if (xmlStrEqual(node->name, BAD_CAST "disk")) {
dev->type = VIR_DOMAIN_DEVICE_DISK;
if (!(dev->data.disk = virDomainDiskDefParseXML(caps, node,
- NULL, flags)))
+ NULL, flags, NULL)))
goto error;
} else if (xmlStrEqual(node->name, BAD_CAST "lease")) {
dev->type = VIR_DOMAIN_DEVICE_LEASE;
@@ -7076,7 +7133,8 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
virDomainDiskDefPtr disk = virDomainDiskDefParseXML(caps,
nodes[i],
bootMap,
- flags);
+ flags,
+ ctxt);
if (!disk)
goto error;
@@ -9511,6 +9569,43 @@ virDomainDiskDefFormat(virBufferPtr buf,
virBufferAsprintf(buf, " <target dev='%s' bus='%s'/>\n",
def->dst, bus);
+ /*disk I/O throttling*/
+ if (def->blkdeviotune.mark) {
+ virBufferAddLit(buf, " <iotune>\n");
+ if (def->blkdeviotune.total_bytes_sec) {
+ virBufferAsprintf(buf, " <total_bytes_sec>%llu</total_bytes_sec>\n",
+ def->blkdeviotune.total_bytes_sec);
+ }
+
+ if (def->blkdeviotune.read_bytes_sec) {
+ virBufferAsprintf(buf, " <read_bytes_sec>%llu</read_bytes_sec>\n",
+ def->blkdeviotune.read_bytes_sec);
+
+ }
+
+ if (def->blkdeviotune.write_bytes_sec) {
+ virBufferAsprintf(buf, " <write_bytes_sec>%llu</write_bytes_sec>\n",
+ def->blkdeviotune.write_bytes_sec);
+ }
+
+ if (def->blkdeviotune.total_iops_sec) {
+ virBufferAsprintf(buf, " <total_iops_sec>%llu</total_iops_sec>\n",
+ def->blkdeviotune.total_iops_sec);
+ }
+
+ if (def->blkdeviotune.read_iops_sec) {
+ virBufferAsprintf(buf, " <read_iops_sec>%llu</read_iops_sec>",
+ def->blkdeviotune.read_iops_sec);
+ }
+
+ if (def->blkdeviotune.write_iops_sec) {
+ virBufferAsprintf(buf, " <write_iops_sec>%llu</write_iops_sec>",
+ def->blkdeviotune.write_iops_sec);
+ }
+
+ virBufferAddLit(buf, " </iotune>\n");
+ }
+
if (def->bootIndex)
virBufferAsprintf(buf, " <boot order='%d'/>\n", def->bootIndex);
if (def->readonly)
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index a3cb834..d95e239 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -333,6 +333,18 @@ struct _virDomainDiskDef {
} auth;
char *driverName;
char *driverType;
+
+ /*disk I/O throttling*/
+ struct {
+ unsigned long long total_bytes_sec;
+ unsigned long long read_bytes_sec;
+ unsigned long long write_bytes_sec;
+ unsigned long long total_iops_sec;
+ unsigned long long read_iops_sec;
+ unsigned long long write_iops_sec;
+ unsigned int mark;
+ } blkdeviotune;
+
char *serial;
int cachemode;
int error_policy; /* enum virDomainDiskErrorPolicy */
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 11ebb69..3a8575b 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -1715,6 +1715,39 @@ qemuBuildDriveStr(virConnectPtr conn ATTRIBUTE_UNUSED,
}
}
+ /*block I/O throttling*/
+ if (disk->blkdeviotune.mark) {
+ if (disk->blkdeviotune.total_bytes_sec) {
+ virBufferAsprintf(&opt, ",bps=%llu",
+ disk->blkdeviotune.total_bytes_sec);
+ }
+
+ if (disk->blkdeviotune.read_bytes_sec) {
+ virBufferAsprintf(&opt, ",bps_rd=%llu",
+ disk->blkdeviotune.read_bytes_sec);
+ }
+
+ if (disk->blkdeviotune.write_bytes_sec) {
+ virBufferAsprintf(&opt, ",bps_wr=%llu",
+ disk->blkdeviotune.write_bytes_sec);
+ }
+
+ if (disk->blkdeviotune.total_iops_sec) {
+ virBufferAsprintf(&opt, ",iops=%llu",
+ disk->blkdeviotune.total_iops_sec);
+ }
+
+ if (disk->blkdeviotune.read_iops_sec) {
+ virBufferAsprintf(&opt, ",iops_rd=%llu",
+ disk->blkdeviotune.read_iops_sec);
+ }
+
+ if (disk->blkdeviotune.write_iops_sec) {
+ virBufferAsprintf(&opt, ",iops_wr=%llu",
+ disk->blkdeviotune.write_iops_sec);
+ }
+ }
+
if (virBufferError(&opt)) {
virReportOOMError();
goto error;
diff --git a/src/util/xml.h b/src/util/xml.h
index c492063..5742f19 100644
--- a/src/util/xml.h
+++ b/src/util/xml.h
@@ -50,6 +50,8 @@ xmlNodePtr virXPathNode(const char *xpath,
int virXPathNodeSet(const char *xpath,
xmlXPathContextPtr ctxt,
xmlNodePtr **list);
+int virXMLStringToULongLong (const char *stringval,
+ unsigned long long *value);
char * virXMLPropString(xmlNodePtr node,
const char *name);
--
1.7.1
13 years
[libvirt] [PATCH 3/8] Implement virDomain{Set, Get}BlockIoTune for the qemu driver
by Lei Li
This patch implement the blk io throttle setting and getting support to qemu
driver.
Signed-off-by: Zhi Yong Wu <wuzhy(a)linux.vnet.ibm.com>
Signed-off-by: Lei Li <lilei(a)linux.vnet.ibm.com>
---
src/qemu/qemu_driver.c | 216 ++++++++++++++++++++++++++++++++++++++++++
src/qemu/qemu_monitor.c | 36 +++++++
src/qemu/qemu_monitor.h | 10 ++
src/qemu/qemu_monitor_json.c | 191 +++++++++++++++++++++++++++++++++++++
src/qemu/qemu_monitor_json.h | 10 ++
src/qemu/qemu_monitor_text.c | 152 +++++++++++++++++++++++++++++
src/qemu/qemu_monitor_text.h | 10 ++
7 files changed, 625 insertions(+), 0 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index db2ac0d..7ca6719 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -10759,6 +10759,220 @@ cleanup:
return ret;
}
+static int
+qemuDomainSetBlockIoTune(virDomainPtr dom,
+ const char *disk,
+ virDomainBlockIoTuneInfoPtr info,
+ unsigned int flags)
+{
+ struct qemud_driver *driver = dom->conn->privateData;
+ virDomainObjPtr vm = NULL;
+ qemuDomainObjPrivatePtr priv;
+ virDomainDefPtr persistentDef = NULL;
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ const char *device = NULL;
+ int ret = -1;
+ bool isActive;
+
+ virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
+ VIR_DOMAIN_AFFECT_CONFIG, -1);
+
+ qemuDriverLock(driver);
+ virUUIDFormat(dom->uuid, uuidstr);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ if (!vm) {
+ qemuReportError(VIR_ERR_NO_DOMAIN,
+ _("no domain with matching uuid '%s'"), uuidstr);
+ goto cleanup;
+ }
+
+ device = qemuDiskPathToAlias(vm, disk);
+ if (!device) {
+ goto cleanup;
+ }
+
+ if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
+ goto cleanup;
+
+ isActive = virDomainObjIsActive(vm);
+
+ if (flags == VIR_DOMAIN_AFFECT_CURRENT) {
+ if (isActive)
+ flags = VIR_DOMAIN_AFFECT_LIVE;
+ else
+ flags = VIR_DOMAIN_AFFECT_CONFIG;
+ }
+
+ if ((info->total_bytes_sec && info->read_bytes_sec) ||
+ (info->total_bytes_sec && info->write_bytes_sec)) {
+ qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("bps and bps_rd/bps_wr cannot be used at the same time"));
+ goto endjob;
+ }
+
+ if ((info->total_iops_sec && info->read_iops_sec) ||
+ (info->total_iops_sec && info->write_iops_sec)) {
+ qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("iops and iops_rd/iops_wr cannot be used at the same time"));
+ goto endjob;
+ }
+
+ if (!isActive && (flags & VIR_DOMAIN_AFFECT_LIVE)) {
+ qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("domain is not running"));
+ goto endjob;
+ }
+
+ if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
+ if (!vm->persistent) {
+ qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("cannot change persistent config of a transient domain"));
+ goto endjob;
+ }
+ if (!(persistentDef = virDomainObjGetPersistentDef(driver->caps, vm)))
+ goto endjob;
+ }
+
+ if (flags & VIR_DOMAIN_AFFECT_LIVE) {
+ priv = vm->privateData;
+ qemuDomainObjEnterMonitorWithDriver(driver, vm);
+ ret = qemuMonitorSetBlockIoThrottle(priv->mon, device, info, 1);
+ qemuDomainObjExitMonitorWithDriver(driver, vm);
+ }
+
+ if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
+ sa_assert(persistentDef);
+ int i = virDomainDiskIndexByName(vm->def, disk, true);
+ if (i < 0)
+ goto endjob;
+ persistentDef->disks[i]->blkdeviotune.total_bytes_sec = info->total_bytes_sec;
+ persistentDef->disks[i]->blkdeviotune.read_bytes_sec = info->read_bytes_sec;
+ persistentDef->disks[i]->blkdeviotune.write_bytes_sec = info->write_bytes_sec;
+ persistentDef->disks[i]->blkdeviotune.total_iops_sec = info->total_iops_sec;
+ persistentDef->disks[i]->blkdeviotune.read_iops_sec = info->read_iops_sec;
+ persistentDef->disks[i]->blkdeviotune.write_iops_sec = info->write_iops_sec;
+ persistentDef->disks[i]->blkdeviotune.mark = 1;
+ }
+
+ if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
+ ret = virDomainSaveConfig(driver->configDir, persistentDef);
+ if (ret < 0) {
+ qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("Write to config file failed"));
+ goto endjob;
+ }
+ }
+
+endjob:
+ if (qemuDomainObjEndJob(driver, vm) == 0)
+ vm = NULL;
+
+cleanup:
+ VIR_FREE(device);
+ if (vm)
+ virDomainObjUnlock(vm);
+ qemuDriverUnlock(driver);
+ return ret;
+}
+
+static int
+qemuDomainGetBlockIoTune(virDomainPtr dom,
+ const char *disk,
+ virDomainBlockIoTuneInfoPtr reply,
+ unsigned int flags)
+{
+ struct qemud_driver *driver = dom->conn->privateData;
+ virDomainObjPtr vm = NULL;
+ qemuDomainObjPrivatePtr priv;
+ virDomainDefPtr persistentDef = NULL;
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ const char *device = NULL;
+ int ret = -1;
+ bool isActive;
+
+ virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
+ VIR_DOMAIN_AFFECT_CONFIG, -1);
+
+ qemuDriverLock(driver);
+ virUUIDFormat(dom->uuid, uuidstr);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ if (!vm) {
+ qemuReportError(VIR_ERR_NO_DOMAIN,
+ _("no domain with matching uuid '%s'"), uuidstr);
+ goto cleanup;
+ }
+
+ device = qemuDiskPathToAlias(vm, disk);
+
+ if (!device) {
+ goto cleanup;
+ }
+
+ if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
+ goto cleanup;
+
+ isActive = virDomainObjIsActive(vm);
+
+ if (flags == VIR_DOMAIN_AFFECT_CURRENT) {
+ if (isActive)
+ flags = VIR_DOMAIN_AFFECT_LIVE;
+ else
+ flags = VIR_DOMAIN_AFFECT_CONFIG;
+ }
+
+ if ((flags & VIR_DOMAIN_AFFECT_LIVE) && (flags & VIR_DOMAIN_AFFECT_CONFIG)) {
+ qemuReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("Cannot query with --live and --config together"));
+ goto cleanup;
+ }
+
+ if (!isActive && (flags & VIR_DOMAIN_AFFECT_LIVE)) {
+ qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("domain is not running"));
+ goto cleanup;
+ }
+
+ if (flags & VIR_DOMAIN_AFFECT_LIVE) {
+ priv = vm->privateData;
+ qemuDomainObjEnterMonitorWithDriver(driver, vm);
+ ret = qemuMonitorGetBlockIoThrottle(priv->mon, device, reply, 0);
+ qemuDomainObjExitMonitorWithDriver(driver, vm);
+ }
+
+ if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
+ if (!vm->persistent) {
+ qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("domain is transient"));
+ goto cleanup;
+ }
+ if (!(persistentDef = virDomainObjGetPersistentDef(driver->caps, vm)))
+ goto cleanup;
+
+ sa_assert(persistentDef);
+ int i = virDomainDiskIndexByName(vm->def, disk, true);
+ if (i < 0)
+ goto cleanup;
+ reply->total_bytes_sec = persistentDef->disks[i]->blkdeviotune.total_bytes_sec;
+ reply->read_bytes_sec = persistentDef->disks[i]->blkdeviotune.read_bytes_sec;
+ reply->write_bytes_sec = persistentDef->disks[i]->blkdeviotune.write_bytes_sec;
+ reply->total_iops_sec = persistentDef->disks[i]->blkdeviotune.total_iops_sec;
+ reply->read_iops_sec = persistentDef->disks[i]->blkdeviotune.read_iops_sec;
+ reply->write_iops_sec = persistentDef->disks[i]->blkdeviotune.write_iops_sec;
+ ret = 0;
+ }
+
+ if (qemuDomainObjEndJob(driver, vm) == 0) {
+ vm = NULL;
+ goto cleanup;
+ }
+
+cleanup:
+ VIR_FREE(device);
+ if (vm)
+ virDomainObjUnlock(vm);
+ qemuDriverUnlock(driver);
+ return ret;
+}
static virDriver qemuDriver = {
.no = VIR_DRV_QEMU,
@@ -10903,6 +11117,8 @@ static virDriver qemuDriver = {
.domainGetBlockJobInfo = qemuDomainGetBlockJobInfo, /* 0.9.4 */
.domainBlockJobSetSpeed = qemuDomainBlockJobSetSpeed, /* 0.9.4 */
.domainBlockPull = qemuDomainBlockPull, /* 0.9.4 */
+ .domainSetBlockIoTune = qemuDomainSetBlockIoTune, /* 0.9.8 */
+ .domainGetBlockIoTune = qemuDomainGetBlockIoTune, /* 0.9.8 */
};
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 73e5ea9..5f5bd08 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -2567,6 +2567,42 @@ int qemuMonitorBlockJob(qemuMonitorPtr mon,
return ret;
}
+int qemuMonitorSetBlockIoThrottle(qemuMonitorPtr mon,
+ const char *device,
+ virDomainBlockIoTuneInfoPtr info,
+ unsigned int flags)
+{
+ int ret;
+
+ VIR_DEBUG("mon=%p, device=%p, info=%p, flags=%x",
+ mon, device, info, flags);
+
+ if (mon->json) {
+ ret = qemuMonitorJSONSetBlockIoThrottle(mon, device, info, flags);
+ } else {
+ ret = qemuMonitorTextSetBlockIoThrottle(mon, device, info, flags);
+ }
+ return ret;
+}
+
+int qemuMonitorGetBlockIoThrottle(qemuMonitorPtr mon,
+ const char *device,
+ virDomainBlockIoTuneInfoPtr reply,
+ unsigned int flags)
+{
+ int ret;
+
+ VIR_DEBUG("mon=%p, device=%p, reply=%p, flags=%x",
+ mon, device, reply, flags);
+
+ if (mon->json) {
+ ret = qemuMonitorJSONGetBlockIoThrottle(mon, device, reply, flags);
+ } else {
+ ret = qemuMonitorTextGetBlockIoThrottle(mon, device, reply, flags);
+ }
+ return ret;
+}
+
int qemuMonitorVMStatusToPausedReason(const char *status)
{
int st;
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 883e0aa..bf00068 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -521,6 +521,16 @@ int qemuMonitorOpenGraphics(qemuMonitorPtr mon,
const char *fdname,
bool skipauth);
+int qemuMonitorSetBlockIoThrottle(qemuMonitorPtr mon,
+ const char *device,
+ virDomainBlockIoTuneInfoPtr info,
+ unsigned int flags);
+
+int qemuMonitorGetBlockIoThrottle(qemuMonitorPtr mon,
+ const char *device,
+ virDomainBlockIoTuneInfoPtr reply,
+ unsigned int flags);
+
/**
* When running two dd process and using <> redirection, we need a
* shell that will not truncate files. These two strings serve that
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 56a62db..7501c59 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -3276,3 +3276,194 @@ int qemuMonitorJSONOpenGraphics(qemuMonitorPtr mon,
virJSONValueFree(reply);
return ret;
}
+
+static int
+qemuMonitorJSONBlockIoThrottleInfo(virJSONValuePtr result,
+ const char *device,
+ virDomainBlockIoTuneInfoPtr reply)
+{
+ virJSONValuePtr io_throttle;
+ int ret = -1;
+ int i;
+ int found = 0;
+
+ io_throttle = virJSONValueObjectGet(result, "return");
+
+ if (!io_throttle || io_throttle->type != VIR_JSON_TYPE_ARRAY) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _(" block_io_throttle reply was missing device list "));
+ goto cleanup;
+ }
+
+ for (i = 0; i < virJSONValueArraySize(io_throttle); i++) {
+ virJSONValuePtr temp_dev = virJSONValueArrayGet(io_throttle, i);
+ virJSONValuePtr inserted;
+ const char *current_dev;
+
+ if (!temp_dev || temp_dev->type != VIR_JSON_TYPE_OBJECT) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("block io throttle device entry was not in expected format"));
+ goto cleanup;
+ }
+
+ if ((current_dev = virJSONValueObjectGetString(temp_dev, "device")) == NULL) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("block io throttle device entry was not in expected format"));
+ goto cleanup;
+ }
+
+ if(STRPREFIX(current_dev, QEMU_DRIVE_HOST_PREFIX))
+ current_dev += strlen(QEMU_DRIVE_HOST_PREFIX);
+
+ if (STREQ(current_dev, device))
+ continue;
+
+ found = 1;
+ if ((inserted = virJSONValueObjectGet(temp_dev, "inserted")) == NULL ||
+ inserted->type != VIR_JSON_TYPE_OBJECT) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("block io throttle inserted entry was not in expected format"));
+ goto cleanup;
+ }
+
+ if (virJSONValueObjectGetNumberUlong(inserted, "bps", &reply->total_bytes_sec) < 0) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("cannot read %s"),
+ "total_bytes_sec");
+ goto cleanup;
+ }
+
+ if (virJSONValueObjectGetNumberUlong(inserted, "bps_rd", &reply->read_bytes_sec) < 0) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("cannot read %s"),
+ "read_bytes_sec");
+ goto cleanup;
+ }
+
+ if (virJSONValueObjectGetNumberUlong(inserted, "bps_wr", &reply->write_bytes_sec) < 0) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("cannot read %s"),
+ "write_bytes_sec");
+ goto cleanup;
+ }
+
+ if (virJSONValueObjectGetNumberUlong(inserted, "iops", &reply->total_iops_sec) < 0) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("cannot read %s"),
+ "total_iops_sec");
+ goto cleanup;
+ }
+
+ if (virJSONValueObjectGetNumberUlong(inserted, "iops_rd", &reply->read_iops_sec) < 0) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("cannot read %s"),
+ "read_iops_sec");
+ goto cleanup;
+ }
+
+ if (virJSONValueObjectGetNumberUlong(inserted, "iops_wr", &reply->write_iops_sec) < 0) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("cannot read %s"),
+ "write_iops_sec");
+ goto cleanup;
+ }
+ break;
+ }
+
+ if (!found) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("cannot found info for device '%s'"),
+ device);
+ goto cleanup;
+ }
+ ret = 0;
+
+cleanup:
+ return ret;
+}
+
+int qemuMonitorJSONSetBlockIoThrottle(qemuMonitorPtr mon,
+ const char *device,
+ virDomainBlockIoTuneInfoPtr info,
+ unsigned int flags)
+{
+ int ret = -1;
+ virJSONValuePtr cmd = NULL;
+ virJSONValuePtr result = NULL;
+
+ if (flags) {
+ cmd = qemuMonitorJSONMakeCommand("block_set_io_throttle",
+ "s:device", device,
+ "U:bps", info->total_bytes_sec,
+ "U:bps_rd", info->read_bytes_sec,
+ "U:bps_wr", info->write_bytes_sec,
+ "U:iops", info->total_iops_sec,
+ "U:iops_rd", info->read_iops_sec,
+ "U:iops_wr", info->write_iops_sec,
+ NULL);
+ }
+
+ if (!cmd)
+ return -1;
+
+ ret = qemuMonitorJSONCommand(mon, cmd, &result);
+
+ if (ret == 0 && virJSONValueObjectHasKey(result, "error")) {
+ if (qemuMonitorJSONHasError(result, "DeviceNotActive"))
+ qemuReportError(VIR_ERR_OPERATION_INVALID,
+ _("No active operation on device: %s"), device);
+ else if (qemuMonitorJSONHasError(result, "NotSupported"))
+ qemuReportError(VIR_ERR_OPERATION_INVALID,
+ _("Operation is not supported for device: %s"), device);
+ else
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Unexpected error"));
+ ret = -1;
+ }
+
+ virJSONValueFree(cmd);
+ virJSONValueFree(result);
+ return ret;
+}
+
+int qemuMonitorJSONGetBlockIoThrottle(qemuMonitorPtr mon,
+ const char *device,
+ virDomainBlockIoTuneInfoPtr reply,
+ unsigned int flags)
+{
+ int ret = -1;
+ virJSONValuePtr cmd = NULL;
+ virJSONValuePtr result = NULL;
+
+ if (!flags) {
+ cmd = qemuMonitorJSONMakeCommand("query-block",
+ NULL);
+ }
+
+ if (!cmd) {
+ return -1;
+ }
+
+ ret = qemuMonitorJSONCommand(mon, cmd, &result);
+
+ if (ret == 0 && virJSONValueObjectHasKey(result, "error")) {
+ if (qemuMonitorJSONHasError(result, "DeviceNotActive"))
+ qemuReportError(VIR_ERR_OPERATION_INVALID,
+ _("No active operation on device: %s"), device);
+ else if (qemuMonitorJSONHasError(result, "NotSupported"))
+ qemuReportError(VIR_ERR_OPERATION_INVALID,
+ _("Operation is not supported for device: %s"), device);
+ else
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Unexpected error"));
+ ret = -1;
+ }
+
+ if (ret == 0 && !flags)
+ ret = qemuMonitorJSONBlockIoThrottleInfo(result, device, reply);
+
+ virJSONValueFree(cmd);
+ virJSONValueFree(result);
+ return ret;
+}
+
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index f10d7d2..bf12dc5 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -255,4 +255,14 @@ int qemuMonitorJSONOpenGraphics(qemuMonitorPtr mon,
const char *fdname,
bool skipauth);
+int qemuMonitorJSONSetBlockIoThrottle(qemuMonitorPtr mon,
+ const char *device,
+ virDomainBlockIoTuneInfoPtr info,
+ unsigned int flags);
+
+int qemuMonitorJSONGetBlockIoThrottle(qemuMonitorPtr mon,
+ const char *device,
+ virDomainBlockIoTuneInfoPtr reply,
+ unsigned int flags);
+
#endif /* QEMU_MONITOR_JSON_H */
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c
index 5de4d24..5c92e60 100644
--- a/src/qemu/qemu_monitor_text.c
+++ b/src/qemu/qemu_monitor_text.c
@@ -3429,3 +3429,155 @@ cleanup:
VIR_FREE(cmd);
return ret;
}
+
+int qemuMonitorTextSetBlockIoThrottle(qemuMonitorPtr mon,
+ const char *device,
+ virDomainBlockIoTuneInfoPtr info,
+ unsigned int flags)
+{
+ char *cmd = NULL;
+ char *result = NULL;
+ int ret = 0;
+
+ if (flags) {
+ ret = virAsprintf(&cmd, "block_set_io_throttle %s %llu %llu %llu %llu %llu %llu",
+ device, info->total_bytes_sec, info->read_bytes_sec,
+ info->write_bytes_sec, info->total_iops_sec,
+ info->read_iops_sec, info->write_iops_sec);
+ }
+
+ if (ret < 0) {
+ virReportOOMError();
+ return -1;
+ }
+
+ if (qemuMonitorHMPCommand(mon, cmd, &result) < 0) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot run monitor command"));
+ ret = -1;
+ goto cleanup;
+ }
+
+cleanup:
+ VIR_FREE(cmd);
+ VIR_FREE(result);
+ return ret;
+}
+
+static int qemuMonitorTextParseBlockIoThrottle(const char *result,
+ const char *device,
+ virDomainBlockIoTuneInfoPtr reply)
+{
+ char *dummy = NULL;
+ int ret = -1;
+ const char *p, *eol;
+ int devnamelen = strlen(device);
+
+ p = result;
+
+ while (*p) {
+ if (STRPREFIX(p, QEMU_DRIVE_HOST_PREFIX))
+ p += strlen(QEMU_DRIVE_HOST_PREFIX);
+
+ if (STREQLEN(p, device, devnamelen) &&
+ p[devnamelen] == ':' && p[devnamelen+1] == ' ') {
+
+ eol = strchr(p, '\n');
+ if (!eol)
+ eol = p + strlen(p);
+
+ p += devnamelen + 2; /*Skip to first label. */
+
+ while (*p) {
+ if (STRPREFIX(p, "bps=")) {
+ p += strlen("bps=");
+ if (virStrToLong_ull(p, &dummy, 10, &reply->total_bytes_sec) == -1)
+ VIR_DEBUG("error reading total_bytes_sec: %s", p);
+ } else if (STRPREFIX(p, "bps_rd=")) {
+ p += strlen("bps_rd=");
+ if (virStrToLong_ull(p, &dummy, 10, &reply->read_bytes_sec) == -1)
+ VIR_DEBUG("error reading read_bytes_sec: %s", p);
+ } else if (STRPREFIX(p, "bps_wr=")) {
+ p += strlen("bps_wr=");
+ if (virStrToLong_ull(p, &dummy, 10, &reply->write_bytes_sec) == -1)
+ VIR_DEBUG("error reading write_bytes_sec: %s", p);
+ } else if (STRPREFIX(p, "iops=")) {
+ p += strlen("iops=");
+ if (virStrToLong_ull(p, &dummy, 10, &reply->total_iops_sec) == -1)
+ VIR_DEBUG("error reading total_iops_sec: %s", p);
+ } else if (STRPREFIX(p, "iops_rd=")) {
+ p += strlen("iops_rd=");
+ if (virStrToLong_ull(p, &dummy, 10, &reply->read_iops_sec) == -1)
+ VIR_DEBUG("error reading read_iops_sec: %s", p);
+ } else if (STRPREFIX(p, "iops_wr=")) {
+ p += strlen("iops_wr=");
+ if (virStrToLong_ull(p, &dummy, 10, &reply->write_iops_sec) == -1)
+ VIR_DEBUG("error reading write_iops_sec: %s", p);
+ } else {
+ VIR_DEBUG(" unknown block info %s", p);
+ }
+
+ /* Skip to next label. */
+ p = strchr (p, ' ');
+ if (!p || p >= eol)
+ break;
+ p++;
+ }
+ ret = 0;
+ goto cleanup;
+ }
+
+ /* Skip to next line. */
+ p = strchr (p, '\n');
+ if (!p)
+ break;
+ p++;
+ }
+
+ qemuReportError(VIR_ERR_INVALID_ARG,
+ _("no info for device '%s'"), device);
+
+cleanup:
+ return ret;
+}
+
+int qemuMonitorTextGetBlockIoThrottle(qemuMonitorPtr mon,
+ const char *device,
+ virDomainBlockIoTuneInfoPtr reply,
+ unsigned int flags)
+{
+ char *cmd = NULL;
+ char *result = NULL;
+ int ret = 0;
+
+ if (flags) {
+ ret = virAsprintf(&cmd, "info block");
+ }
+
+ if (ret < 0) {
+ virReportOOMError();
+ return -1;
+ }
+
+ if (qemuMonitorHMPCommand(mon, cmd, &result) < 0) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot run monitor command"));
+ ret = -1;
+ goto cleanup;
+ }
+
+ if (strstr(result, "\ninfo ")) {
+ qemuReportError(VIR_ERR_OPERATION_INVALID,
+ "%s",
+ _("info block not supported by this qemu"));
+ ret = -1;
+ goto cleanup;
+ }
+ ret = qemuMonitorTextParseBlockIoThrottle(result, device, reply);
+
+cleanup:
+ VIR_FREE(cmd);
+ VIR_FREE(result);
+ return ret;
+}
+
diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h
index f32fce0..1c47d39 100644
--- a/src/qemu/qemu_monitor_text.h
+++ b/src/qemu/qemu_monitor_text.h
@@ -248,4 +248,14 @@ int qemuMonitorTextOpenGraphics(qemuMonitorPtr mon,
const char *fdname,
bool skipauth);
+int qemuMonitorTextSetBlockIoThrottle(qemuMonitorPtr mon,
+ const char *device,
+ virDomainBlockIoTuneInfoPtr info,
+ unsigned int flags);
+
+int qemuMonitorTextGetBlockIoThrottle(qemuMonitorPtr mon,
+ const char *device,
+ virDomainBlockIoTuneInfoPtr reply,
+ unsigned int flags);
+
#endif /* QEMU_MONITOR_TEXT_H */
--
1.7.1
13 years
[libvirt] Problem with libvirt daemon
by Wouter - Iamotor
Hello,
I have a problem with the libvirt daemon. I have a little php script which
should connect with libvirt, but it won't.
When I try to start the libvirt daemon I get this error (using the command
libvirtd --listen):
2011-11-09 19:35:18.095: 3560: info : libvirt version: 0.9.7
2011-11-09 19:35:18.095: 3560: error : virPidFileAcquirePath:345 : Failed to
acquire pid file '/var/run/libvirtd.pid': Resource temporarily unavailable
So the daemon won't start and isn't started yet. If I check if the service
is running with ps -ef | grep libvirtd I get this output:
root 2865 1 0 15:50 ? 00:00:00 /usr/sbin/libvirtd -d
root 3149 1 0 19:17 ? 00:00:00 libvirtd -d
root 3206 1 0 19:17 ? 00:00:00 libvirtd -dl
root 3300 1 0 19:20 ? 00:00:00 libvirtd --listen --daemon
root 3356 1 0 19:21 ? 00:00:00 libvirtd --listen --daemon
root 3564 3077 0 19:36 pts/0 00:00:00 grep --color=auto libvirtd
Here you can see that the service isn't running.
How can I fix this problem. There is a .pid file in the /var/run/ directory.
I already deleted it and used the command libvirtd -daemon -listen but it
won't start. It doesn't show any output but when I use the ps -ef command, I
see that the service is not running.
Can you please help me?
With kind regards,
Wouter.
13 years
[libvirt] [PATCH 2/8] Add virDomain{Set, Get}BlockIoTune support to the remote driver
by Lei Li
Support Block I/O Throttle setting and query to remote driver.
Signed-off-by: Zhi Yong Wu <wuzhy(a)linux.vnet.ibm.com>
Signed-off-by: Lei Li <lilei(a)linux.vnet.ibm.com>
---
daemon/remote.c | 87 ++++++++++++++++++++++++++++++++++++++++++
src/remote/remote_driver.c | 80 ++++++++++++++++++++++++++++++++++++++
src/remote/remote_protocol.x | 38 ++++++++++++++++++-
src/remote_protocol-structs | 33 ++++++++++++++++
4 files changed, 237 insertions(+), 1 deletions(-)
diff --git a/daemon/remote.c b/daemon/remote.c
index bd0c3e3..070ca65 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -1850,6 +1850,93 @@ cleanup:
return rv;
}
+static int
+remoteDispatchDomainSetBlockIoThrottle(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_set_block_io_throttle_args *args)
+{
+ virDomainPtr dom = NULL;
+ virDomainBlockIoTuneInfo tmp;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ if (args) {
+ tmp.total_bytes_sec = args->bps;
+ tmp.read_bytes_sec = args->bps_rd;
+ tmp.write_bytes_sec = args->bps_wr;
+ tmp.total_iops_sec = args->iops;
+ tmp.read_iops_sec = args->iops_rd;
+ tmp.write_iops_sec = args->iops_wr;
+ }
+
+ rv = virDomainSetBlockIoTune(dom, args->disk, &tmp, args->flags);
+
+ if (rv < 0)
+ goto cleanup;
+
+cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ if (dom)
+ virDomainFree(dom);
+ return rv;
+}
+
+static int
+remoteDispatchDomainGetBlockIoThrottle(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_get_block_io_throttle_args *args,
+ remote_domain_get_block_io_throttle_ret *ret)
+{
+ virDomainPtr dom = NULL;
+ virDomainBlockIoTuneInfo reply;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ rv = virDomainGetBlockIoTune(dom, args->disk, &reply, args->flags);
+
+ if (rv < 0) {
+ ret->found = 0;
+ goto cleanup;
+ }
+
+ ret->bps = reply.total_bytes_sec;
+ ret->bps_rd = reply.read_bytes_sec;
+ ret->bps_wr = reply.write_bytes_sec;
+ ret->iops = reply.total_iops_sec;
+ ret->iops_rd = reply.read_iops_sec;
+ ret->iops_wr = reply.write_iops_sec;
+ ret->found = 1;
+
+cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ if (dom)
+ virDomainFree(dom);
+ return rv;
+}
/*-------------------------------------------------------------*/
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index f3b8ad5..0900231 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -2154,6 +2154,84 @@ done:
return rv;
}
+static int remoteDomainSetBlockIoTune(virDomainPtr domain,
+ const char *disk,
+ virDomainBlockIoTuneInfoPtr info,
+ unsigned int flags)
+{
+ int rv = -1;
+ remote_domain_set_block_io_throttle_args args;
+ struct private_data *priv = domain->conn->privateData;
+
+ remoteDriverLock(priv);
+
+ memset(&args, 0, sizeof(args));
+
+ make_nonnull_domain(&args.dom, domain);
+ args.disk = (char *)disk;
+ args.bps = info->total_bytes_sec;
+ args.bps_rd = info->read_bytes_sec;
+ args.bps_wr = info->write_bytes_sec;
+ args.iops = info->total_iops_sec;
+ args.iops_rd = info->read_iops_sec;
+ args.iops_wr = info->write_iops_sec;
+ args.flags = flags;
+
+ if (call(domain->conn, priv, 0, REMOTE_PROC_DOMAIN_SET_BLOCK_IO_THROTTLE,
+ (xdrproc_t) xdr_remote_domain_set_block_io_throttle_args,
+ (char *) &args,
+ (xdrproc_t) xdr_void,
+ (char *) NULL) == -1) {
+ goto done;
+ }
+ rv = 0;
+
+done:
+ remoteDriverUnlock(priv);
+ return rv;
+}
+
+static int remoteDomainGetBlockIoTune(virDomainPtr domain,
+ const char *disk,
+ virDomainBlockIoTuneInfoPtr reply,
+ unsigned int flags)
+{
+ int rv = -1;
+ remote_domain_get_block_io_throttle_args args;
+ remote_domain_get_block_io_throttle_ret ret;
+ struct private_data *priv = domain->conn->privateData;
+
+ remoteDriverLock(priv);
+
+ make_nonnull_domain(&args.dom, domain);
+ args.disk = (char *)disk;
+ args.flags = flags;
+
+ memset(&ret, 0, sizeof(ret));
+
+ if (call(domain->conn, priv, 0, REMOTE_PROC_DOMAIN_GET_BLOCK_IO_THROTTLE,
+ (xdrproc_t) xdr_remote_domain_get_block_io_throttle_args,
+ (char *) &args,
+ (xdrproc_t) xdr_remote_domain_get_block_io_throttle_ret,
+ (char *) &ret) == -1) {
+ goto done;
+ }
+
+ if (ret.found) {
+ reply->total_bytes_sec = ret.bps;
+ reply->read_bytes_sec = ret.bps_rd;
+ reply->write_bytes_sec = ret.bps_wr;
+ reply->total_iops_sec = ret.iops;
+ reply->read_iops_sec = ret.iops_rd;
+ reply->write_iops_sec = ret.iops_wr;
+ }
+ rv = 0;
+
+done:
+ remoteDriverUnlock(priv);
+ return rv;
+}
+
/*----------------------------------------------------------------------*/
static virDrvOpenStatus ATTRIBUTE_NONNULL (1)
@@ -4526,6 +4604,8 @@ static virDriver remote_driver = {
.domainGetBlockJobInfo = remoteDomainGetBlockJobInfo, /* 0.9.4 */
.domainBlockJobSetSpeed = remoteDomainBlockJobSetSpeed, /* 0.9.4 */
.domainBlockPull = remoteDomainBlockPull, /* 0.9.4 */
+ .domainSetBlockIoTune = remoteDomainSetBlockIoTune, /* 0.9.8 */
+ .domainGetBlockIoTune = remoteDomainGetBlockIoTune, /* 0.9.8 */
};
static virNetworkDriver network_driver = {
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index a174af8..ccc77b5 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -1073,6 +1073,40 @@ struct remote_domain_block_pull_args {
unsigned int flags;
};
+struct remote_domain_set_block_io_throttle_args {
+ remote_nonnull_domain dom;
+ remote_nonnull_string disk;
+ unsigned hyper bps;
+ unsigned hyper bps_rd;
+ unsigned hyper bps_wr;
+ unsigned hyper iops;
+ unsigned hyper iops_rd;
+ unsigned hyper iops_wr;
+ unsigned int flags;
+};
+
+struct remote_domain_get_block_io_throttle_args {
+ remote_nonnull_domain dom;
+ remote_nonnull_string disk;
+ unsigned hyper bps;
+ unsigned hyper bps_rd;
+ unsigned hyper bps_wr;
+ unsigned hyper iops;
+ unsigned hyper iops_rd;
+ unsigned hyper iops_wr;
+ unsigned int flags;
+};
+
+struct remote_domain_get_block_io_throttle_ret {
+ unsigned hyper bps;
+ unsigned hyper bps_rd;
+ unsigned hyper bps_wr;
+ unsigned hyper iops;
+ unsigned hyper iops_rd;
+ unsigned hyper iops_wr;
+ unsigned int found;
+};
+
/* Network calls: */
struct remote_num_of_networks_ret {
@@ -2562,7 +2596,9 @@ enum remote_procedure {
REMOTE_PROC_DOMAIN_SNAPSHOT_NUM_CHILDREN = 246, /* autogen autogen priority:high */
REMOTE_PROC_DOMAIN_SNAPSHOT_LIST_CHILDREN_NAMES = 247, /* autogen autogen priority:high */
REMOTE_PROC_DOMAIN_EVENT_DISK_CHANGE = 248, /* skipgen skipgen */
- REMOTE_PROC_DOMAIN_OPEN_GRAPHICS = 249 /* skipgen skipgen */
+ REMOTE_PROC_DOMAIN_OPEN_GRAPHICS = 249, /* skipgen skipgen */
+ REMOTE_PROC_DOMAIN_SET_BLOCK_IO_THROTTLE = 250, /* skipgen skipgen */
+ REMOTE_PROC_DOMAIN_GET_BLOCK_IO_THROTTLE = 251 /* skipgen skipgen */
/*
* Notice how the entries are grouped in sets of 10 ?
diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs
index 12cedef..4a813e0 100644
--- a/src/remote_protocol-structs
+++ b/src/remote_protocol-structs
@@ -757,6 +757,37 @@ struct remote_domain_block_pull_args {
uint64_t bandwidth;
u_int flags;
};
+struct remote_domain_set_block_io_throttle_args {
+ remote_nonnull_domain dom;
+ remote_nonnull_string disk;
+ uint64_t bps;
+ uint64_t bps_rd;
+ uint64_t bps_wr;
+ uint64_t iops;
+ uint64_t iops_rd;
+ uint64_t iops_wr;
+ u_int flags;
+};
+struct remote_domain_get_block_io_throttle_args {
+ remote_nonnull_domain dom;
+ remote_nonnull_string disk;
+ uint64_t bps;
+ uint64_t bps_rd;
+ uint64_t bps_wr;
+ uint64_t iops;
+ uint64_t iops_rd;
+ uint64_t iops_wr;
+ u_int flags;
+};
+struct remote_domain_get_block_io_throttle_ret {
+ uint64_t bps;
+ uint64_t bps_rd;
+ uint64_t bps_wr;
+ uint64_t iops;
+ uint64_t iops_rd;
+ uint64_t iops_wr;
+ u_int found;
+};
struct remote_num_of_networks_ret {
int num;
};
@@ -2005,4 +2036,6 @@ enum remote_procedure {
REMOTE_PROC_DOMAIN_SNAPSHOT_LIST_CHILDREN_NAMES = 247,
REMOTE_PROC_DOMAIN_EVENT_DISK_CHANGE = 248,
REMOTE_PROC_DOMAIN_OPEN_GRAPHICS = 249,
+ REMOTE_PROC_DOMAIN_SET_BLOCK_IO_THROTTLE = 250,
+ REMOTE_PROC_DOMAIN_GET_BLOCK_IO_THROTTLE = 251,
};
--
1.7.1
13 years
[libvirt] [PATCH 1/8] Add new API virDomain{Set, Get}BlockIoTune
by Lei Li
This patch add new pulic API virDomainSetBlockIoTune and
virDomainGetBlockIoTune.
Signed-off-by: Zhi Yong Wu <wuzhy(a)linux.vnet.ibm.com>
Signed-off-by: Lei Li <lilei(a)linux.vnet.ibm.com>
---
include/libvirt/libvirt.h.in | 26 +++++++++
src/driver.h | 19 +++++++
src/libvirt.c | 115 ++++++++++++++++++++++++++++++++++++++++++
src/libvirt_public.syms | 2 +
4 files changed, 162 insertions(+), 0 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index aa320b6..a79c35e 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -1640,6 +1640,32 @@ int virDomainBlockJobSetSpeed(virDomainPtr dom, const char *path,
int virDomainBlockPull(virDomainPtr dom, const char *path,
unsigned long bandwidth, unsigned int flags);
+/*
+ * Block I/O throttling support
+ */
+
+typedef struct _virDomainBlockIoTuneInfo virDomainBlockIoTuneInfo;
+struct _virDomainBlockIoTuneInfo {
+ unsigned long long total_bytes_sec;
+ unsigned long long read_bytes_sec;
+ unsigned long long write_bytes_sec;
+ unsigned long long total_iops_sec;
+ unsigned long long read_iops_sec;
+ unsigned long long write_iops_sec;
+};
+typedef virDomainBlockIoTuneInfo *virDomainBlockIoTuneInfoPtr;
+
+int
+virDomainSetBlockIoTune(virDomainPtr dom,
+ const char *disk,
+ virDomainBlockIoTuneInfoPtr info,
+ unsigned int flags);
+int
+virDomainGetBlockIoTune(virDomainPtr dom,
+ const char *disk,
+ virDomainBlockIoTuneInfoPtr reply,
+ unsigned int flags);
+
/*
* NUMA support
diff --git a/src/driver.h b/src/driver.h
index 4c14aaa..9628ad7 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -741,6 +741,23 @@ typedef int
unsigned long bandwidth, unsigned int flags);
+/*
+ * Block I/O throttling support
+ */
+
+typedef int
+ (*virDrvDomainSetBlockIoTune)(virDomainPtr dom,
+ const char *disk,
+ virDomainBlockIoTuneInfoPtr info,
+ unsigned int flags);
+
+typedef int
+ (*virDrvDomainGetBlockIoTune)(virDomainPtr dom,
+ const char *disk,
+ virDomainBlockIoTuneInfoPtr reply,
+ unsigned int flags);
+
+
/**
* _virDriver:
*
@@ -899,6 +916,8 @@ struct _virDriver {
virDrvDomainGetBlockJobInfo domainGetBlockJobInfo;
virDrvDomainBlockJobSetSpeed domainBlockJobSetSpeed;
virDrvDomainBlockPull domainBlockPull;
+ virDrvDomainSetBlockIoTune domainSetBlockIoTune;
+ virDrvDomainGetBlockIoTune domainGetBlockIoTune;
};
typedef int
diff --git a/src/libvirt.c b/src/libvirt.c
index b0d1e01..79ac84d 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -17083,3 +17083,118 @@ error:
virDispatchError(dom->conn);
return -1;
}
+
+/**
+ * virDomainSetBlockIoTune:
+ * @dom: pointer to domain object
+ * @disk: Fully-qualified disk name
+ * @info: Specify block I/O limits in bytes
+ * @flags: An OR'ed set of virDomainModificationImpact
+ *
+ * This function is mainly to enable Block I/O throttling function in libvirt.
+ * It is used to change the block I/O throttling setting for specified domain.
+ *
+ * Returns 0 if the operation has started, -1 on failure.
+ */
+int virDomainSetBlockIoTune(virDomainPtr dom,
+ const char *disk,
+ virDomainBlockIoTuneInfoPtr info,
+ unsigned int flags)
+{
+ virConnectPtr conn;
+
+ VIR_DOMAIN_DEBUG(dom, "disk=%p, info=%p, flags=%x",
+ disk, info, flags);
+
+ virResetLastError();
+
+ if (!VIR_IS_CONNECTED_DOMAIN (dom)) {
+ virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+ virDispatchError(NULL);
+ return -1;
+ }
+ conn = dom->conn;
+
+ if (dom->conn->flags & VIR_CONNECT_RO) {
+ virLibDomainError(VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+ goto error;
+ }
+
+ if (!disk) {
+ virLibDomainError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto error;
+ }
+
+ if (!info) {
+ virLibDomainError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto error;
+ }
+
+ if (conn->driver->domainSetBlockIoTune) {
+ int ret;
+ ret = conn->driver->domainSetBlockIoTune(dom, disk, info, flags);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virLibDomainError(VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+ virDispatchError(dom->conn);
+ return -1;
+}
+
+/**
+ * virDomainGetBlockIoTune:
+ * @dom: pointer to domain object
+ * @disk: Fully-qualified disk name
+ * @reply: Specify block I/O info in bytes
+ * @flags: An OR'ed set of virDomainModificationImpact
+ *
+ * This function is mainly to enable Block I/O throttling function in libvirt.
+ * It is used to get the block I/O throttling setting for specified domain.
+ *
+ * Returns 0 if the operation has started, -1 on failure.
+ */
+
+int virDomainGetBlockIoTune(virDomainPtr dom,
+ const char *disk,
+ virDomainBlockIoTuneInfoPtr reply,
+ unsigned int flags)
+{
+ virConnectPtr conn;
+
+ VIR_DOMAIN_DEBUG(dom, "disk=%p, reply=%p, flags=%x",
+ disk, reply, flags);
+
+ virResetLastError();
+
+ if (!VIR_IS_CONNECTED_DOMAIN (dom)) {
+ virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+ virDispatchError(NULL);
+ return -1;
+ }
+ conn = dom->conn;
+
+ if (!disk) {
+ virLibDomainError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto error;
+ }
+
+ if (conn->driver->domainGetBlockIoTune) {
+ int ret;
+ ret = conn->driver->domainGetBlockIoTune(dom, disk, reply, flags);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virLibDomainError(VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+ virDispatchError(dom->conn);
+ return -1;
+
+}
+
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index bcefb10..4808891 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -496,6 +496,8 @@ LIBVIRT_0.9.7 {
virDomainSnapshotGetParent;
virDomainSnapshotListChildrenNames;
virDomainSnapshotNumChildren;
+ virDomainSetBlockIoTune;
+ virDomainGetBlockIoTune;
} LIBVIRT_0.9.5;
# .... define new API here using predicted next version number ....
--
1.7.1
13 years