#include "qemu/option.h"
#include "qemu/config-file.h"
#include "qapi/qmp/types.h"
+#include "qapi-visit.h"
+#include "qapi/qmp-output-visitor.h"
#include "sysemu/sysemu.h"
#include "block/block_int.h"
#include "qmp-commands.h"
{
DriveInfo *dinfo = drive_get_by_blockdev(bs);
+ if (dinfo && !dinfo->enable_auto_del) {
+ return;
+ }
+
if (bs->job) {
block_job_cancel(bs->job);
}
return NULL;
}
- drv = bdrv_find_whitelisted_format(buf, ro);
+ drv = bdrv_find_format(buf);
if (!drv) {
- if (!ro && bdrv_find_whitelisted_format(buf, !ro)) {
- error_report("'%s' can be only used as read-only device.", buf);
- } else {
- error_report("'%s' invalid format", buf);
- }
+ error_report("'%s' invalid format", buf);
return NULL;
}
}
DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
{
const char *value;
+ DriveInfo *dinfo;
/* Change legacy command line options into QMP ones */
qemu_opt_rename(all_opts, "iops", "throttling.iops-total");
qemu_opt_unset(all_opts, "cache");
}
- return blockdev_init(all_opts, block_default_type);
+ /* Actual block device init: Functionality shared with blockdev-add */
+ dinfo = blockdev_init(all_opts, block_default_type);
+ if (dinfo == NULL) {
+ goto fail;
+ }
+
+ /* Set legacy DriveInfo fields */
+ dinfo->enable_auto_del = true;
+
+fail:
+ return dinfo;
}
void do_commit(Monitor *mon, const QDict *qdict)
}
}
+ if (bdrv_check_ext_snapshot(state->old_bs) != EXT_SNAPSHOT_ALLOWED) {
+ error_set(errp, QERR_FEATURE_DISABLED, "snapshot");
+ return;
+ }
+
flags = state->old_bs->open_flags;
/* create new image w/backing file */
block_job_complete(job, errp);
}
+void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
+{
+ QmpOutputVisitor *ov = qmp_output_visitor_new();
+ QObject *obj;
+ QDict *qdict;
+ DriveInfo *dinfo;
+ Error *local_err = NULL;
+
+ /* Require an ID in the top level */
+ if (!options->has_id) {
+ error_setg(errp, "Block device needs an ID");
+ goto fail;
+ }
+
+ /* TODO Sort it out in raw-posix and drive_init: Reject aio=native with
+ * cache.direct=false instead of silently switching to aio=threads, except
+ * if called from drive_init.
+ *
+ * For now, simply forbidding the combination for all drivers will do. */
+ if (options->has_aio && options->aio == BLOCKDEV_AIO_OPTIONS_NATIVE) {
+ bool direct = options->cache->has_direct && options->cache->direct;
+ if (!options->has_cache && !direct) {
+ error_setg(errp, "aio=native requires cache.direct=true");
+ goto fail;
+ }
+ }
+
+ visit_type_BlockdevOptions(qmp_output_get_visitor(ov),
+ &options, NULL, &local_err);
+ if (error_is_set(&local_err)) {
+ error_propagate(errp, local_err);
+ goto fail;
+ }
+
+ obj = qmp_output_get_qobject(ov);
+ qdict = qobject_to_qdict(obj);
+
+ qdict_flatten(qdict);
+
+ QemuOpts *opts = qemu_opts_from_qdict(&qemu_drive_opts, qdict, &local_err);
+ if (error_is_set(&local_err)) {
+ error_propagate(errp, local_err);
+ goto fail;
+ }
+
+ dinfo = blockdev_init(opts, IF_NONE);
+ if (!dinfo) {
+ error_setg(errp, "Could not open image");
+ goto fail;
+ }
+
+fail:
+ qmp_output_visitor_cleanup(ov);
+}
+
static void do_qmp_query_block_jobs_one(void *opaque, BlockDriverState *bs)
{
BlockJobInfoList **prev = opaque;