aboutsummaryrefslogtreecommitdiff
path: root/blockdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'blockdev.c')
-rw-r--r--blockdev.c113
1 files changed, 111 insertions, 2 deletions
diff --git a/blockdev.c b/blockdev.c
index 222818690d..dbf0251a77 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -216,6 +216,26 @@ static int parse_block_error_action(const char *buf, int is_read)
}
}
+static bool do_check_io_limits(BlockIOLimit *io_limits)
+{
+ bool bps_flag;
+ bool iops_flag;
+
+ assert(io_limits);
+
+ bps_flag = (io_limits->bps[BLOCK_IO_LIMIT_TOTAL] != 0)
+ && ((io_limits->bps[BLOCK_IO_LIMIT_READ] != 0)
+ || (io_limits->bps[BLOCK_IO_LIMIT_WRITE] != 0));
+ iops_flag = (io_limits->iops[BLOCK_IO_LIMIT_TOTAL] != 0)
+ && ((io_limits->iops[BLOCK_IO_LIMIT_READ] != 0)
+ || (io_limits->iops[BLOCK_IO_LIMIT_WRITE] != 0));
+ if (bps_flag || iops_flag) {
+ return false;
+ }
+
+ return true;
+}
+
DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
{
const char *buf;
@@ -235,7 +255,9 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
int on_read_error, on_write_error;
const char *devaddr;
DriveInfo *dinfo;
+ BlockIOLimit io_limits;
int snapshot = 0;
+ bool copy_on_read;
int ret;
translation = BIOS_ATA_TRANSLATION_AUTO;
@@ -252,6 +274,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
snapshot = qemu_opt_get_bool(opts, "snapshot", 0);
ro = qemu_opt_get_bool(opts, "readonly", 0);
+ copy_on_read = qemu_opt_get_bool(opts, "copy-on-read", false);
file = qemu_opt_get(opts, "file");
serial = qemu_opt_get(opts, "serial");
@@ -353,6 +376,26 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
}
}
+ /* disk I/O throttling */
+ io_limits.bps[BLOCK_IO_LIMIT_TOTAL] =
+ qemu_opt_get_number(opts, "bps", 0);
+ io_limits.bps[BLOCK_IO_LIMIT_READ] =
+ qemu_opt_get_number(opts, "bps_rd", 0);
+ io_limits.bps[BLOCK_IO_LIMIT_WRITE] =
+ qemu_opt_get_number(opts, "bps_wr", 0);
+ io_limits.iops[BLOCK_IO_LIMIT_TOTAL] =
+ qemu_opt_get_number(opts, "iops", 0);
+ io_limits.iops[BLOCK_IO_LIMIT_READ] =
+ qemu_opt_get_number(opts, "iops_rd", 0);
+ io_limits.iops[BLOCK_IO_LIMIT_WRITE] =
+ qemu_opt_get_number(opts, "iops_wr", 0);
+
+ if (!do_check_io_limits(&io_limits)) {
+ error_report("bps(iops) and bps_rd/bps_wr(iops_rd/iops_wr) "
+ "cannot be used at the same time");
+ return NULL;
+ }
+
on_write_error = BLOCK_ERR_STOP_ENOSPC;
if ((buf = qemu_opt_get(opts, "werror")) != NULL) {
if (type != IF_IDE && type != IF_SCSI && type != IF_VIRTIO && type != IF_NONE) {
@@ -460,6 +503,9 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
bdrv_set_on_error(dinfo->bdrv, on_read_error, on_write_error);
+ /* disk I/O throttling */
+ bdrv_set_io_limits(dinfo->bdrv, &io_limits);
+
switch(type) {
case IF_IDE:
case IF_SCSI:
@@ -502,6 +548,10 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
bdrv_flags |= (BDRV_O_SNAPSHOT|BDRV_O_CACHE_WB|BDRV_O_NO_FLUSH);
}
+ if (copy_on_read) {
+ bdrv_flags |= BDRV_O_COPY_ON_READ;
+ }
+
if (media == MEDIA_CDROM) {
/* CDROM is fine for any interface, don't check. */
ro = 1;
@@ -603,7 +653,7 @@ int do_snapshot_blkdev(Monitor *mon, const QDict *qdict, QObject **ret_data)
goto out;
}
- qemu_aio_flush();
+ bdrv_drain_all();
bdrv_flush(bs);
bdrv_close(bs);
@@ -715,6 +765,65 @@ int do_change_block(Monitor *mon, const char *device,
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)
{
const char *id = qdict_get_str(qdict, "id");
@@ -731,7 +840,7 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
}
/* quiesce block driver; prevent further io */
- qemu_aio_flush();
+ bdrv_drain_all();
bdrv_flush(bs);
bdrv_close(bs);