#include "sysemu/blockdev.h"
#include "hw/block/block.h"
#include "block/blockjob.h"
+#include "block/throttle-groups.h"
#include "monitor/monitor.h"
+#include "qemu/error-report.h"
#include "qemu/option.h"
#include "qemu/config-file.h"
#include "qapi/qmp/types.h"
#include "qapi-visit.h"
+#include "qapi/qmp/qerror.h"
#include "qapi/qmp-output-visitor.h"
#include "qapi/util.h"
#include "sysemu/sysemu.h"
QemuOpts *drive_def(const char *optstr)
{
- return qemu_opts_parse(qemu_find_opts("drive"), optstr, 0);
+ return qemu_opts_parse_noisily(qemu_find_opts("drive"), optstr, false);
}
QemuOpts *drive_add(BlockInterfaceType type, int index, const char *file,
return false;
}
+ if (throttle_max_is_missing_limit(cfg)) {
+ error_setg(errp, "bps_max/iops_max require corresponding"
+ " bps/iops values");
+ return false;
+ }
+
return true;
}
const char *id;
bool has_driver_specific_opts;
BlockdevDetectZeroesOptions detect_zeroes;
+ const char *throttling_group;
/* Check common options by copying from bs_opts to opts, all other options
* stay in bs_opts for processing by bdrv_open(). */
}
}
- if (qemu_opt_get_bool(opts, "cache.writeback", true)) {
+ if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_WB, true)) {
bdrv_flags |= BDRV_O_CACHE_WB;
}
- if (qemu_opt_get_bool(opts, "cache.direct", false)) {
+ if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_DIRECT, false)) {
bdrv_flags |= BDRV_O_NOCACHE;
}
- if (qemu_opt_get_bool(opts, "cache.no-flush", false)) {
+ if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_NO_FLUSH, false)) {
bdrv_flags |= BDRV_O_NO_FLUSH;
}
cfg.op_size = qemu_opt_get_number(opts, "throttling.iops-size", 0);
+ throttling_group = qemu_opt_get(opts, "throttling.group");
+
if (!check_throttle_config(&cfg, &error)) {
error_propagate(errp, error);
goto early_err;
/* disk I/O throttling */
if (throttle_enabled(&cfg)) {
- bdrv_io_limits_enable(bs);
+ if (!throttling_group) {
+ throttling_group = blk_name(blk);
+ }
+ bdrv_io_limits_enable(bs, throttling_group);
bdrv_set_io_limits(bs, &cfg);
}
{ "iops_size", "throttling.iops-size" },
+ { "group", "throttling.group" },
+
{ "readonly", "read-only" },
};
}
/* Specific options take precedence */
- if (!qemu_opt_get(all_opts, "cache.writeback")) {
- qemu_opt_set_bool(all_opts, "cache.writeback",
+ if (!qemu_opt_get(all_opts, BDRV_OPT_CACHE_WB)) {
+ qemu_opt_set_bool(all_opts, BDRV_OPT_CACHE_WB,
!!(flags & BDRV_O_CACHE_WB), &error_abort);
}
- if (!qemu_opt_get(all_opts, "cache.direct")) {
- qemu_opt_set_bool(all_opts, "cache.direct",
+ if (!qemu_opt_get(all_opts, BDRV_OPT_CACHE_DIRECT)) {
+ qemu_opt_set_bool(all_opts, BDRV_OPT_CACHE_DIRECT,
!!(flags & BDRV_O_NOCACHE), &error_abort);
}
- if (!qemu_opt_get(all_opts, "cache.no-flush")) {
- qemu_opt_set_bool(all_opts, "cache.no-flush",
+ if (!qemu_opt_get(all_opts, BDRV_OPT_CACHE_NO_FLUSH)) {
+ qemu_opt_set_bool(all_opts, BDRV_OPT_CACHE_NO_FLUSH,
!!(flags & BDRV_O_NO_FLUSH), &error_abort);
}
qemu_opt_unset(all_opts, "cache");
devopts = qemu_opts_create(qemu_find_opts("device"), NULL, 0,
&error_abort);
if (arch_type == QEMU_ARCH_S390X) {
- qemu_opt_set(devopts, "driver", "virtio-blk-s390", &error_abort);
+ qemu_opt_set(devopts, "driver", "virtio-blk-ccw", &error_abort);
} else {
qemu_opt_set(devopts, "driver", "virtio-blk-pci", &error_abort);
}
blk = blk_by_name(device);
if (!blk) {
- error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+ "Device '%s' not found", device);
return NULL;
}
bs = blk_bs(blk);
/* 2. check for validation */
blk = blk_by_name(device);
if (!blk) {
- error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+ "Device '%s' not found", device);
return;
}
bs = blk_bs(blk);
aio_context_acquire(state->aio_context);
if (!bdrv_is_inserted(bs)) {
- error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
+ error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
return;
}
static void external_snapshot_prepare(BlkTransactionState *common,
Error **errp)
{
- BlockDriver *drv;
int flags, ret;
- QDict *options = NULL;
+ QDict *options;
Error *local_err = NULL;
bool has_device = false;
const char *device;
}
/* start processing */
- drv = bdrv_find_format(format);
- if (!drv) {
- error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
- return;
- }
-
state->old_bs = bdrv_lookup_bs(has_device ? device : NULL,
has_node_name ? node_name : NULL,
&local_err);
aio_context_acquire(state->aio_context);
if (!bdrv_is_inserted(state->old_bs)) {
- error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
+ error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
return;
}
if (!bdrv_is_read_only(state->old_bs)) {
if (bdrv_flush(state->old_bs)) {
- error_set(errp, QERR_IO_ERROR);
+ error_setg(errp, QERR_IO_ERROR);
return;
}
}
if (!bdrv_is_first_non_filter(state->old_bs)) {
- error_set(errp, QERR_FEATURE_DISABLED, "snapshot");
+ error_setg(errp, QERR_FEATURE_DISABLED, "snapshot");
return;
}
}
}
+ options = qdict_new();
if (has_snapshot_node_name) {
- options = qdict_new();
qdict_put(options, "node-name",
qstring_from_str(snapshot_node_name));
}
+ qdict_put(options, "driver", qstring_from_str(format));
/* TODO Inherit bs->options or only take explicit options with an
* extended QMP command? */
assert(state->new_bs == NULL);
ret = bdrv_open(&state->new_bs, new_image_file, NULL, options,
- flags | BDRV_O_NO_BACKING, drv, &local_err);
+ flags | BDRV_O_NO_BACKING, &local_err);
/* We will manually add the backing_hd field to the bs later */
if (ret != 0) {
error_propagate(errp, local_err);
blk = blk_by_name(backup->device);
if (!blk) {
- error_set(errp, QERR_DEVICE_NOT_FOUND, backup->device);
+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+ "Device '%s' not found", backup->device);
return;
}
bs = blk_bs(blk);
blk = blk_by_name(device);
if (!blk) {
- error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+ "Device '%s' not found", device);
return;
}
/* Assumes AioContext is held */
static void qmp_bdrv_open_encrypted(BlockDriverState *bs, const char *filename,
- int bdrv_flags, BlockDriver *drv,
+ int bdrv_flags, const char *format,
const char *password, Error **errp)
{
Error *local_err = NULL;
+ QDict *options = NULL;
int ret;
- ret = bdrv_open(&bs, filename, NULL, NULL, bdrv_flags, drv, &local_err);
+ if (format) {
+ options = qdict_new();
+ qdict_put(options, "driver", qstring_from_str(format));
+ }
+
+ ret = bdrv_open(&bs, filename, NULL, options, bdrv_flags, &local_err);
if (ret < 0) {
error_propagate(errp, local_err);
return;
BlockBackend *blk;
BlockDriverState *bs;
AioContext *aio_context;
- BlockDriver *drv = NULL;
int bdrv_flags;
Error *err = NULL;
blk = blk_by_name(device);
if (!blk) {
- error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+ "Device '%s' not found", device);
return;
}
bs = blk_bs(blk);
aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context);
- if (format) {
- drv = bdrv_find_whitelisted_format(format, bs->read_only);
- if (!drv) {
- error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
- goto out;
- }
- }
-
eject_device(blk, 0, &err);
if (err) {
error_propagate(errp, err);
bdrv_flags = bdrv_is_read_only(bs) ? 0 : BDRV_O_RDWR;
bdrv_flags |= bdrv_is_snapshot(bs) ? BDRV_O_SNAPSHOT : 0;
- qmp_bdrv_open_encrypted(bs, filename, bdrv_flags, drv, NULL, errp);
+ qmp_bdrv_open_encrypted(bs, filename, bdrv_flags, format, NULL, errp);
out:
aio_context_release(aio_context);
bool has_iops_wr_max,
int64_t iops_wr_max,
bool has_iops_size,
- int64_t iops_size, Error **errp)
+ int64_t iops_size,
+ bool has_group,
+ const char *group, Error **errp)
{
ThrottleConfig cfg;
BlockDriverState *bs;
blk = blk_by_name(device);
if (!blk) {
- error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+ "Device '%s' not found", device);
return;
}
bs = blk_bs(blk);
aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context);
- if (!bs->io_limits_enabled && throttle_enabled(&cfg)) {
- bdrv_io_limits_enable(bs);
- } else if (bs->io_limits_enabled && !throttle_enabled(&cfg)) {
- bdrv_io_limits_disable(bs);
- }
-
- if (bs->io_limits_enabled) {
+ if (throttle_enabled(&cfg)) {
+ /* Enable I/O limits if they're not enabled yet, otherwise
+ * just update the throttling group. */
+ if (!bs->io_limits_enabled) {
+ bdrv_io_limits_enable(bs, has_group ? group : device);
+ } else if (has_group) {
+ bdrv_io_limits_update_group(bs, group);
+ }
+ /* Set the new throttling configuration */
bdrv_set_io_limits(bs, &cfg);
+ } else if (bs->io_limits_enabled) {
+ /* If all throttling settings are set to 0, disable I/O limits */
+ bdrv_io_limits_disable(bs);
}
aio_context_release(aio_context);
return;
}
- /* quiesce block driver; prevent further io */
- bdrv_drain_all();
- bdrv_flush(bs);
bdrv_close(bs);
/* if we have a device attached to this BlockDriverState
aio_context_acquire(aio_context);
if (!bdrv_is_first_non_filter(bs)) {
- error_set(errp, QERR_FEATURE_DISABLED, "resize");
+ error_setg(errp, QERR_FEATURE_DISABLED, "resize");
goto out;
}
if (size < 0) {
- error_set(errp, QERR_INVALID_PARAMETER_VALUE, "size", "a >0 size");
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "size", "a >0 size");
goto out;
}
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_RESIZE, NULL)) {
- error_set(errp, QERR_DEVICE_IN_USE, device);
+ error_setg(errp, QERR_DEVICE_IN_USE, device);
goto out;
}
case 0:
break;
case -ENOMEDIUM:
- error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
+ error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
break;
case -ENOTSUP:
- error_set(errp, QERR_UNSUPPORTED);
+ error_setg(errp, QERR_UNSUPPORTED);
break;
case -EACCES:
error_setg(errp, "Device '%s' is read only", device);
break;
case -EBUSY:
- error_set(errp, QERR_DEVICE_IN_USE, device);
+ error_setg(errp, QERR_DEVICE_IN_USE, device);
break;
default:
error_setg_errno(errp, -ret, "Could not resize");
blk = blk_by_name(device);
if (!blk) {
- error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+ "Device '%s' not found", device);
return;
}
bs = blk_bs(blk);
if (has_base) {
base_bs = bdrv_find_backing_image(bs, base);
if (base_bs == NULL) {
- error_set(errp, QERR_BASE_NOT_FOUND, base);
+ error_setg(errp, QERR_BASE_NOT_FOUND, base);
goto out;
}
assert(bdrv_get_aio_context(base_bs) == aio_context);
* scenario in which all optional arguments are omitted. */
blk = blk_by_name(device);
if (!blk) {
- error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+ "Device '%s' not found", device);
return;
}
bs = blk_bs(blk);
aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context);
- /* drain all i/o before commits */
- bdrv_drain_all();
-
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_COMMIT_SOURCE, errp)) {
goto out;
}
}
if (base_bs == NULL) {
- error_set(errp, QERR_BASE_NOT_FOUND, base ? base : "NULL");
+ error_setg(errp, QERR_BASE_NOT_FOUND, base ? base : "NULL");
goto out;
}
BlockDriverState *source = NULL;
BdrvDirtyBitmap *bmap = NULL;
AioContext *aio_context;
- BlockDriver *drv = NULL;
+ QDict *options = NULL;
Error *local_err = NULL;
int flags;
int64_t size;
blk = blk_by_name(device);
if (!blk) {
- error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+ "Device '%s' not found", device);
return;
}
bs = blk_bs(blk);
/* Although backup_run has this check too, we need to use bs->drv below, so
* do an early check redundantly. */
if (!bdrv_is_inserted(bs)) {
- error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
+ error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
goto out;
}
if (!has_format) {
format = mode == NEW_IMAGE_MODE_EXISTING ? NULL : bs->drv->format_name;
}
- if (format) {
- drv = bdrv_find_format(format);
- if (!drv) {
- error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
- goto out;
- }
- }
/* Early check to avoid creating target */
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) {
}
if (mode != NEW_IMAGE_MODE_EXISTING) {
- assert(format && drv);
+ assert(format);
if (source) {
bdrv_img_create(target, format, source->filename,
source->drv->format_name, NULL,
goto out;
}
+ if (format) {
+ options = qdict_new();
+ qdict_put(options, "driver", qstring_from_str(format));
+ }
+
target_bs = NULL;
- ret = bdrv_open(&target_bs, target, NULL, NULL, flags, drv, &local_err);
+ ret = bdrv_open(&target_bs, target, NULL, options, flags, &local_err);
if (ret < 0) {
error_propagate(errp, local_err);
goto out;
aio_context_release(aio_context);
}
-#define DEFAULT_MIRROR_BUF_SIZE (10 << 20)
-
void qmp_drive_mirror(const char *device, const char *target,
bool has_format, const char *format,
bool has_node_name, const char *node_name,
bool has_buf_size, int64_t buf_size,
bool has_on_source_error, BlockdevOnError on_source_error,
bool has_on_target_error, BlockdevOnError on_target_error,
+ bool has_unmap, bool unmap,
Error **errp)
{
BlockBackend *blk;
BlockDriverState *bs;
BlockDriverState *source, *target_bs;
AioContext *aio_context;
- BlockDriver *drv = NULL;
Error *local_err = NULL;
- QDict *options = NULL;
+ QDict *options;
int flags;
int64_t size;
int ret;
granularity = 0;
}
if (!has_buf_size) {
- buf_size = DEFAULT_MIRROR_BUF_SIZE;
+ buf_size = 0;
+ }
+ if (!has_unmap) {
+ unmap = true;
}
if (granularity != 0 && (granularity < 512 || granularity > 1048576 * 64)) {
- error_set(errp, QERR_INVALID_PARAMETER_VALUE, "granularity",
- "a value in range [512B, 64MB]");
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "granularity",
+ "a value in range [512B, 64MB]");
return;
}
if (granularity & (granularity - 1)) {
- error_set(errp, QERR_INVALID_PARAMETER_VALUE, "granularity", "power of 2");
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "granularity",
+ "power of 2");
return;
}
blk = blk_by_name(device);
if (!blk) {
- error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+ "Device '%s' not found", device);
return;
}
bs = blk_bs(blk);
aio_context_acquire(aio_context);
if (!bdrv_is_inserted(bs)) {
- error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
+ error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
goto out;
}
if (!has_format) {
format = mode == NEW_IMAGE_MODE_EXISTING ? NULL : bs->drv->format_name;
}
- if (format) {
- drv = bdrv_find_format(format);
- if (!drv) {
- error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
- goto out;
- }
- }
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_MIRROR, errp)) {
goto out;
goto out;
}
- to_replace_bs = check_to_replace_node(replaces, &local_err);
+ to_replace_bs = check_to_replace_node(bs, replaces, &local_err);
if (!to_replace_bs) {
error_propagate(errp, local_err);
&& mode != NEW_IMAGE_MODE_EXISTING)
{
/* create new image w/o backing file */
- assert(format && drv);
+ assert(format);
bdrv_img_create(target, format,
NULL, NULL, NULL, size, flags, &local_err, false);
} else {
goto out;
}
+ options = qdict_new();
if (has_node_name) {
- options = qdict_new();
qdict_put(options, "node-name", qstring_from_str(node_name));
}
+ if (format) {
+ qdict_put(options, "driver", qstring_from_str(format));
+ }
/* Mirroring takes care of copy-on-write using the source's backing
* file.
*/
target_bs = NULL;
ret = bdrv_open(&target_bs, target, NULL, options,
- flags | BDRV_O_NO_BACKING, drv, &local_err);
+ flags | BDRV_O_NO_BACKING, &local_err);
if (ret < 0) {
error_propagate(errp, local_err);
goto out;
has_replaces ? replaces : NULL,
speed, granularity, buf_size, sync,
on_source_error, on_target_error,
+ unmap,
block_job_cb, bs, &local_err);
if (local_err != NULL) {
bdrv_unref(target_bs);
blk = blk_by_name(device);
if (!blk) {
- error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+ "Device '%s' not found", device);
return;
}
bs = blk_bs(blk);
.type = QEMU_OPT_STRING,
.help = "discard operation (ignore/off, unmap/on)",
},{
- .name = "cache.writeback",
+ .name = BDRV_OPT_CACHE_WB,
.type = QEMU_OPT_BOOL,
.help = "enables writeback mode for any caches",
},{
- .name = "cache.direct",
+ .name = BDRV_OPT_CACHE_DIRECT,
.type = QEMU_OPT_BOOL,
.help = "enables use of O_DIRECT (bypass the host page cache)",
},{
- .name = "cache.no-flush",
+ .name = BDRV_OPT_CACHE_NO_FLUSH,
.type = QEMU_OPT_BOOL,
.help = "ignore any flush requests for the device",
},{
.name = "throttling.iops-size",
.type = QEMU_OPT_NUMBER,
.help = "when limiting by iops max size of an I/O in bytes",
+ },{
+ .name = "throttling.group",
+ .type = QEMU_OPT_STRING,
+ .help = "name of the block throttling group",
},{
.name = "copy-on-read",
.type = QEMU_OPT_BOOL,