Re: [libvirt] [PATCH 5/8] Enable the blkdeviotune command in virsh

2011-11-23 Thread Eric Blake
On 11/15/2011 02:02 AM, Lei Li wrote:
 Support virsh command blkdeviotune. Can set or query a block disk
 I/O throttle setting.
 
 Signed-off-by: Lei Li li...@linux.vnet.ibm.com
 Signed-off-by: Zhi Yong Wu wu...@linux.vnet.ibm.com
 ---
  tools/virsh.c   |  240 
 +++
  tools/virsh.pod |   23 +
  2 files changed, 263 insertions(+), 0 deletions(-)
 

  
  /*
 + * 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)},

That's a bit long; most of our help text is one line, with the long
version left for the man page (virsh.pod).

 +{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)},

I line wrapped these.

 +
 +for (i = 0; i  nparams; i++) {
 +switch(params[i].type) {
 +case VIR_TYPED_PARAM_INT:
 +vshPrint(ctl, %-15s: %d\n, params[i].field,
 + params[i].value.i);
 +break;

This feels like code duplication that we should factor out in a future
patch, but it doesn't matter for this one.

 +
 +virDomainFree(dom);
 +return true;

Memory leak - you need to free params.

 +} else {
 +/* Set the block I/O throttle, match by opt since parameters can be 
 0 */
 +params = vshCalloc(ctl, nparams, sizeof(*params));
 +i = 0;
 +

 +if ((virDomainSetBlockIoTune(dom, disk, params, nparams, flags)) != 
 0) {
 +vshError(ctl, %s,
 + _(Unable to change block I/O throttle));
 +goto out;
 +} else {
 +virDomainFree(dom);
 +return true;

Same leak.

 @@ -14023,6 +14262,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},

Sorting.

 +++ b/tools/virsh.pod
 @@ -572,6 +572,29 @@ operation can be checked with Bblockjob.
  Ipath specifies fully-qualified path of the disk.
  Ibandwidth specifies copying bandwidth limit in Mbps.
  
 +=item Bblkdeviotune Idomain Idevice [[I--total_bytes_sec 
 Btotal_bytes_sec]
 +| [[I--read_bytes_sec Bread_bytes_sec] [I--write_bytes_sec 
 Bwrite_bytes_sec]]
 +[[I--total_iops_sec Btotal_iops_sec] | [[I--read_iops_sec 
 Bread_iops_sec]
 +[I--write_iops_sec Bwrite_iops_sec]] [[I--config] [I--live] | 
 [I--current]]

This reads long; I shortened it to Iop instead of I--op Bop.

 +
 +Set or query the block disk io limits settting.

s/settting/setting/

 +Ipath specifies block disk name.

I copied text from domblkstat here.

 +I--total_bytes_sec specifies total throughput limit in bytes per second.
 +I--read_bytes_sec specifies read throughput limit in bytes per second.
 +I--write_bytes_sec specifies write throughput limit in bytes per second.
 +I--total_iops_sec specifies total I/O operations limit per second.
 +I--read_iops_sec specifies read I/O operations limit per second.
 +I--write_iops_sec specifies write I/O operations limit per second.

Needs to mention the restriction on total vs. read/write, also on the
handling of 0: it is necessary to specify at least one flag as explicit
0 to clear limits, otherwise you are just querying limits; and per my
comments in 4/8, the current behavior clears the remaining 5 limits when
one limit is set, although we may find it desirable to instead leave
limits unchanged if they are not specified.

 +
 +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.

This line belongs earlier.

Here's what I'm squashing:

diff --git i/tools/virsh.c w/tools/virsh.c
index eb8c0b6..ea5a267 100644
--- i/tools/virsh.c
+++ w/tools/virsh.c
@@ -6079,23 +6079,26 @@ cmdNetworkAutostart(vshControl *ctl, const
vshCmd *cmd)
  * blkdeviotune command
  */
 static const vshCmdInfo info_blkdeviotune[] = {
-{help, N_(Set or query a block disk I/O throttle setting.)},
-{desc, N_(Set or query 

[libvirt] [PATCH 5/8] Enable the blkdeviotune command in virsh

2011-11-15 Thread Lei Li
Support virsh command blkdeviotune. Can set or query a block disk
I/O throttle setting.

Signed-off-by: Lei Li li...@linux.vnet.ibm.com
Signed-off-by: Zhi Yong Wu wu...@linux.vnet.ibm.com
---
 tools/virsh.c   |  240 +++
 tools/virsh.pod |   23 +
 2 files changed, 263 insertions(+), 0 deletions(-)

diff --git a/tools/virsh.c b/tools/virsh.c
index 83dc3c7..9eec68e 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -6074,6 +6074,245 @@ cmdNetworkAutostart(vshControl *ctl, const vshCmd *cmd)
 }
 
 /*
+ * 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)},
+{read_bytes_sec, VSH_OT_INT, VSH_OFLAG_NONE, N_(read throughput limit 
in bytes per second)},
+{write_bytes_sec, VSH_OT_INT, VSH_OFLAG_NONE, N_(write throughput limit 
in bytes per second)},
+{total_iops_sec, VSH_OT_INT, VSH_OFLAG_NONE, N_(total I/O operations 
limit per second)},
+{read_iops_sec, VSH_OT_INT, VSH_OFLAG_NONE, N_(read I/O operations 
limit per second)},
+{write_iops_sec, VSH_OT_INT, VSH_OFLAG_NONE, N_(write I/O operations 
limit per second)},
+{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;
+unsigned long long total_bytes_sec = 0, read_bytes_sec = 0, 
write_bytes_sec = 0;
+unsigned long long total_iops_sec = 0, read_iops_sec = 0, write_iops_sec = 
0;
+int nparams = 0;
+virTypedParameterPtr params = NULL, temp = NULL;
+unsigned int flags = 0, i = 0;
+int rv = 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;
+}
+
+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, 
total_bytes_sec))  0) {
+vshError(ctl, %s,
+ _(Unable to parse integer parameter));
+goto out;
+} else if (rv  0) {
+nparams++;
+}
+
+if ((rv = vshCommandOptULongLong(cmd, read_bytes_sec, read_bytes_sec)) 
 0) {
+vshError(ctl, %s,
+ _(Unable to parse integer parameter));
+goto out;
+} else if (rv  0) {
+nparams++;
+}
+
+if ((rv = vshCommandOptULongLong(cmd, write_bytes_sec, 
write_bytes_sec))  0) {
+vshError(ctl, %s,
+ _(Unable to parse integer parameter));
+goto out;
+} else if (rv  0) {
+nparams++;
+}
+
+if ((rv = vshCommandOptULongLong(cmd, total_iops_sec, total_iops_sec)) 
 0) {
+vshError(ctl, %s,
+ _(Unable to parse integer parameter));
+goto out;
+} else if (rv  0) {
+nparams++;
+}
+
+if ((rv = vshCommandOptULongLong(cmd, read_iops_sec, read_iops_sec))  
0) {
+vshError(ctl, %s,
+ _(Unable to parse integer parameter));
+goto out;
+} else if (rv  0) {
+nparams++;
+}
+
+if ((rv = vshCommandOptULongLong(cmd, write_iops_sec, write_iops_sec)) 
 0) {
+vshError(ctl, %s,
+ _(Unable to parse integer parameter));
+goto out;
+} else if (rv  0) {
+nparams++;
+}
+
+if (nparams == 0) {
+
+if ((virDomainGetBlockIoTune(dom, disk, NULL, nparams, flags)) != 0) {
+vshError(ctl, %s,
+ _(Unable to get number of block I/O throttle 
parameters));
+goto out;
+}
+
+if (nparams == 0) {
+virDomainFree(dom);
+return true;
+}
+
+params = vshCalloc(ctl, nparams, sizeof(*params));
+
+if 

[libvirt] [PATCH 5/8] Enable the blkdeviotune command in virsh

2011-11-14 Thread Lei Li
Support virsh command blkdeviotune. Can set or query a block disk
I/O throttle setting.

Signed-off-by: Lei Li li...@linux.vnet.ibm.com
Signed-off-by: Zhi Yong Wu wu...@linux.vnet.ibm.com
---
 tools/virsh.c   |  240 +++
 tools/virsh.pod |   23 +
 2 files changed, 263 insertions(+), 0 deletions(-)

diff --git a/tools/virsh.c b/tools/virsh.c
index 83dc3c7..9eec68e 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -6074,6 +6074,245 @@ cmdNetworkAutostart(vshControl *ctl, const vshCmd *cmd)
 }
 
 /*
+ * 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)},
+{read_bytes_sec, VSH_OT_INT, VSH_OFLAG_NONE, N_(read throughput limit 
in bytes per second)},
+{write_bytes_sec, VSH_OT_INT, VSH_OFLAG_NONE, N_(write throughput limit 
in bytes per second)},
+{total_iops_sec, VSH_OT_INT, VSH_OFLAG_NONE, N_(total I/O operations 
limit per second)},
+{read_iops_sec, VSH_OT_INT, VSH_OFLAG_NONE, N_(read I/O operations 
limit per second)},
+{write_iops_sec, VSH_OT_INT, VSH_OFLAG_NONE, N_(write I/O operations 
limit per second)},
+{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;
+unsigned long long total_bytes_sec = 0, read_bytes_sec = 0, 
write_bytes_sec = 0;
+unsigned long long total_iops_sec = 0, read_iops_sec = 0, write_iops_sec = 
0;
+int nparams = 0;
+virTypedParameterPtr params = NULL, temp = NULL;
+unsigned int flags = 0, i = 0;
+int rv = 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;
+}
+
+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, 
total_bytes_sec))  0) {
+vshError(ctl, %s,
+ _(Unable to parse integer parameter));
+goto out;
+} else if (rv  0) {
+nparams++;
+}
+
+if ((rv = vshCommandOptULongLong(cmd, read_bytes_sec, read_bytes_sec)) 
 0) {
+vshError(ctl, %s,
+ _(Unable to parse integer parameter));
+goto out;
+} else if (rv  0) {
+nparams++;
+}
+
+if ((rv = vshCommandOptULongLong(cmd, write_bytes_sec, 
write_bytes_sec))  0) {
+vshError(ctl, %s,
+ _(Unable to parse integer parameter));
+goto out;
+} else if (rv  0) {
+nparams++;
+}
+
+if ((rv = vshCommandOptULongLong(cmd, total_iops_sec, total_iops_sec)) 
 0) {
+vshError(ctl, %s,
+ _(Unable to parse integer parameter));
+goto out;
+} else if (rv  0) {
+nparams++;
+}
+
+if ((rv = vshCommandOptULongLong(cmd, read_iops_sec, read_iops_sec))  
0) {
+vshError(ctl, %s,
+ _(Unable to parse integer parameter));
+goto out;
+} else if (rv  0) {
+nparams++;
+}
+
+if ((rv = vshCommandOptULongLong(cmd, write_iops_sec, write_iops_sec)) 
 0) {
+vshError(ctl, %s,
+ _(Unable to parse integer parameter));
+goto out;
+} else if (rv  0) {
+nparams++;
+}
+
+if (nparams == 0) {
+
+if ((virDomainGetBlockIoTune(dom, disk, NULL, nparams, flags)) != 0) {
+vshError(ctl, %s,
+ _(Unable to get number of block I/O throttle 
parameters));
+goto out;
+}
+
+if (nparams == 0) {
+virDomainFree(dom);
+return true;
+}
+
+params = vshCalloc(ctl, nparams, sizeof(*params));
+
+if 

Re: [libvirt] [PATCH 5/8] Enable the blkdeviotune command in virsh

2011-11-10 Thread Adam Litke
OK.

On Thu, Nov 10, 2011 at 04:32:55AM +0800, Lei HH Li wrote:
 Support virsh command blkdeviotune. Can set or query a block disk 
 I/O throttle setting.
 
 Signed-off-by: Zhi Yong Wu wu...@linux.vnet.ibm.com
 Signed-off-by: Lei Li li...@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);
 +

[libvirt] [PATCH 5/8] Enable the blkdeviotune command in virsh

2011-11-09 Thread Lei Li
Support virsh command blkdeviotune. Can set or query a block disk 
I/O throttle setting.

Signed-off-by: Zhi Yong Wu wu...@linux.vnet.ibm.com
Signed-off-by: Lei Li li...@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:),