}
}
+static bool parse_stats_intervals(BlockAcctStats *stats, QList *intervals,
+ Error **errp)
+{
+ const QListEntry *entry;
+ for (entry = qlist_first(intervals); entry; entry = qlist_next(entry)) {
+ switch (qobject_type(entry->value)) {
+
+ case QTYPE_QSTRING: {
+ unsigned long long length;
+ const char *str = qstring_get_str(qobject_to_qstring(entry->value));
+ if (parse_uint_full(str, &length, 10) == 0 &&
+ length > 0 && length <= UINT_MAX) {
+ block_acct_add_interval(stats, (unsigned) length);
+ } else {
+ error_setg(errp, "Invalid interval length: %s", str);
+ return false;
+ }
+ break;
+ }
+
+ case QTYPE_QINT: {
+ int64_t length = qint_get_int(qobject_to_qint(entry->value));
+ if (length > 0 && length <= UINT_MAX) {
+ block_acct_add_interval(stats, (unsigned) length);
+ } else {
+ error_setg(errp, "Invalid interval length: %" PRId64, length);
+ return false;
+ }
+ break;
+ }
+
+ default:
+ error_setg(errp, "The specification of stats-intervals is invalid");
+ return false;
+ }
+ }
+ return true;
+}
+
static bool check_throttle_config(ThrottleConfig *cfg, Error **errp)
{
if (throttle_conflicting(cfg)) {
}
}
- if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_WB, true)) {
- *bdrv_flags |= BDRV_O_CACHE_WB;
- }
- if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_DIRECT, false)) {
- *bdrv_flags |= BDRV_O_NOCACHE;
- }
- if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_NO_FLUSH, false)) {
- *bdrv_flags |= BDRV_O_NO_FLUSH;
- }
-
if ((aio = qemu_opt_get(opts, "aio")) != NULL) {
if (!strcmp(aio, "native")) {
*bdrv_flags |= BDRV_O_NATIVE_AIO;
*detect_zeroes =
qapi_enum_parse(BlockdevDetectZeroesOptions_lookup,
qemu_opt_get(opts, "detect-zeroes"),
- BLOCKDEV_DETECT_ZEROES_OPTIONS_MAX,
+ BLOCKDEV_DETECT_ZEROES_OPTIONS__MAX,
BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF,
&local_error);
if (local_error) {
int bdrv_flags = 0;
int on_read_error, on_write_error;
bool account_invalid, account_failed;
- const char *stats_intervals;
BlockBackend *blk;
BlockDriverState *bs;
ThrottleConfig cfg;
int snapshot = 0;
Error *error = NULL;
QemuOpts *opts;
+ QDict *interval_dict = NULL;
+ QList *interval_list = NULL;
const char *id;
- bool has_driver_specific_opts;
BlockdevDetectZeroesOptions detect_zeroes =
BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF;
const char *throttling_group = NULL;
qdict_del(bs_opts, "id");
}
- has_driver_specific_opts = !!qdict_size(bs_opts);
-
/* extract parameters */
snapshot = qemu_opt_get_bool(opts, "snapshot", 0);
account_invalid = qemu_opt_get_bool(opts, "stats-account-invalid", true);
account_failed = qemu_opt_get_bool(opts, "stats-account-failed", true);
- stats_intervals = qemu_opt_get(opts, "stats-intervals");
+ qdict_extract_subqdict(bs_opts, &interval_dict, "stats-intervals.");
+ qdict_array_split(interval_dict, &interval_list);
+
+ if (qdict_size(interval_dict) != 0) {
+ error_setg(errp, "Invalid option stats-intervals.%s",
+ qdict_first(interval_dict)->key);
+ goto early_err;
+ }
extract_common_blockdev_options(opts, &bdrv_flags, &throttling_group, &cfg,
&detect_zeroes, &error);
}
if (snapshot) {
- /* always use cache=unsafe with snapshot */
- bdrv_flags &= ~BDRV_O_CACHE_MASK;
- bdrv_flags |= (BDRV_O_SNAPSHOT|BDRV_O_CACHE_WB|BDRV_O_NO_FLUSH);
+ bdrv_flags |= BDRV_O_SNAPSHOT;
}
/* init */
- if ((!file || !*file) && !has_driver_specific_opts) {
+ if ((!file || !*file) && !qdict_size(bs_opts)) {
BlockBackendRootState *blk_rs;
blk = blk_new(qemu_opts_id(opts), errp);
file = NULL;
}
+ /* bdrv_open() defaults to the values in bdrv_flags (for compatibility
+ * with other callers) rather than what we want as the real defaults.
+ * Apply the defaults here instead. */
+ qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_WB, "on");
+ qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_DIRECT, "off");
+ qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_NO_FLUSH, "off");
+
+ if (snapshot) {
+ /* always use cache=unsafe with snapshot */
+ qdict_put(bs_opts, BDRV_OPT_CACHE_WB, qstring_from_str("on"));
+ qdict_put(bs_opts, BDRV_OPT_CACHE_DIRECT, qstring_from_str("off"));
+ qdict_put(bs_opts, BDRV_OPT_CACHE_NO_FLUSH, qstring_from_str("on"));
+ }
+
blk = blk_new_open(qemu_opts_id(opts), file, NULL, bs_opts, bdrv_flags,
errp);
if (!blk) {
block_acct_init(blk_get_stats(blk), account_invalid, account_failed);
- if (stats_intervals) {
- char **intervals = g_strsplit(stats_intervals, ":", 0);
- unsigned i;
-
- if (*stats_intervals == '\0') {
- error_setg(&error, "stats-intervals can't have an empty value");
- }
-
- for (i = 0; !error && intervals[i] != NULL; i++) {
- unsigned long long val;
- if (parse_uint_full(intervals[i], &val, 10) == 0 &&
- val > 0 && val <= UINT_MAX) {
- block_acct_add_interval(blk_get_stats(blk), val);
- } else {
- error_setg(&error, "Invalid interval length: '%s'",
- intervals[i]);
- }
- }
-
- g_strfreev(intervals);
-
- if (error) {
- error_propagate(errp, error);
- blk_unref(blk);
- blk = NULL;
- goto err_no_bs_opts;
- }
+ if (!parse_stats_intervals(blk_get_stats(blk), interval_list, errp)) {
+ blk_unref(blk);
+ blk = NULL;
+ goto err_no_bs_opts;
}
}
err_no_bs_opts:
qemu_opts_del(opts);
+ QDECREF(interval_dict);
+ QDECREF(interval_list);
return blk;
early_err:
qemu_opts_del(opts);
+ QDECREF(interval_dict);
+ QDECREF(interval_list);
err_no_opts:
QDECREF(bs_opts);
return NULL;
.prepare = external_snapshot_prepare,
.commit = external_snapshot_commit,
.abort = external_snapshot_abort,
+ .clean = external_snapshot_clean,
},
[TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC] = {
.instance_size = sizeof(ExternalSnapshotState),
return;
}
- qmp_blockdev_remove_medium(device, errp);
+ qmp_x_blockdev_remove_medium(device, errp);
}
void qmp_block_passwd(bool has_device, const char *device,
blk_dev_change_media_cb(blk, true);
}
-void qmp_blockdev_remove_medium(const char *device, Error **errp)
+void qmp_x_blockdev_remove_medium(const char *device, Error **errp)
{
BlockBackend *blk;
BlockDriverState *bs;
QTAILQ_INSERT_TAIL(&bdrv_states, bs, device_list);
}
-void qmp_blockdev_insert_medium(const char *device, const char *node_name,
- Error **errp)
+void qmp_x_blockdev_insert_medium(const char *device, const char *node_name,
+ Error **errp)
{
BlockDriverState *bs;
goto fail;
}
- qmp_blockdev_remove_medium(device, &err);
+ qmp_x_blockdev_remove_medium(device, &err);
if (err) {
error_propagate(errp, err);
goto fail;
bmap = bdrv_find_dirty_bitmap(bs, bitmap);
if (!bmap) {
error_setg(errp, "Bitmap '%s' could not be found", bitmap);
+ bdrv_unref(target_bs);
goto out;
}
}
.name = "discard",
.type = QEMU_OPT_STRING,
.help = "discard operation (ignore/off, unmap/on)",
- },{
- .name = BDRV_OPT_CACHE_WB,
- .type = QEMU_OPT_BOOL,
- .help = "enables writeback mode for any caches",
- },{
- .name = BDRV_OPT_CACHE_DIRECT,
- .type = QEMU_OPT_BOOL,
- .help = "enables use of O_DIRECT (bypass the host page cache)",
- },{
- .name = BDRV_OPT_CACHE_NO_FLUSH,
- .type = QEMU_OPT_BOOL,
- .help = "ignore any flush requests for the device",
},{
.name = "aio",
.type = QEMU_OPT_STRING,
.type = QEMU_OPT_BOOL,
.help = "whether to account for failed I/O operations "
"in the statistics",
- },{
- .name = "stats-intervals",
- .type = QEMU_OPT_STRING,
- .help = "colon-separated list of intervals "
- "for collecting I/O statistics, in seconds",
},
{ /* end of list */ }
},
.name = "discard",
.type = QEMU_OPT_STRING,
.help = "discard operation (ignore/off, unmap/on)",
- },{
- .name = "cache.writeback",
- .type = QEMU_OPT_BOOL,
- .help = "enables writeback mode for any caches",
- },{
- .name = "cache.direct",
- .type = QEMU_OPT_BOOL,
- .help = "enables use of O_DIRECT (bypass the host page cache)",
- },{
- .name = "cache.no-flush",
- .type = QEMU_OPT_BOOL,
- .help = "ignore any flush requests for the device",
},{
.name = "aio",
.type = QEMU_OPT_STRING,