* THE SOFTWARE.
*/
+#include "qemu/osdep.h"
#include "sysemu/block-backend.h"
#include "sysemu/blockdev.h"
#include "hw/block/block.h"
#include "trace.h"
#include "sysemu/arch_init.h"
+static QTAILQ_HEAD(, BlockDriverState) monitor_bdrv_states =
+ QTAILQ_HEAD_INITIALIZER(monitor_bdrv_states);
+
static const char *const if_name[IF_COUNT] = {
[IF_NONE] = "none",
[IF_IDE] = "ide",
return true;
}
-static bool check_throttle_config(ThrottleConfig *cfg, Error **errp)
-{
- if (throttle_conflicting(cfg)) {
- error_setg(errp, "bps/iops/max total values and read/write values"
- " cannot be used at the same time");
- return false;
- }
-
- if (!throttle_is_valid(cfg)) {
- error_setg(errp, "bps/iops/maxs values must be 0 or greater");
- 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;
-}
-
typedef enum { MEDIA_DISK, MEDIA_CDROM } DriveMediaType;
/* All parameters but @opts are optional and may be set to NULL. */
}
if (throttle_cfg) {
- memset(throttle_cfg, 0, sizeof(*throttle_cfg));
+ throttle_config_init(throttle_cfg);
throttle_cfg->buckets[THROTTLE_BPS_TOTAL].avg =
qemu_opt_get_number(opts, "throttling.bps-total", 0);
throttle_cfg->buckets[THROTTLE_BPS_READ].avg =
throttle_cfg->buckets[THROTTLE_OPS_WRITE].max =
qemu_opt_get_number(opts, "throttling.iops-write-max", 0);
+ throttle_cfg->buckets[THROTTLE_BPS_TOTAL].burst_length =
+ qemu_opt_get_number(opts, "throttling.bps-total-max-length", 1);
+ throttle_cfg->buckets[THROTTLE_BPS_READ].burst_length =
+ qemu_opt_get_number(opts, "throttling.bps-read-max-length", 1);
+ throttle_cfg->buckets[THROTTLE_BPS_WRITE].burst_length =
+ qemu_opt_get_number(opts, "throttling.bps-write-max-length", 1);
+ throttle_cfg->buckets[THROTTLE_OPS_TOTAL].burst_length =
+ qemu_opt_get_number(opts, "throttling.iops-total-max-length", 1);
+ throttle_cfg->buckets[THROTTLE_OPS_READ].burst_length =
+ qemu_opt_get_number(opts, "throttling.iops-read-max-length", 1);
+ throttle_cfg->buckets[THROTTLE_OPS_WRITE].burst_length =
+ qemu_opt_get_number(opts, "throttling.iops-write-max-length", 1);
+
throttle_cfg->op_size =
qemu_opt_get_number(opts, "throttling.iops-size", 0);
- if (!check_throttle_config(throttle_cfg, errp)) {
+ if (!throttle_is_valid(throttle_cfg, errp)) {
return;
}
}
qdict_put(bs_opts, BDRV_OPT_CACHE_NO_FLUSH, qstring_from_str("on"));
}
+ if (runstate_check(RUN_STATE_INMIGRATE)) {
+ bdrv_flags |= BDRV_O_INACTIVE;
+ }
+
blk = blk_new_open(qemu_opts_id(opts), file, NULL, bs_opts, bdrv_flags,
errp);
if (!blk) {
goto fail;
}
+ if (runstate_check(RUN_STATE_INMIGRATE)) {
+ bdrv_flags |= BDRV_O_INACTIVE;
+ }
+
bs = NULL;
ret = bdrv_open(&bs, NULL, NULL, bs_opts, bdrv_flags, errp);
if (ret < 0) {
return NULL;
}
+void blockdev_close_all_bdrv_states(void)
+{
+ BlockDriverState *bs, *next_bs;
+
+ QTAILQ_FOREACH_SAFE(bs, &monitor_bdrv_states, monitor_list, next_bs) {
+ AioContext *ctx = bdrv_get_aio_context(bs);
+
+ aio_context_acquire(ctx);
+ bdrv_unref(bs);
+ aio_context_release(ctx);
+ }
+}
+
static void qemu_opt_rename(QemuOpts *opts, const char *from, const char *to,
Error **errp)
{
}
if (bdrv_snapshot_delete(bs, sn->id_str, sn->name, &local_error) < 0) {
- error_report("Failed to delete snapshot with id '%s' and name '%s' on "
- "device '%s' in abort: %s",
- sn->id_str,
- sn->name,
- bdrv_get_device_name(bs),
- error_get_pretty(local_error));
- error_free(local_error);
+ error_reportf_err(local_error,
+ "Failed to delete snapshot with id '%s' and "
+ "name '%s' on device '%s' in abort: ",
+ sn->id_str, sn->name,
+ bdrv_get_device_name(bs));
}
}
return;
}
+ if (!blk_dev_has_tray(blk)) {
+ /* Ignore this command on tray-less devices */
+ return;
+ }
+
if (blk_dev_is_tray_open(blk)) {
return;
}
return;
}
+ if (!blk_dev_has_tray(blk)) {
+ /* Ignore this command on tray-less devices */
+ return;
+ }
+
if (!blk_dev_is_tray_open(blk)) {
return;
}
return;
}
- if (has_device && !blk_dev_is_tray_open(blk)) {
+ if (has_device && blk_dev_has_tray(blk) && !blk_dev_is_tray_open(blk)) {
error_setg(errp, "Tray of device '%s' is not open", device);
return;
}
/* This follows the convention established by bdrv_make_anon() */
if (bs->device_list.tqe_prev) {
- QTAILQ_REMOVE(&bdrv_states, bs, device_list);
- bs->device_list.tqe_prev = NULL;
+ bdrv_device_remove(bs);
}
blk_remove_bs(blk);
+ if (!blk_dev_has_tray(blk)) {
+ /* For tray-less devices, blockdev-open-tray is a no-op (or may not be
+ * called at all); therefore, the medium needs to be ejected here.
+ * Do it after blk_remove_bs() so blk_is_inserted(blk) returns the @load
+ * value passed here (i.e. false). */
+ blk_dev_change_media_cb(blk, false);
+ }
+
out:
aio_context_release(aio_context);
}
return;
}
- if (has_device && !blk_dev_is_tray_open(blk)) {
+ if (has_device && blk_dev_has_tray(blk) && !blk_dev_is_tray_open(blk)) {
error_setg(errp, "Tray of device '%s' is not open", device);
return;
}
blk_insert_bs(blk, bs);
QTAILQ_INSERT_TAIL(&bdrv_states, bs, device_list);
+
+ if (!blk_dev_has_tray(blk)) {
+ /* For tray-less devices, blockdev-close-tray is a no-op (or may not be
+ * called at all); therefore, the medium needs to be pushed into the
+ * slot here.
+ * Do it after blk_insert_bs() so blk_is_inserted(blk) returns the @load
+ * value passed here (i.e. true). */
+ blk_dev_change_media_cb(blk, true);
+ }
}
void qmp_x_blockdev_insert_medium(const char *device, const char *node_name,
}
bdrv_flags = blk_get_open_flags_from_root_state(blk);
+ bdrv_flags &= ~(BDRV_O_TEMPORARY | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING |
+ BDRV_O_PROTOCOL);
if (!has_read_only) {
read_only = BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN;
int64_t iops_rd_max,
bool has_iops_wr_max,
int64_t iops_wr_max,
+ bool has_bps_max_length,
+ int64_t bps_max_length,
+ bool has_bps_rd_max_length,
+ int64_t bps_rd_max_length,
+ bool has_bps_wr_max_length,
+ int64_t bps_wr_max_length,
+ bool has_iops_max_length,
+ int64_t iops_max_length,
+ bool has_iops_rd_max_length,
+ int64_t iops_rd_max_length,
+ bool has_iops_wr_max_length,
+ int64_t iops_wr_max_length,
bool has_iops_size,
int64_t iops_size,
bool has_group,
goto out;
}
- memset(&cfg, 0, sizeof(cfg));
+ throttle_config_init(&cfg);
cfg.buckets[THROTTLE_BPS_TOTAL].avg = bps;
cfg.buckets[THROTTLE_BPS_READ].avg = bps_rd;
cfg.buckets[THROTTLE_BPS_WRITE].avg = bps_wr;
cfg.buckets[THROTTLE_OPS_WRITE].max = iops_wr_max;
}
+ if (has_bps_max_length) {
+ cfg.buckets[THROTTLE_BPS_TOTAL].burst_length = bps_max_length;
+ }
+ if (has_bps_rd_max_length) {
+ cfg.buckets[THROTTLE_BPS_READ].burst_length = bps_rd_max_length;
+ }
+ if (has_bps_wr_max_length) {
+ cfg.buckets[THROTTLE_BPS_WRITE].burst_length = bps_wr_max_length;
+ }
+ if (has_iops_max_length) {
+ cfg.buckets[THROTTLE_OPS_TOTAL].burst_length = iops_max_length;
+ }
+ if (has_iops_rd_max_length) {
+ cfg.buckets[THROTTLE_OPS_READ].burst_length = iops_rd_max_length;
+ }
+ if (has_iops_wr_max_length) {
+ cfg.buckets[THROTTLE_OPS_WRITE].burst_length = iops_wr_max_length;
+ }
+
if (has_iops_size) {
cfg.op_size = iops_size;
}
- if (!check_throttle_config(&cfg, errp)) {
+ if (!throttle_is_valid(&cfg, errp)) {
goto out;
}
return;
}
- bdrv_close(bs);
+ blk_remove_bs(blk);
}
/* if we have a device attached to this BlockDriverState
}
}
- visit_type_BlockdevOptions(qmp_output_get_visitor(ov),
- &options, NULL, &local_err);
+ visit_type_BlockdevOptions(qmp_output_get_visitor(ov), NULL, &options,
+ &local_err);
if (local_err) {
error_propagate(errp, local_err);
goto fail;
if (!bs) {
goto fail;
}
+
+ QTAILQ_INSERT_TAIL(&monitor_bdrv_states, bs, monitor_list);
}
if (bs && bdrv_key_required(bs)) {
if (blk) {
blk_unref(blk);
} else {
+ QTAILQ_REMOVE(&monitor_bdrv_states, bs, monitor_list);
bdrv_unref(bs);
}
error_setg(errp, "blockdev-add doesn't support encrypted devices");
goto out;
}
- if (bs->refcnt > 1 || !QLIST_EMPTY(&bs->parents)) {
+ if (!blk && !bs->monitor_list.tqe_prev) {
+ error_setg(errp, "Node %s is not owned by the monitor",
+ bs->node_name);
+ goto out;
+ }
+
+ if (bs->refcnt > 1) {
error_setg(errp, "Block device %s is in use",
bdrv_get_device_or_node_name(bs));
goto out;
if (blk) {
blk_unref(blk);
} else {
+ QTAILQ_REMOVE(&monitor_bdrv_states, bs, monitor_list);
bdrv_unref(bs);
}
.name = "throttling.bps-write-max",
.type = QEMU_OPT_NUMBER,
.help = "total bytes write burst",
+ },{
+ .name = "throttling.iops-total-max-length",
+ .type = QEMU_OPT_NUMBER,
+ .help = "length of the iops-total-max burst period, in seconds",
+ },{
+ .name = "throttling.iops-read-max-length",
+ .type = QEMU_OPT_NUMBER,
+ .help = "length of the iops-read-max burst period, in seconds",
+ },{
+ .name = "throttling.iops-write-max-length",
+ .type = QEMU_OPT_NUMBER,
+ .help = "length of the iops-write-max burst period, in seconds",
+ },{
+ .name = "throttling.bps-total-max-length",
+ .type = QEMU_OPT_NUMBER,
+ .help = "length of the bps-total-max burst period, in seconds",
+ },{
+ .name = "throttling.bps-read-max-length",
+ .type = QEMU_OPT_NUMBER,
+ .help = "length of the bps-read-max burst period, in seconds",
+ },{
+ .name = "throttling.bps-write-max-length",
+ .type = QEMU_OPT_NUMBER,
+ .help = "length of the bps-write-max burst period, in seconds",
},{
.name = "throttling.iops-size",
.type = QEMU_OPT_NUMBER,