hmp/qmp: add block_set_io_throttle

Signed-off-by: Zhi Yong Wu <wuzhy@linux.vnet.ibm.com>
Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
Zhi Yong Wu 2011-11-08 13:00:31 +08:00 committed by Kevin Wolf
parent 98f90dba5e
commit 727f005e6a
9 changed files with 175 additions and 2 deletions

15
block.c
View File

@ -1978,6 +1978,21 @@ BlockInfoList *qmp_query_block(Error **errp)
info->value->inserted->has_backing_file = true; info->value->inserted->has_backing_file = true;
info->value->inserted->backing_file = g_strdup(bs->backing_file); info->value->inserted->backing_file = g_strdup(bs->backing_file);
} }
if (bs->io_limits_enabled) {
info->value->inserted->bps =
bs->io_limits.bps[BLOCK_IO_LIMIT_TOTAL];
info->value->inserted->bps_rd =
bs->io_limits.bps[BLOCK_IO_LIMIT_READ];
info->value->inserted->bps_wr =
bs->io_limits.bps[BLOCK_IO_LIMIT_WRITE];
info->value->inserted->iops =
bs->io_limits.iops[BLOCK_IO_LIMIT_TOTAL];
info->value->inserted->iops_rd =
bs->io_limits.iops[BLOCK_IO_LIMIT_READ];
info->value->inserted->iops_wr =
bs->io_limits.iops[BLOCK_IO_LIMIT_WRITE];
}
} }
/* XXX: waiting for the qapi to support GSList */ /* XXX: waiting for the qapi to support GSList */

View File

@ -759,6 +759,65 @@ int do_change_block(Monitor *mon, const char *device,
return monitor_read_bdrv_key_start(mon, bs, NULL, NULL); return monitor_read_bdrv_key_start(mon, bs, NULL, NULL);
} }
/* throttling disk I/O limits */
int do_block_set_io_throttle(Monitor *mon,
const QDict *qdict, QObject **ret_data)
{
BlockIOLimit io_limits;
const char *devname = qdict_get_str(qdict, "device");
BlockDriverState *bs;
io_limits.bps[BLOCK_IO_LIMIT_TOTAL]
= qdict_get_try_int(qdict, "bps", -1);
io_limits.bps[BLOCK_IO_LIMIT_READ]
= qdict_get_try_int(qdict, "bps_rd", -1);
io_limits.bps[BLOCK_IO_LIMIT_WRITE]
= qdict_get_try_int(qdict, "bps_wr", -1);
io_limits.iops[BLOCK_IO_LIMIT_TOTAL]
= qdict_get_try_int(qdict, "iops", -1);
io_limits.iops[BLOCK_IO_LIMIT_READ]
= qdict_get_try_int(qdict, "iops_rd", -1);
io_limits.iops[BLOCK_IO_LIMIT_WRITE]
= qdict_get_try_int(qdict, "iops_wr", -1);
bs = bdrv_find(devname);
if (!bs) {
qerror_report(QERR_DEVICE_NOT_FOUND, devname);
return -1;
}
if ((io_limits.bps[BLOCK_IO_LIMIT_TOTAL] == -1)
|| (io_limits.bps[BLOCK_IO_LIMIT_READ] == -1)
|| (io_limits.bps[BLOCK_IO_LIMIT_WRITE] == -1)
|| (io_limits.iops[BLOCK_IO_LIMIT_TOTAL] == -1)
|| (io_limits.iops[BLOCK_IO_LIMIT_READ] == -1)
|| (io_limits.iops[BLOCK_IO_LIMIT_WRITE] == -1)) {
qerror_report(QERR_MISSING_PARAMETER,
"bps/bps_rd/bps_wr/iops/iops_rd/iops_wr");
return -1;
}
if (!do_check_io_limits(&io_limits)) {
qerror_report(QERR_INVALID_PARAMETER_COMBINATION);
return -1;
}
bs->io_limits = io_limits;
bs->slice_time = BLOCK_IO_SLICE_TIME;
if (!bs->io_limits_enabled && bdrv_io_limits_enabled(bs)) {
bdrv_io_limits_enable(bs);
} else if (bs->io_limits_enabled && !bdrv_io_limits_enabled(bs)) {
bdrv_io_limits_disable(bs);
} else {
if (bs->block_timer) {
qemu_mod_timer(bs->block_timer, qemu_get_clock_ns(vm_clock));
}
}
return 0;
}
int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data) int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
{ {
const char *id = qdict_get_str(qdict, "id"); const char *id = qdict_get_str(qdict, "id");

View File

@ -63,6 +63,8 @@ int do_block_set_passwd(Monitor *mon, const QDict *qdict, QObject **ret_data);
int do_change_block(Monitor *mon, const char *device, int do_change_block(Monitor *mon, const char *device,
const char *filename, const char *fmt); const char *filename, const char *fmt);
int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data); int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data);
int do_block_set_io_throttle(Monitor *mon,
const QDict *qdict, QObject **ret_data);
int do_snapshot_blkdev(Monitor *mon, const QDict *qdict, QObject **ret_data); int do_snapshot_blkdev(Monitor *mon, const QDict *qdict, QObject **ret_data);
int do_block_resize(Monitor *mon, const QDict *qdict, QObject **ret_data); int do_block_resize(Monitor *mon, const QDict *qdict, QObject **ret_data);

View File

@ -1206,6 +1206,21 @@ ETEXI
.mhandler.cmd_new = do_block_set_passwd, .mhandler.cmd_new = do_block_set_passwd,
}, },
STEXI
@item block_set_io_throttle @var{device} @var{bps} @var{bps_rd} @var{bps_wr} @var{iops} @var{iops_rd} @var{iops_wr}
@findex block_set_io_throttle
Change I/O throttle limits for a block drive to @var{bps} @var{bps_rd} @var{bps_wr} @var{iops} @var{iops_rd} @var{iops_wr}
ETEXI
{
.name = "block_set_io_throttle",
.args_type = "device:B,bps:l,bps_rd:l,bps_wr:l,iops:l,iops_rd:l,iops_wr:l",
.params = "device bps bps_rd bps_wr iops iops_rd iops_wr",
.help = "change I/O throttle limits for a block drive",
.user_print = monitor_user_noop,
.mhandler.cmd_new = do_block_set_io_throttle,
},
STEXI STEXI
@item block_passwd @var{device} @var{password} @item block_passwd @var{device} @var{password}
@findex block_passwd @findex block_passwd

10
hmp.c
View File

@ -216,6 +216,16 @@ void hmp_info_block(Monitor *mon)
info->value->inserted->ro, info->value->inserted->ro,
info->value->inserted->drv, info->value->inserted->drv,
info->value->inserted->encrypted); info->value->inserted->encrypted);
monitor_printf(mon, " bps=%" PRId64 " bps_rd=%" PRId64
" bps_wr=%" PRId64 " iops=%" PRId64
" iops_rd=%" PRId64 " iops_wr=%" PRId64,
info->value->inserted->bps,
info->value->inserted->bps_rd,
info->value->inserted->bps_wr,
info->value->inserted->iops,
info->value->inserted->iops_rd,
info->value->inserted->iops_wr);
} else { } else {
monitor_printf(mon, " [not inserted]"); monitor_printf(mon, " [not inserted]");
} }

View File

@ -370,13 +370,27 @@
# #
# @encrypted: true if the backing device is encrypted # @encrypted: true if the backing device is encrypted
# #
# @bps: total throughput limit in bytes per second is specified
#
# @bps_rd: read throughput limit in bytes per second is specified
#
# @bps_wr: write throughput limit in bytes per second is specified
#
# @iops: total I/O operations per second is specified
#
# @iops_rd: read I/O operations per second is specified
#
# @iops_wr: write I/O operations per second is specified
#
# Since: 0.14.0 # Since: 0.14.0
# #
# Notes: This interface is only found in @BlockInfo. # Notes: This interface is only found in @BlockInfo.
## ##
{ 'type': 'BlockDeviceInfo', { 'type': 'BlockDeviceInfo',
'data': { 'file': 'str', 'ro': 'bool', 'drv': 'str', 'data': { 'file': 'str', 'ro': 'bool', 'drv': 'str',
'*backing_file': 'str', 'encrypted': 'bool' } } '*backing_file': 'str', 'encrypted': 'bool',
'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int'} }
## ##
# @BlockDeviceIoStatus: # @BlockDeviceIoStatus:

View File

@ -246,6 +246,10 @@ static const QErrorStringTable qerror_table[] = {
.error_fmt = QERR_QGA_COMMAND_FAILED, .error_fmt = QERR_QGA_COMMAND_FAILED,
.desc = "Guest agent command failed, error was '%(message)'", .desc = "Guest agent command failed, error was '%(message)'",
}, },
{
.error_fmt = QERR_INVALID_PARAMETER_COMBINATION,
.desc = "Invalid paramter combination",
},
{} {}
}; };

View File

@ -204,4 +204,7 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_QGA_COMMAND_FAILED \ #define QERR_QGA_COMMAND_FAILED \
"{ 'class': 'QgaCommandFailed', 'data': { 'message': %s } }" "{ 'class': 'QgaCommandFailed', 'data': { 'message': %s } }"
#define QERR_INVALID_PARAMETER_COMBINATION \
"{ 'class': 'InvalidParameterCombination', 'data': {} }"
#endif /* QERROR_H */ #endif /* QERROR_H */

View File

@ -848,6 +848,44 @@ Example:
"password": "12345" } } "password": "12345" } }
<- { "return": {} } <- { "return": {} }
EQMP
{
.name = "block_set_io_throttle",
.args_type = "device:B,bps:l,bps_rd:l,bps_wr:l,iops:l,iops_rd:l,iops_wr:l",
.params = "device bps bps_rd bps_wr iops iops_rd iops_wr",
.help = "change I/O throttle limits for a block drive",
.user_print = monitor_user_noop,
.mhandler.cmd_new = do_block_set_io_throttle,
},
SQMP
block_set_io_throttle
------------
Change I/O throttle limits for a block drive.
Arguments:
- "device": device name (json-string)
- "bps": total throughput limit in bytes per second(json-int)
- "bps_rd": read throughput limit in bytes per second(json-int)
- "bps_wr": read throughput limit in bytes per second(json-int)
- "iops": total I/O operations per second(json-int)
- "iops_rd": read I/O operations per second(json-int)
- "iops_wr": write I/O operations per second(json-int)
Example:
-> { "execute": "block_set_io_throttle", "arguments": { "device": "virtio0",
"bps": "1000000",
"bps_rd": "0",
"bps_wr": "0",
"iops": "0",
"iops_rd": "0",
"iops_wr": "0" } }
<- { "return": {} }
EQMP EQMP
{ {
@ -1152,6 +1190,13 @@ Each json-object contain the following:
"tftp", "vdi", "vmdk", "vpc", "vvfat" "tftp", "vdi", "vmdk", "vpc", "vvfat"
- "backing_file": backing file name (json-string, optional) - "backing_file": backing file name (json-string, optional)
- "encrypted": true if encrypted, false otherwise (json-bool) - "encrypted": true if encrypted, false otherwise (json-bool)
- "bps": limit total bytes per second (json-int)
- "bps_rd": limit read bytes per second (json-int)
- "bps_wr": limit write bytes per second (json-int)
- "iops": limit total I/O operations per second (json-int)
- "iops_rd": limit read operations per second (json-int)
- "iops_wr": limit write operations per second (json-int)
- "io-status": I/O operation status, only present if the device supports it - "io-status": I/O operation status, only present if the device supports it
and the VM is configured to stop on errors. It's always reset and the VM is configured to stop on errors. It's always reset
to "ok" when the "cont" command is issued (json_string, optional) to "ok" when the "cont" command is issued (json_string, optional)
@ -1171,7 +1216,13 @@ Example:
"ro":false, "ro":false,
"drv":"qcow2", "drv":"qcow2",
"encrypted":false, "encrypted":false,
"file":"disks/test.img" "file":"disks/test.img",
"bps":1000000,
"bps_rd":0,
"bps_wr":0,
"iops":1000000,
"iops_rd":0,
"iops_wr":0,
}, },
"type":"unknown" "type":"unknown"
}, },