diff options
Diffstat (limited to 'blockdev.c')
-rw-r--r-- | blockdev.c | 202 |
1 files changed, 145 insertions, 57 deletions
diff --git a/blockdev.c b/blockdev.c index 222818690d..c832782d03 100644 --- a/blockdev.c +++ b/blockdev.c @@ -15,6 +15,7 @@ #include "qemu-config.h" #include "sysemu.h" #include "block_int.h" +#include "qmp-commands.h" static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives); @@ -216,6 +217,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 +256,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 +275,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 +377,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 +504,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 +549,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; @@ -550,28 +601,20 @@ void do_commit(Monitor *mon, const QDict *qdict) } } -int do_snapshot_blkdev(Monitor *mon, const QDict *qdict, QObject **ret_data) +void qmp_blockdev_snapshot_sync(const char *device, const char *snapshot_file, + bool has_format, const char *format, + Error **errp) { - const char *device = qdict_get_str(qdict, "device"); - const char *filename = qdict_get_try_str(qdict, "snapshot-file"); - const char *format = qdict_get_try_str(qdict, "format"); BlockDriverState *bs; BlockDriver *drv, *old_drv, *proto_drv; int ret = 0; int flags; char old_filename[1024]; - if (!filename) { - qerror_report(QERR_MISSING_PARAMETER, "snapshot-file"); - ret = -1; - goto out; - } - bs = bdrv_find(device); if (!bs) { - qerror_report(QERR_DEVICE_NOT_FOUND, device); - ret = -1; - goto out; + error_set(errp, QERR_DEVICE_NOT_FOUND, device); + return; } pstrcpy(old_filename, sizeof(old_filename), bs->filename); @@ -579,35 +622,34 @@ int do_snapshot_blkdev(Monitor *mon, const QDict *qdict, QObject **ret_data) old_drv = bs->drv; flags = bs->open_flags; - if (!format) { + if (!has_format) { format = "qcow2"; } drv = bdrv_find_format(format); if (!drv) { - qerror_report(QERR_INVALID_BLOCK_FORMAT, format); - ret = -1; - goto out; + error_set(errp, QERR_INVALID_BLOCK_FORMAT, format); + return; } - proto_drv = bdrv_find_protocol(filename); + proto_drv = bdrv_find_protocol(snapshot_file); if (!proto_drv) { - qerror_report(QERR_INVALID_BLOCK_FORMAT, format); - ret = -1; - goto out; + error_set(errp, QERR_INVALID_BLOCK_FORMAT, format); + return; } - ret = bdrv_img_create(filename, format, bs->filename, + ret = bdrv_img_create(snapshot_file, format, bs->filename, bs->drv->format_name, NULL, -1, flags); if (ret) { - goto out; + error_set(errp, QERR_UNDEFINED_ERROR); + return; } - qemu_aio_flush(); + bdrv_drain_all(); bdrv_flush(bs); bdrv_close(bs); - ret = bdrv_open(bs, filename, flags, drv); + ret = bdrv_open(bs, snapshot_file, flags, drv); /* * If reopening the image file we just created fails, fall back * and try to re-open the original image. If that fails too, we @@ -616,17 +658,11 @@ int do_snapshot_blkdev(Monitor *mon, const QDict *qdict, QObject **ret_data) if (ret != 0) { ret = bdrv_open(bs, old_filename, flags, old_drv); if (ret != 0) { - qerror_report(QERR_OPEN_FILE_FAILED, old_filename); + error_set(errp, QERR_OPEN_FILE_FAILED, old_filename); } else { - qerror_report(QERR_OPEN_FILE_FAILED, filename); + error_set(errp, QERR_OPEN_FILE_FAILED, snapshot_file); } } -out: - if (ret) { - ret = -1; - } - - return ret; } static int eject_device(Monitor *mon, BlockDriverState *bs, int force) @@ -660,28 +696,25 @@ int do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data) return eject_device(mon, bs, force); } -int do_block_set_passwd(Monitor *mon, const QDict *qdict, - QObject **ret_data) +void qmp_block_passwd(const char *device, const char *password, Error **errp) { BlockDriverState *bs; int err; - bs = bdrv_find(qdict_get_str(qdict, "device")); + bs = bdrv_find(device); if (!bs) { - qerror_report(QERR_DEVICE_NOT_FOUND, qdict_get_str(qdict, "device")); - return -1; + error_set(errp, QERR_DEVICE_NOT_FOUND, device); + return; } - err = bdrv_set_key(bs, qdict_get_str(qdict, "password")); + err = bdrv_set_key(bs, password); if (err == -EINVAL) { - qerror_report(QERR_DEVICE_NOT_ENCRYPTED, bdrv_get_device_name(bs)); - return -1; + error_set(errp, QERR_DEVICE_NOT_ENCRYPTED, bdrv_get_device_name(bs)); + return; } else if (err < 0) { - qerror_report(QERR_INVALID_PASSWORD); - return -1; + error_set(errp, QERR_INVALID_PASSWORD); + return; } - - return 0; } int do_change_block(Monitor *mon, const char *device, @@ -715,6 +748,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 +823,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); @@ -754,27 +846,23 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data) * existing QERR_ macro mess is cleaned up. A good example for better * error reports can be found in the qemu-img resize code. */ -int do_block_resize(Monitor *mon, const QDict *qdict, QObject **ret_data) +void qmp_block_resize(const char *device, int64_t size, Error **errp) { - const char *device = qdict_get_str(qdict, "device"); - int64_t size = qdict_get_int(qdict, "size"); BlockDriverState *bs; bs = bdrv_find(device); if (!bs) { - qerror_report(QERR_DEVICE_NOT_FOUND, device); - return -1; + error_set(errp, QERR_DEVICE_NOT_FOUND, device); + return; } if (size < 0) { - qerror_report(QERR_UNDEFINED_ERROR); - return -1; + error_set(errp, QERR_UNDEFINED_ERROR); + return; } if (bdrv_truncate(bs, size)) { - qerror_report(QERR_UNDEFINED_ERROR); - return -1; + error_set(errp, QERR_UNDEFINED_ERROR); + return; } - - return 0; } |