mirror of https://github.com/xemu-project/xemu.git
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:
parent
98f90dba5e
commit
727f005e6a
15
block.c
15
block.c
|
@ -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 */
|
||||||
|
|
59
blockdev.c
59
blockdev.c
|
@ -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");
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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
10
hmp.c
|
@ -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]");
|
||||||
}
|
}
|
||||||
|
|
|
@ -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:
|
||||||
|
|
4
qerror.c
4
qerror.c
|
@ -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",
|
||||||
|
},
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
3
qerror.h
3
qerror.h
|
@ -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 */
|
||||||
|
|
|
@ -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"
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue