#include "qemu/main-loop.h"
#include "qemu/throttle-options.h"
-static QTAILQ_HEAD(, BlockDriverState) monitor_bdrv_states =
+QTAILQ_HEAD(, BlockDriverState) monitor_bdrv_states =
QTAILQ_HEAD_INITIALIZER(monitor_bdrv_states);
-static int do_open_tray(const char *blk_name, const char *qdev_id,
- bool force, Error **errp);
-static void blockdev_remove_medium(bool has_device, const char *device,
- bool has_id, const char *id, Error **errp);
-static void blockdev_insert_medium(bool has_device, const char *device,
- bool has_id, const char *id,
- const char *node_name, Error **errp);
+void bdrv_set_monitor_owned(BlockDriverState *bs)
+{
+ QTAILQ_INSERT_TAIL(&monitor_bdrv_states, bs, monitor_list);
+}
static const char *const if_name[IF_COUNT] = {
[IF_NONE] = "none",
}
if ((aio = qemu_opt_get(opts, "aio")) != NULL) {
- if (!strcmp(aio, "native")) {
- *bdrv_flags |= BDRV_O_NATIVE_AIO;
- } else if (!strcmp(aio, "threads")) {
- /* this is the default */
- } else {
- error_setg(errp, "invalid aio option");
- return;
+ if (bdrv_parse_aio(aio, bdrv_flags) < 0) {
+ error_setg(errp, "invalid aio option");
+ return;
}
}
}
}
/* Takes the ownership of bs_opts */
-static BlockDriverState *bds_tree_init(QDict *bs_opts, Error **errp)
+BlockDriverState *bds_tree_init(QDict *bs_opts, Error **errp)
{
int bdrv_flags = 0;
return bs;
}
-static BlockBackend *qmp_get_blk(const char *blk_name, const char *qdev_id,
- Error **errp)
-{
- BlockBackend *blk;
-
- if (!blk_name == !qdev_id) {
- error_setg(errp, "Need exactly one of 'device' and 'id'");
- return NULL;
- }
-
- if (qdev_id) {
- blk = blk_by_qdev_id(qdev_id, errp);
- } else {
- blk = blk_by_name(blk_name);
- if (blk == NULL) {
- error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
- "Device '%s' not found", blk_name);
- }
- }
-
- return blk;
-}
-
-void hmp_commit(Monitor *mon, const QDict *qdict)
-{
- const char *device = qdict_get_str(qdict, "device");
- BlockBackend *blk;
- int ret;
-
- if (!strcmp(device, "all")) {
- ret = blk_commit_all();
- } else {
- BlockDriverState *bs;
- AioContext *aio_context;
-
- blk = blk_by_name(device);
- if (!blk) {
- monitor_printf(mon, "Device '%s' not found\n", device);
- return;
- }
- if (!blk_is_available(blk)) {
- monitor_printf(mon, "Device '%s' has no medium\n", device);
- return;
- }
-
- bs = blk_bs(blk);
- aio_context = bdrv_get_aio_context(bs);
- aio_context_acquire(aio_context);
-
- ret = bdrv_commit(bs);
-
- aio_context_release(aio_context);
- }
- if (ret < 0) {
- monitor_printf(mon, "'commit' error for '%s': %s\n", device,
- strerror(-ret));
- }
-}
-
static void blockdev_do_action(TransactionAction *action, Error **errp)
{
TransactionActionList list;
return NULL;
}
-/**
- * block_dirty_bitmap_lookup:
- * Return a dirty bitmap (if present), after validating
- * the node reference and bitmap names.
- *
- * @node: The name of the BDS node to search for bitmaps
- * @name: The name of the bitmap to search for
- * @pbs: Output pointer for BDS lookup, if desired. Can be NULL.
- * @errp: Output pointer for error information. Can be NULL.
- *
- * @return: A bitmap object on success, or NULL on failure.
- */
-static BdrvDirtyBitmap *block_dirty_bitmap_lookup(const char *node,
- const char *name,
- BlockDriverState **pbs,
- Error **errp)
-{
- BlockDriverState *bs;
- BdrvDirtyBitmap *bitmap;
-
- if (!node) {
- error_setg(errp, "Node cannot be NULL");
- return NULL;
- }
- if (!name) {
- error_setg(errp, "Bitmap name cannot be NULL");
- return NULL;
- }
- bs = bdrv_lookup_bs(node, node, NULL);
- if (!bs) {
- error_setg(errp, "Node '%s' not found", node);
- return NULL;
- }
-
- bitmap = bdrv_find_dirty_bitmap(bs, name);
- if (!bitmap) {
- error_setg(errp, "Dirty bitmap '%s' not found", name);
- return NULL;
- }
-
- if (pbs) {
- *pbs = bs;
- }
-
- return bitmap;
-}
-
/* New and old BlockDriverState structs for atomic group operations */
typedef struct BlkActionState BlkActionState;
DO_UPCAST(ExternalSnapshotState, common, common);
TransactionAction *action = common->action;
AioContext *aio_context;
- int ret;
+ uint64_t perm, shared;
/* 'blockdev-snapshot' and 'blockdev-snapshot-sync' have similar
* purpose but a different set of parameters */
}
}
- if (!bdrv_is_first_non_filter(state->old_bs)) {
- error_setg(errp, QERR_FEATURE_DISABLED, "snapshot");
- goto out;
- }
-
if (action->type == TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC) {
BlockdevSnapshotSync *s = action->u.blockdev_snapshot_sync.data;
const char *format = s->has_format ? s->format : "qcow2";
goto out;
}
- if (bdrv_has_blk(state->new_bs)) {
+ /*
+ * Allow attaching a backing file to an overlay that's already in use only
+ * if the parents don't assume that they are already seeing a valid image.
+ * (Specifically, allow it as a mirror target, which is write-only access.)
+ */
+ bdrv_get_cumulative_perm(state->new_bs, &perm, &shared);
+ if (perm & BLK_PERM_CONSISTENT_READ) {
error_setg(errp, "The overlay is already in use");
goto out;
}
- if (bdrv_op_is_blocked(state->new_bs, BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT,
- errp)) {
- goto out;
- }
-
if (state->new_bs->backing != NULL) {
error_setg(errp, "The overlay already has a backing image");
goto out;
goto out;
}
- ret = bdrv_try_set_aio_context(state->new_bs, aio_context, errp);
- if (ret < 0) {
- goto out;
- }
-
/* This removes our old bs and adds the new bs. This is an operation that
* can fail, so we need to do it in .prepare; undoing it for abort is
* always possible. */
if (state->new_bs) {
if (state->overlay_appended) {
AioContext *aio_context;
+ AioContext *tmp_context;
+ int ret;
aio_context = bdrv_get_aio_context(state->old_bs);
aio_context_acquire(aio_context);
bdrv_ref(state->old_bs); /* we can't let bdrv_set_backind_hd()
close state->old_bs; we need it */
bdrv_set_backing_hd(state->new_bs, NULL, &error_abort);
+
+ /*
+ * The call to bdrv_set_backing_hd() above returns state->old_bs to
+ * the main AioContext. As we're still going to be using it, return
+ * it to the AioContext it was before.
+ */
+ tmp_context = bdrv_get_aio_context(state->old_bs);
+ if (aio_context != tmp_context) {
+ aio_context_release(aio_context);
+ aio_context_acquire(tmp_context);
+
+ ret = bdrv_try_set_aio_context(state->old_bs,
+ aio_context, NULL);
+ assert(ret == 0);
+
+ aio_context_release(tmp_context);
+ aio_context_acquire(aio_context);
+ }
+
bdrv_replace_node(state->new_bs, state->old_bs, &error_abort);
bdrv_unref(state->old_bs); /* bdrv_replace_node() ref'ed old_bs */
BlockJob *job;
} DriveBackupState;
-static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn,
- Error **errp);
+static BlockJob *do_backup_common(BackupCommon *backup,
+ BlockDriverState *bs,
+ BlockDriverState *target_bs,
+ AioContext *aio_context,
+ JobTxn *txn, Error **errp);
static void drive_backup_prepare(BlkActionState *common, Error **errp)
{
DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common);
- BlockDriverState *bs;
DriveBackup *backup;
+ BlockDriverState *bs;
+ BlockDriverState *target_bs;
+ BlockDriverState *source = NULL;
AioContext *aio_context;
+ AioContext *old_context;
+ QDict *options;
Error *local_err = NULL;
+ int flags;
+ int64_t size;
+ bool set_backing_hd = false;
+ int ret;
assert(common->action->type == TRANSACTION_ACTION_KIND_DRIVE_BACKUP);
backup = common->action->u.drive_backup.data;
+ if (!backup->has_mode) {
+ backup->mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;
+ }
+
bs = bdrv_lookup_bs(backup->device, backup->device, errp);
if (!bs) {
return;
}
+ if (!bs->drv) {
+ error_setg(errp, "Device has no medium");
+ return;
+ }
+
aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context);
/* Paired with .clean() */
bdrv_drained_begin(bs);
- state->bs = bs;
+ if (!backup->has_format) {
+ backup->format = backup->mode == NEW_IMAGE_MODE_EXISTING ?
+ NULL : (char *) bs->drv->format_name;
+ }
+
+ /* Early check to avoid creating target */
+ if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) {
+ goto out;
+ }
+
+ flags = bs->open_flags | BDRV_O_RDWR;
+
+ /*
+ * See if we have a backing HD we can use to create our new image
+ * on top of.
+ */
+ if (backup->sync == MIRROR_SYNC_MODE_TOP) {
+ source = backing_bs(bs);
+ if (!source) {
+ backup->sync = MIRROR_SYNC_MODE_FULL;
+ }
+ }
+ if (backup->sync == MIRROR_SYNC_MODE_NONE) {
+ source = bs;
+ flags |= BDRV_O_NO_BACKING;
+ set_backing_hd = true;
+ }
+
+ size = bdrv_getlength(bs);
+ if (size < 0) {
+ error_setg_errno(errp, -size, "bdrv_getlength failed");
+ goto out;
+ }
+
+ if (backup->mode != NEW_IMAGE_MODE_EXISTING) {
+ assert(backup->format);
+ if (source) {
+ bdrv_refresh_filename(source);
+ bdrv_img_create(backup->target, backup->format, source->filename,
+ source->drv->format_name, NULL,
+ size, flags, false, &local_err);
+ } else {
+ bdrv_img_create(backup->target, backup->format, NULL, NULL, NULL,
+ size, flags, false, &local_err);
+ }
+ }
- state->job = do_drive_backup(backup, common->block_job_txn, &local_err);
if (local_err) {
error_propagate(errp, local_err);
goto out;
}
+ options = qdict_new();
+ qdict_put_str(options, "discard", "unmap");
+ qdict_put_str(options, "detect-zeroes", "unmap");
+ if (backup->format) {
+ qdict_put_str(options, "driver", backup->format);
+ }
+
+ target_bs = bdrv_open(backup->target, NULL, options, flags, errp);
+ if (!target_bs) {
+ goto out;
+ }
+
+ /* Honor bdrv_try_set_aio_context() context acquisition requirements. */
+ old_context = bdrv_get_aio_context(target_bs);
+ aio_context_release(aio_context);
+ aio_context_acquire(old_context);
+
+ ret = bdrv_try_set_aio_context(target_bs, aio_context, errp);
+ if (ret < 0) {
+ bdrv_unref(target_bs);
+ aio_context_release(old_context);
+ return;
+ }
+
+ aio_context_release(old_context);
+ aio_context_acquire(aio_context);
+
+ if (set_backing_hd) {
+ bdrv_set_backing_hd(target_bs, source, &local_err);
+ if (local_err) {
+ goto unref;
+ }
+ }
+
+ state->bs = bs;
+
+ state->job = do_backup_common(qapi_DriveBackup_base(backup),
+ bs, target_bs, aio_context,
+ common->block_job_txn, errp);
+
+unref:
+ bdrv_unref(target_bs);
out:
aio_context_release(aio_context);
}
BlockJob *job;
} BlockdevBackupState;
-static BlockJob *do_blockdev_backup(BlockdevBackup *backup, JobTxn *txn,
- Error **errp);
-
static void blockdev_backup_prepare(BlkActionState *common, Error **errp)
{
BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common);
BlockdevBackup *backup;
- BlockDriverState *bs, *target;
+ BlockDriverState *bs;
+ BlockDriverState *target_bs;
AioContext *aio_context;
- Error *local_err = NULL;
+ AioContext *old_context;
+ int ret;
assert(common->action->type == TRANSACTION_ACTION_KIND_BLOCKDEV_BACKUP);
backup = common->action->u.blockdev_backup.data;
return;
}
- target = bdrv_lookup_bs(backup->target, backup->target, errp);
- if (!target) {
+ target_bs = bdrv_lookup_bs(backup->target, backup->target, errp);
+ if (!target_bs) {
return;
}
+ /* Honor bdrv_try_set_aio_context() context acquisition requirements. */
aio_context = bdrv_get_aio_context(bs);
+ old_context = bdrv_get_aio_context(target_bs);
+ aio_context_acquire(old_context);
+
+ ret = bdrv_try_set_aio_context(target_bs, aio_context, errp);
+ if (ret < 0) {
+ aio_context_release(old_context);
+ return;
+ }
+
+ aio_context_release(old_context);
aio_context_acquire(aio_context);
state->bs = bs;
/* Paired with .clean() */
bdrv_drained_begin(state->bs);
- state->job = do_blockdev_backup(backup, common->block_job_txn, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- goto out;
- }
+ state->job = do_backup_common(qapi_BlockdevBackup_base(backup),
+ bs, target_bs, aio_context,
+ common->block_job_txn, errp);
-out:
aio_context_release(aio_context);
}
qmp_block_dirty_bitmap_add(action->node, action->name,
action->has_granularity, action->granularity,
action->has_persistent, action->persistent,
- action->has_autoload, action->autoload,
action->has_disabled, action->disabled,
&local_err);
}
}
-static BdrvDirtyBitmap *do_block_dirty_bitmap_merge(
- const char *node, const char *target,
- BlockDirtyBitmapMergeSourceList *bitmaps,
- HBitmap **backup, Error **errp);
-
static void block_dirty_bitmap_merge_prepare(BlkActionState *common,
Error **errp)
{
action = common->action->u.block_dirty_bitmap_merge.data;
- state->bitmap = do_block_dirty_bitmap_merge(action->node, action->target,
- action->bitmaps, &state->backup,
- errp);
+ state->bitmap = block_dirty_bitmap_merge(action->node, action->target,
+ action->bitmaps, &state->backup,
+ errp);
}
-static BdrvDirtyBitmap *do_block_dirty_bitmap_remove(
- const char *node, const char *name, bool release,
- BlockDriverState **bitmap_bs, Error **errp);
-
static void block_dirty_bitmap_remove_prepare(BlkActionState *common,
Error **errp)
{
action = common->action->u.block_dirty_bitmap_remove.data;
- state->bitmap = do_block_dirty_bitmap_remove(action->node, action->name,
- false, &state->bs, errp);
+ state->bitmap = block_dirty_bitmap_remove(action->node, action->name,
+ false, &state->bs, errp);
if (state->bitmap) {
bdrv_dirty_bitmap_skip_store(state->bitmap, true);
bdrv_dirty_bitmap_set_busy(state->bitmap, true);
common, common);
bdrv_dirty_bitmap_set_busy(state->bitmap, false);
- bdrv_release_dirty_bitmap(state->bs, state->bitmap);
+ bdrv_release_dirty_bitmap(state->bitmap);
}
static void abort_prepare(BlkActionState *common, Error **errp)
job_txn_unref(block_job_txn);
}
-void qmp_eject(bool has_device, const char *device,
- bool has_id, const char *id,
- bool has_force, bool force, Error **errp)
-{
- Error *local_err = NULL;
- int rc;
-
- if (!has_force) {
- force = false;
- }
-
- rc = do_open_tray(has_device ? device : NULL,
- has_id ? id : NULL,
- force, &local_err);
- if (rc && rc != -ENOSYS) {
- error_propagate(errp, local_err);
- return;
- }
- error_free(local_err);
-
- blockdev_remove_medium(has_device, device, has_id, id, errp);
-}
-
void qmp_block_passwd(bool has_device, const char *device,
bool has_node_name, const char *node_name,
const char *password, Error **errp)
"Setting block passwords directly is no longer supported");
}
-/*
- * Attempt to open the tray of @device.
- * If @force, ignore its tray lock.
- * Else, if the tray is locked, don't open it, but ask the guest to open it.
- * On error, store an error through @errp and return -errno.
- * If @device does not exist, return -ENODEV.
- * If it has no removable media, return -ENOTSUP.
- * If it has no tray, return -ENOSYS.
- * If the guest was asked to open the tray, return -EINPROGRESS.
- * Else, return 0.
- */
-static int do_open_tray(const char *blk_name, const char *qdev_id,
- bool force, Error **errp)
+BlockDirtyBitmapSha256 *qmp_x_debug_block_dirty_bitmap_sha256(const char *node,
+ const char *name,
+ Error **errp)
{
- BlockBackend *blk;
- const char *device = qdev_id ?: blk_name;
- bool locked;
-
- blk = qmp_get_blk(blk_name, qdev_id, errp);
- if (!blk) {
- return -ENODEV;
- }
-
- if (!blk_dev_has_removable_media(blk)) {
- error_setg(errp, "Device '%s' is not removable", device);
- return -ENOTSUP;
- }
-
- if (!blk_dev_has_tray(blk)) {
- error_setg(errp, "Device '%s' does not have a tray", device);
- return -ENOSYS;
- }
-
- if (blk_dev_is_tray_open(blk)) {
- return 0;
- }
+ BdrvDirtyBitmap *bitmap;
+ BlockDriverState *bs;
+ BlockDirtyBitmapSha256 *ret = NULL;
+ char *sha256;
- locked = blk_dev_is_medium_locked(blk);
- if (locked) {
- blk_dev_eject_request(blk, force);
+ bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
+ if (!bitmap || !bs) {
+ return NULL;
}
- if (!locked || force) {
- blk_dev_change_media_cb(blk, false, &error_abort);
+ sha256 = bdrv_dirty_bitmap_sha256(bitmap, errp);
+ if (sha256 == NULL) {
+ return NULL;
}
- if (locked && !force) {
- error_setg(errp, "Device '%s' is locked and force was not specified, "
- "wait for tray to open and try again", device);
- return -EINPROGRESS;
- }
+ ret = g_new(BlockDirtyBitmapSha256, 1);
+ ret->sha256 = sha256;
- return 0;
+ return ret;
}
-void qmp_blockdev_open_tray(bool has_device, const char *device,
- bool has_id, const char *id,
- bool has_force, bool force,
- Error **errp)
+void qmp_block_resize(bool has_device, const char *device,
+ bool has_node_name, const char *node_name,
+ int64_t size, Error **errp)
{
Error *local_err = NULL;
- int rc;
-
- if (!has_force) {
- force = false;
- }
- rc = do_open_tray(has_device ? device : NULL,
- has_id ? id : NULL,
- force, &local_err);
- if (rc && rc != -ENOSYS && rc != -EINPROGRESS) {
- error_propagate(errp, local_err);
- return;
- }
- error_free(local_err);
-}
-
-void qmp_blockdev_close_tray(bool has_device, const char *device,
- bool has_id, const char *id,
- Error **errp)
-{
- BlockBackend *blk;
- Error *local_err = NULL;
-
- device = has_device ? device : NULL;
- id = has_id ? id : NULL;
-
- blk = qmp_get_blk(device, id, errp);
- if (!blk) {
- return;
- }
-
- if (!blk_dev_has_removable_media(blk)) {
- error_setg(errp, "Device '%s' is not removable", device ?: id);
- return;
- }
-
- if (!blk_dev_has_tray(blk)) {
- /* Ignore this command on tray-less devices */
- return;
- }
-
- if (!blk_dev_is_tray_open(blk)) {
- return;
- }
-
- blk_dev_change_media_cb(blk, true, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-}
-
-static void blockdev_remove_medium(bool has_device, const char *device,
- bool has_id, const char *id, Error **errp)
-{
- BlockBackend *blk;
- BlockDriverState *bs;
- AioContext *aio_context;
- bool has_attached_device;
-
- device = has_device ? device : NULL;
- id = has_id ? id : NULL;
-
- blk = qmp_get_blk(device, id, errp);
- if (!blk) {
- return;
- }
-
- /* For BBs without a device, we can exchange the BDS tree at will */
- has_attached_device = blk_get_attached_dev(blk);
-
- if (has_attached_device && !blk_dev_has_removable_media(blk)) {
- error_setg(errp, "Device '%s' is not removable", device ?: id);
- return;
- }
-
- if (has_attached_device && blk_dev_has_tray(blk) &&
- !blk_dev_is_tray_open(blk))
- {
- error_setg(errp, "Tray of device '%s' is not open", device ?: id);
- return;
- }
-
- bs = blk_bs(blk);
- if (!bs) {
- return;
- }
-
- aio_context = bdrv_get_aio_context(bs);
- aio_context_acquire(aio_context);
-
- if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) {
- goto out;
- }
-
- 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, &error_abort);
- }
-
-out:
- aio_context_release(aio_context);
-}
-
-void qmp_blockdev_remove_medium(const char *id, Error **errp)
-{
- blockdev_remove_medium(false, NULL, true, id, errp);
-}
-
-static void qmp_blockdev_insert_anon_medium(BlockBackend *blk,
- BlockDriverState *bs, Error **errp)
-{
- Error *local_err = NULL;
- bool has_device;
- int ret;
-
- /* For BBs without a device, we can exchange the BDS tree at will */
- has_device = blk_get_attached_dev(blk);
-
- if (has_device && !blk_dev_has_removable_media(blk)) {
- error_setg(errp, "Device is not removable");
- return;
- }
-
- if (has_device && blk_dev_has_tray(blk) && !blk_dev_is_tray_open(blk)) {
- error_setg(errp, "Tray of the device is not open");
- return;
- }
-
- if (blk_bs(blk)) {
- error_setg(errp, "There already is a medium in the device");
- return;
- }
-
- ret = blk_insert_bs(blk, bs, errp);
- if (ret < 0) {
- return;
- }
-
- 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, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- blk_remove_bs(blk);
- return;
- }
- }
-}
-
-static void blockdev_insert_medium(bool has_device, const char *device,
- bool has_id, const char *id,
- const char *node_name, Error **errp)
-{
- BlockBackend *blk;
- BlockDriverState *bs;
-
- blk = qmp_get_blk(has_device ? device : NULL,
- has_id ? id : NULL,
- errp);
- if (!blk) {
- return;
- }
-
- bs = bdrv_find_node(node_name);
- if (!bs) {
- error_setg(errp, "Node '%s' not found", node_name);
- return;
- }
-
- if (bdrv_has_blk(bs)) {
- error_setg(errp, "Node '%s' is already in use", node_name);
- return;
- }
-
- qmp_blockdev_insert_anon_medium(blk, bs, errp);
-}
-
-void qmp_blockdev_insert_medium(const char *id, const char *node_name,
- Error **errp)
-{
- blockdev_insert_medium(false, NULL, true, id, node_name, errp);
-}
-
-void qmp_blockdev_change_medium(bool has_device, const char *device,
- bool has_id, const char *id,
- const char *filename,
- bool has_format, const char *format,
- bool has_read_only,
- BlockdevChangeReadOnlyMode read_only,
- Error **errp)
-{
- BlockBackend *blk;
- BlockDriverState *medium_bs = NULL;
- int bdrv_flags;
- bool detect_zeroes;
- int rc;
- QDict *options = NULL;
- Error *err = NULL;
-
- blk = qmp_get_blk(has_device ? device : NULL,
- has_id ? id : NULL,
- errp);
- if (!blk) {
- goto fail;
- }
-
- if (blk_bs(blk)) {
- blk_update_root_state(blk);
- }
-
- 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 | BDRV_O_AUTO_RDONLY);
-
- if (!has_read_only) {
- read_only = BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN;
- }
-
- switch (read_only) {
- case BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN:
- break;
-
- case BLOCKDEV_CHANGE_READ_ONLY_MODE_READ_ONLY:
- bdrv_flags &= ~BDRV_O_RDWR;
- break;
-
- case BLOCKDEV_CHANGE_READ_ONLY_MODE_READ_WRITE:
- bdrv_flags |= BDRV_O_RDWR;
- break;
-
- default:
- abort();
- }
-
- options = qdict_new();
- detect_zeroes = blk_get_detect_zeroes_from_root_state(blk);
- qdict_put_str(options, "detect-zeroes", detect_zeroes ? "on" : "off");
-
- if (has_format) {
- qdict_put_str(options, "driver", format);
- }
-
- medium_bs = bdrv_open(filename, NULL, options, bdrv_flags, errp);
- if (!medium_bs) {
- goto fail;
- }
-
- rc = do_open_tray(has_device ? device : NULL,
- has_id ? id : NULL,
- false, &err);
- if (rc && rc != -ENOSYS) {
- error_propagate(errp, err);
- goto fail;
- }
- error_free(err);
- err = NULL;
-
- blockdev_remove_medium(has_device, device, has_id, id, &err);
- if (err) {
- error_propagate(errp, err);
- goto fail;
- }
-
- qmp_blockdev_insert_anon_medium(blk, medium_bs, &err);
- if (err) {
- error_propagate(errp, err);
- goto fail;
- }
-
- qmp_blockdev_close_tray(has_device, device, has_id, id, errp);
-
-fail:
- /* If the medium has been inserted, the device has its own reference, so
- * ours must be relinquished; and if it has not been inserted successfully,
- * the reference must be relinquished anyway */
- bdrv_unref(medium_bs);
-}
-
-/* throttling disk I/O limits */
-void qmp_block_set_io_throttle(BlockIOThrottle *arg, Error **errp)
-{
- ThrottleConfig cfg;
- BlockDriverState *bs;
- BlockBackend *blk;
- AioContext *aio_context;
-
- blk = qmp_get_blk(arg->has_device ? arg->device : NULL,
- arg->has_id ? arg->id : NULL,
- errp);
- if (!blk) {
- return;
- }
-
- aio_context = blk_get_aio_context(blk);
- aio_context_acquire(aio_context);
-
- bs = blk_bs(blk);
- if (!bs) {
- error_setg(errp, "Device has no medium");
- goto out;
- }
-
- throttle_config_init(&cfg);
- cfg.buckets[THROTTLE_BPS_TOTAL].avg = arg->bps;
- cfg.buckets[THROTTLE_BPS_READ].avg = arg->bps_rd;
- cfg.buckets[THROTTLE_BPS_WRITE].avg = arg->bps_wr;
-
- cfg.buckets[THROTTLE_OPS_TOTAL].avg = arg->iops;
- cfg.buckets[THROTTLE_OPS_READ].avg = arg->iops_rd;
- cfg.buckets[THROTTLE_OPS_WRITE].avg = arg->iops_wr;
-
- if (arg->has_bps_max) {
- cfg.buckets[THROTTLE_BPS_TOTAL].max = arg->bps_max;
- }
- if (arg->has_bps_rd_max) {
- cfg.buckets[THROTTLE_BPS_READ].max = arg->bps_rd_max;
- }
- if (arg->has_bps_wr_max) {
- cfg.buckets[THROTTLE_BPS_WRITE].max = arg->bps_wr_max;
- }
- if (arg->has_iops_max) {
- cfg.buckets[THROTTLE_OPS_TOTAL].max = arg->iops_max;
- }
- if (arg->has_iops_rd_max) {
- cfg.buckets[THROTTLE_OPS_READ].max = arg->iops_rd_max;
- }
- if (arg->has_iops_wr_max) {
- cfg.buckets[THROTTLE_OPS_WRITE].max = arg->iops_wr_max;
- }
-
- if (arg->has_bps_max_length) {
- cfg.buckets[THROTTLE_BPS_TOTAL].burst_length = arg->bps_max_length;
- }
- if (arg->has_bps_rd_max_length) {
- cfg.buckets[THROTTLE_BPS_READ].burst_length = arg->bps_rd_max_length;
- }
- if (arg->has_bps_wr_max_length) {
- cfg.buckets[THROTTLE_BPS_WRITE].burst_length = arg->bps_wr_max_length;
- }
- if (arg->has_iops_max_length) {
- cfg.buckets[THROTTLE_OPS_TOTAL].burst_length = arg->iops_max_length;
- }
- if (arg->has_iops_rd_max_length) {
- cfg.buckets[THROTTLE_OPS_READ].burst_length = arg->iops_rd_max_length;
- }
- if (arg->has_iops_wr_max_length) {
- cfg.buckets[THROTTLE_OPS_WRITE].burst_length = arg->iops_wr_max_length;
- }
-
- if (arg->has_iops_size) {
- cfg.op_size = arg->iops_size;
- }
-
- if (!throttle_is_valid(&cfg, errp)) {
- goto out;
- }
-
- if (throttle_enabled(&cfg)) {
- /* Enable I/O limits if they're not enabled yet, otherwise
- * just update the throttling group. */
- if (!blk_get_public(blk)->throttle_group_member.throttle_state) {
- blk_io_limits_enable(blk,
- arg->has_group ? arg->group :
- arg->has_device ? arg->device :
- arg->id);
- } else if (arg->has_group) {
- blk_io_limits_update_group(blk, arg->group);
- }
- /* Set the new throttling configuration */
- blk_set_io_limits(blk, &cfg);
- } else if (blk_get_public(blk)->throttle_group_member.throttle_state) {
- /* If all throttling settings are set to 0, disable I/O limits */
- blk_io_limits_disable(blk);
- }
-
-out:
- aio_context_release(aio_context);
-}
-
-void qmp_block_dirty_bitmap_add(const char *node, const char *name,
- bool has_granularity, uint32_t granularity,
- bool has_persistent, bool persistent,
- bool has_autoload, bool autoload,
- bool has_disabled, bool disabled,
- Error **errp)
-{
- BlockDriverState *bs;
- BdrvDirtyBitmap *bitmap;
-
- if (!name || name[0] == '\0') {
- error_setg(errp, "Bitmap name cannot be empty");
- return;
- }
-
- bs = bdrv_lookup_bs(node, node, errp);
- if (!bs) {
- return;
- }
-
- if (has_granularity) {
- if (granularity < 512 || !is_power_of_2(granularity)) {
- error_setg(errp, "Granularity must be power of 2 "
- "and at least 512");
- return;
- }
- } else {
- /* Default to cluster size, if available: */
- granularity = bdrv_get_default_bitmap_granularity(bs);
- }
-
- if (!has_persistent) {
- persistent = false;
- }
-
- if (has_autoload) {
- warn_report("Autoload option is deprecated and its value is ignored");
- }
-
- if (!has_disabled) {
- disabled = false;
- }
-
- if (persistent) {
- AioContext *aio_context = bdrv_get_aio_context(bs);
- bool ok;
-
- aio_context_acquire(aio_context);
- ok = bdrv_can_store_new_dirty_bitmap(bs, name, granularity, errp);
- aio_context_release(aio_context);
- if (!ok) {
- return;
- }
- }
-
- bitmap = bdrv_create_dirty_bitmap(bs, granularity, name, errp);
- if (bitmap == NULL) {
- return;
- }
-
- if (disabled) {
- bdrv_disable_dirty_bitmap(bitmap);
- }
-
- bdrv_dirty_bitmap_set_persistence(bitmap, persistent);
-}
-
-static BdrvDirtyBitmap *do_block_dirty_bitmap_remove(
- const char *node, const char *name, bool release,
- BlockDriverState **bitmap_bs, Error **errp)
-{
- BlockDriverState *bs;
- BdrvDirtyBitmap *bitmap;
-
- bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
- if (!bitmap || !bs) {
- return NULL;
- }
-
- if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_BUSY | BDRV_BITMAP_RO,
- errp)) {
- return NULL;
- }
-
- if (bdrv_dirty_bitmap_get_persistence(bitmap)) {
- AioContext *aio_context = bdrv_get_aio_context(bs);
- Error *local_err = NULL;
-
- aio_context_acquire(aio_context);
- bdrv_remove_persistent_dirty_bitmap(bs, name, &local_err);
- aio_context_release(aio_context);
-
- if (local_err != NULL) {
- error_propagate(errp, local_err);
- return NULL;
- }
- }
-
- if (release) {
- bdrv_release_dirty_bitmap(bs, bitmap);
- }
-
- if (bitmap_bs) {
- *bitmap_bs = bs;
- }
-
- return release ? NULL : bitmap;
-}
-
-void qmp_block_dirty_bitmap_remove(const char *node, const char *name,
- Error **errp)
-{
- do_block_dirty_bitmap_remove(node, name, true, NULL, errp);
-}
-
-/**
- * Completely clear a bitmap, for the purposes of synchronizing a bitmap
- * immediately after a full backup operation.
- */
-void qmp_block_dirty_bitmap_clear(const char *node, const char *name,
- Error **errp)
-{
- BdrvDirtyBitmap *bitmap;
- BlockDriverState *bs;
-
- bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
- if (!bitmap || !bs) {
- return;
- }
-
- if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_DEFAULT, errp)) {
- return;
- }
-
- bdrv_clear_dirty_bitmap(bitmap, NULL);
-}
-
-void qmp_block_dirty_bitmap_enable(const char *node, const char *name,
- Error **errp)
-{
- BlockDriverState *bs;
- BdrvDirtyBitmap *bitmap;
-
- bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
- if (!bitmap) {
- return;
- }
-
- if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_ALLOW_RO, errp)) {
- return;
- }
-
- bdrv_enable_dirty_bitmap(bitmap);
-}
-
-void qmp_block_dirty_bitmap_disable(const char *node, const char *name,
- Error **errp)
-{
- BlockDriverState *bs;
- BdrvDirtyBitmap *bitmap;
-
- bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
- if (!bitmap) {
- return;
- }
-
- if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_ALLOW_RO, errp)) {
- return;
- }
-
- bdrv_disable_dirty_bitmap(bitmap);
-}
-
-static BdrvDirtyBitmap *do_block_dirty_bitmap_merge(
- const char *node, const char *target,
- BlockDirtyBitmapMergeSourceList *bitmaps,
- HBitmap **backup, Error **errp)
-{
- BlockDriverState *bs;
- BdrvDirtyBitmap *dst, *src, *anon;
- BlockDirtyBitmapMergeSourceList *lst;
- Error *local_err = NULL;
-
- dst = block_dirty_bitmap_lookup(node, target, &bs, errp);
- if (!dst) {
- return NULL;
- }
-
- anon = bdrv_create_dirty_bitmap(bs, bdrv_dirty_bitmap_granularity(dst),
- NULL, errp);
- if (!anon) {
- return NULL;
- }
-
- for (lst = bitmaps; lst; lst = lst->next) {
- switch (lst->value->type) {
- const char *name, *node;
- case QTYPE_QSTRING:
- name = lst->value->u.local;
- src = bdrv_find_dirty_bitmap(bs, name);
- if (!src) {
- error_setg(errp, "Dirty bitmap '%s' not found", name);
- dst = NULL;
- goto out;
- }
- break;
- case QTYPE_QDICT:
- node = lst->value->u.external.node;
- name = lst->value->u.external.name;
- src = block_dirty_bitmap_lookup(node, name, NULL, errp);
- if (!src) {
- dst = NULL;
- goto out;
- }
- break;
- default:
- abort();
- }
-
- bdrv_merge_dirty_bitmap(anon, src, NULL, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- dst = NULL;
- goto out;
- }
- }
-
- /* Merge into dst; dst is unchanged on failure. */
- bdrv_merge_dirty_bitmap(dst, anon, backup, errp);
-
- out:
- bdrv_release_dirty_bitmap(bs, anon);
- return dst;
-}
-
-void qmp_block_dirty_bitmap_merge(const char *node, const char *target,
- BlockDirtyBitmapMergeSourceList *bitmaps,
- Error **errp)
-{
- do_block_dirty_bitmap_merge(node, target, bitmaps, NULL, errp);
-}
-
-BlockDirtyBitmapSha256 *qmp_x_debug_block_dirty_bitmap_sha256(const char *node,
- const char *name,
- Error **errp)
-{
- BdrvDirtyBitmap *bitmap;
- BlockDriverState *bs;
- BlockDirtyBitmapSha256 *ret = NULL;
- char *sha256;
-
- bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
- if (!bitmap || !bs) {
- return NULL;
- }
-
- sha256 = bdrv_dirty_bitmap_sha256(bitmap, errp);
- if (sha256 == NULL) {
- return NULL;
- }
-
- ret = g_new(BlockDirtyBitmapSha256, 1);
- ret->sha256 = sha256;
-
- return ret;
-}
-
-void hmp_drive_del(Monitor *mon, const QDict *qdict)
-{
- const char *id = qdict_get_str(qdict, "id");
- BlockBackend *blk;
- BlockDriverState *bs;
- AioContext *aio_context;
- Error *local_err = NULL;
-
- bs = bdrv_find_node(id);
- if (bs) {
- qmp_blockdev_del(id, &local_err);
- if (local_err) {
- error_report_err(local_err);
- }
- return;
- }
-
- blk = blk_by_name(id);
- if (!blk) {
- error_report("Device '%s' not found", id);
- return;
- }
-
- if (!blk_legacy_dinfo(blk)) {
- error_report("Deleting device added with blockdev-add"
- " is not supported");
- return;
- }
-
- aio_context = blk_get_aio_context(blk);
- aio_context_acquire(aio_context);
-
- bs = blk_bs(blk);
- if (bs) {
- if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_DRIVE_DEL, &local_err)) {
- error_report_err(local_err);
- aio_context_release(aio_context);
- return;
- }
-
- blk_remove_bs(blk);
- }
-
- /* Make the BlockBackend and the attached BlockDriverState anonymous */
- monitor_remove_blk(blk);
-
- /* If this BlockBackend has a device attached to it, its refcount will be
- * decremented when the device is removed; otherwise we have to do so here.
- */
- if (blk_get_attached_dev(blk)) {
- /* Further I/O must not pause the guest */
- blk_set_on_error(blk, BLOCKDEV_ON_ERROR_REPORT,
- BLOCKDEV_ON_ERROR_REPORT);
- } else {
- blk_unref(blk);
- }
-
- aio_context_release(aio_context);
-}
-
-void qmp_block_resize(bool has_device, const char *device,
- bool has_node_name, const char *node_name,
- int64_t size, Error **errp)
-{
- Error *local_err = NULL;
- BlockBackend *blk = NULL;
- BlockDriverState *bs;
- AioContext *aio_context;
- int ret;
+ BlockBackend *blk = NULL;
+ BlockDriverState *bs;
+ AioContext *aio_context;
bs = bdrv_lookup_bs(has_device ? device : NULL,
has_node_name ? node_name : NULL,
aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context);
- if (!bdrv_is_first_non_filter(bs)) {
- error_setg(errp, QERR_FEATURE_DISABLED, "resize");
- goto out;
- }
-
if (size < 0) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "size", "a >0 size");
goto out;
goto out;
}
- blk = blk_new(bdrv_get_aio_context(bs), BLK_PERM_RESIZE, BLK_PERM_ALL);
- ret = blk_insert_bs(blk, bs, errp);
- if (ret < 0) {
+ blk = blk_new_with_bs(bs, BLK_PERM_RESIZE, BLK_PERM_ALL, errp);
+ if (!blk) {
goto out;
}
bdrv_drained_begin(bs);
- ret = blk_truncate(blk, size, PREALLOC_MODE_OFF, errp);
+ blk_truncate(blk, size, false, PREALLOC_MODE_OFF, 0, errp);
bdrv_drained_end(bs);
out:
bool has_top, const char *top,
bool has_backing_file, const char *backing_file,
bool has_speed, int64_t speed,
+ bool has_on_error, BlockdevOnError on_error,
bool has_filter_node_name, const char *filter_node_name,
bool has_auto_finalize, bool auto_finalize,
bool has_auto_dismiss, bool auto_dismiss,
BlockDriverState *base_bs, *top_bs;
AioContext *aio_context;
Error *local_err = NULL;
- /* This will be part of the QMP command, if/when the
- * BlockdevOnError change for blkmirror makes it in
- */
- BlockdevOnError on_error = BLOCKDEV_ON_ERROR_REPORT;
int job_flags = JOB_DEFAULT;
if (!has_speed) {
speed = 0;
}
+ if (!has_on_error) {
+ on_error = BLOCKDEV_ON_ERROR_REPORT;
+ }
if (!has_filter_node_name) {
filter_node_name = NULL;
}
BlockJob *job = NULL;
BdrvDirtyBitmap *bmap = NULL;
int job_flags = JOB_DEFAULT;
- int ret;
if (!backup->has_speed) {
backup->speed = 0;
backup->compress = false;
}
- ret = bdrv_try_set_aio_context(target_bs, aio_context, errp);
- if (ret < 0) {
- return NULL;
- }
-
if ((backup->sync == MIRROR_SYNC_MODE_BITMAP) ||
(backup->sync == MIRROR_SYNC_MODE_INCREMENTAL)) {
/* done before desugaring 'incremental' to print the right message */
return job;
}
-static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn,
- Error **errp)
+void qmp_drive_backup(DriveBackup *backup, Error **errp)
{
- BlockDriverState *bs;
- BlockDriverState *target_bs;
- BlockDriverState *source = NULL;
- BlockJob *job = NULL;
- AioContext *aio_context;
- QDict *options;
- Error *local_err = NULL;
- int flags;
- int64_t size;
- bool set_backing_hd = false;
-
- if (!backup->has_mode) {
- backup->mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;
- }
-
- bs = bdrv_lookup_bs(backup->device, backup->device, errp);
- if (!bs) {
- return NULL;
- }
-
- if (!bs->drv) {
- error_setg(errp, "Device has no medium");
- return NULL;
- }
-
- aio_context = bdrv_get_aio_context(bs);
- aio_context_acquire(aio_context);
-
- if (!backup->has_format) {
- backup->format = backup->mode == NEW_IMAGE_MODE_EXISTING ?
- NULL : (char*) bs->drv->format_name;
- }
-
- /* Early check to avoid creating target */
- if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) {
- goto out;
- }
-
- flags = bs->open_flags | BDRV_O_RDWR;
-
- /* See if we have a backing HD we can use to create our new image
- * on top of. */
- if (backup->sync == MIRROR_SYNC_MODE_TOP) {
- source = backing_bs(bs);
- if (!source) {
- backup->sync = MIRROR_SYNC_MODE_FULL;
- }
- }
- if (backup->sync == MIRROR_SYNC_MODE_NONE) {
- source = bs;
- flags |= BDRV_O_NO_BACKING;
- set_backing_hd = true;
- }
-
- size = bdrv_getlength(bs);
- if (size < 0) {
- error_setg_errno(errp, -size, "bdrv_getlength failed");
- goto out;
- }
-
- if (backup->mode != NEW_IMAGE_MODE_EXISTING) {
- assert(backup->format);
- if (source) {
- bdrv_refresh_filename(source);
- bdrv_img_create(backup->target, backup->format, source->filename,
- source->drv->format_name, NULL,
- size, flags, false, &local_err);
- } else {
- bdrv_img_create(backup->target, backup->format, NULL, NULL, NULL,
- size, flags, false, &local_err);
- }
- }
-
- if (local_err) {
- error_propagate(errp, local_err);
- goto out;
- }
-
- options = qdict_new();
- qdict_put_str(options, "discard", "unmap");
- qdict_put_str(options, "detect-zeroes", "unmap");
- if (backup->format) {
- qdict_put_str(options, "driver", backup->format);
- }
-
- target_bs = bdrv_open(backup->target, NULL, options, flags, errp);
- if (!target_bs) {
- goto out;
- }
-
- if (set_backing_hd) {
- bdrv_set_backing_hd(target_bs, source, &local_err);
- if (local_err) {
- goto unref;
- }
- }
-
- job = do_backup_common(qapi_DriveBackup_base(backup),
- bs, target_bs, aio_context, txn, errp);
-
-unref:
- bdrv_unref(target_bs);
-out:
- aio_context_release(aio_context);
- return job;
+ TransactionAction action = {
+ .type = TRANSACTION_ACTION_KIND_DRIVE_BACKUP,
+ .u.drive_backup.data = backup,
+ };
+ blockdev_do_action(&action, errp);
}
-void qmp_drive_backup(DriveBackup *arg, Error **errp)
+BlockDeviceInfoList *qmp_query_named_block_nodes(bool has_flat,
+ bool flat,
+ Error **errp)
{
+ bool return_flat = has_flat && flat;
- BlockJob *job;
- job = do_drive_backup(arg, NULL, errp);
- if (job) {
- job_start(&job->job);
- }
-}
-
-BlockDeviceInfoList *qmp_query_named_block_nodes(Error **errp)
-{
- return bdrv_named_nodes_list(errp);
+ return bdrv_named_nodes_list(return_flat, errp);
}
XDbgBlockGraph *qmp_x_debug_query_block_graph(Error **errp)
return bdrv_get_xdbg_block_graph(errp);
}
-BlockJob *do_blockdev_backup(BlockdevBackup *backup, JobTxn *txn,
- Error **errp)
-{
- BlockDriverState *bs;
- BlockDriverState *target_bs;
- AioContext *aio_context;
- BlockJob *job;
-
- bs = bdrv_lookup_bs(backup->device, backup->device, errp);
- if (!bs) {
- return NULL;
- }
-
- target_bs = bdrv_lookup_bs(backup->target, backup->target, errp);
- if (!target_bs) {
- return NULL;
- }
-
- aio_context = bdrv_get_aio_context(bs);
- aio_context_acquire(aio_context);
-
- job = do_backup_common(qapi_BlockdevBackup_base(backup),
- bs, target_bs, aio_context, txn, errp);
-
- aio_context_release(aio_context);
- return job;
-}
-
-void qmp_blockdev_backup(BlockdevBackup *arg, Error **errp)
+void qmp_blockdev_backup(BlockdevBackup *backup, Error **errp)
{
- BlockJob *job;
- job = do_blockdev_backup(arg, NULL, errp);
- if (job) {
- job_start(&job->job);
- }
+ TransactionAction action = {
+ .type = TRANSACTION_ACTION_KIND_BLOCKDEV_BACKUP,
+ .u.blockdev_backup.data = backup,
+ };
+ blockdev_do_action(&action, errp);
}
/* Parameter check and block job starting for drive mirroring.
BlockDriverState *bs;
BlockDriverState *source, *target_bs;
AioContext *aio_context;
+ AioContext *old_context;
BlockMirrorBackingMode backing_mode;
Error *local_err = NULL;
QDict *options = NULL;
(arg->mode == NEW_IMAGE_MODE_EXISTING ||
!bdrv_has_zero_init(target_bs)));
+
+ /* Honor bdrv_try_set_aio_context() context acquisition requirements. */
+ old_context = bdrv_get_aio_context(target_bs);
+ aio_context_release(aio_context);
+ aio_context_acquire(old_context);
+
ret = bdrv_try_set_aio_context(target_bs, aio_context, errp);
if (ret < 0) {
bdrv_unref(target_bs);
- goto out;
+ aio_context_release(old_context);
+ return;
}
+ aio_context_release(old_context);
+ aio_context_acquire(aio_context);
+
blockdev_mirror_common(arg->has_job_id ? arg->job_id : NULL, bs, target_bs,
arg->has_replaces, arg->replaces, arg->sync,
backing_mode, zero_target,
BlockDriverState *bs;
BlockDriverState *target_bs;
AioContext *aio_context;
+ AioContext *old_context;
BlockMirrorBackingMode backing_mode = MIRROR_LEAVE_BACKING_CHAIN;
Error *local_err = NULL;
bool zero_target;
zero_target = (sync == MIRROR_SYNC_MODE_FULL);
+ /* Honor bdrv_try_set_aio_context() context acquisition requirements. */
+ old_context = bdrv_get_aio_context(target_bs);
aio_context = bdrv_get_aio_context(bs);
- aio_context_acquire(aio_context);
+ aio_context_acquire(old_context);
ret = bdrv_try_set_aio_context(target_bs, aio_context, errp);
+
+ aio_context_release(old_context);
+ aio_context_acquire(aio_context);
+
if (ret < 0) {
goto out;
}
}
trace_qmp_block_job_finalize(job);
+ job_ref(&job->job);
job_finalize(&job->job, errp);
+
+ /*
+ * Job's context might have changed via job_finalize (and job_txn_apply
+ * automatically acquires the new one), so make sure we release the correct
+ * one.
+ */
+ aio_context = blk_get_aio_context(job->blk);
+ job_unref(&job->job);
aio_context_release(aio_context);
}
aio_context_release(aio_context);
}
-void hmp_drive_add_node(Monitor *mon, const char *optstr)
-{
- QemuOpts *opts;
- QDict *qdict;
- Error *local_err = NULL;
-
- opts = qemu_opts_parse_noisily(&qemu_drive_opts, optstr, false);
- if (!opts) {
- return;
- }
-
- qdict = qemu_opts_to_qdict(opts, NULL);
-
- if (!qdict_get_try_str(qdict, "node-name")) {
- qobject_unref(qdict);
- error_report("'node-name' needs to be specified");
- goto out;
- }
-
- BlockDriverState *bs = bds_tree_init(qdict, &local_err);
- if (!bs) {
- error_report_err(local_err);
- goto out;
- }
-
- QTAILQ_INSERT_TAIL(&monitor_bdrv_states, bs, monitor_list);
-
-out:
- qemu_opts_del(opts);
-}
-
void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
{
BlockDriverState *bs;
QObject *obj;
Visitor *v = qobject_output_visitor_new(&obj);
QDict *qdict;
- Error *local_err = NULL;
-
- visit_type_BlockdevOptions(v, NULL, &options, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- goto fail;
- }
+ visit_type_BlockdevOptions(v, NULL, &options, &error_abort);
visit_complete(v, &obj);
qdict = qobject_to(QDict, obj);
goto fail;
}
- QTAILQ_INSERT_TAIL(&monitor_bdrv_states, bs, monitor_list);
+ bdrv_set_monitor_owned(bs);
fail:
visit_free(v);
AioContext *ctx;
QObject *obj;
Visitor *v = qobject_output_visitor_new(&obj);
- Error *local_err = NULL;
BlockReopenQueue *queue;
QDict *qdict;
}
/* Put all options in a QDict and flatten it */
- visit_type_BlockdevOptions(v, NULL, &options, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- goto fail;
- }
-
+ visit_type_BlockdevOptions(v, NULL, &options, &error_abort);
visit_complete(v, &obj);
qdict = qobject_to(QDict, obj);
aio_context_release(old_context);
}
-void qmp_block_latency_histogram_set(
- const char *id,
- bool has_boundaries, uint64List *boundaries,
- bool has_boundaries_read, uint64List *boundaries_read,
- bool has_boundaries_write, uint64List *boundaries_write,
- bool has_boundaries_flush, uint64List *boundaries_flush,
- Error **errp)
-{
- BlockBackend *blk = qmp_get_blk(NULL, id, errp);
- BlockAcctStats *stats;
- int ret;
-
- if (!blk) {
- return;
- }
-
- stats = blk_get_stats(blk);
-
- if (!has_boundaries && !has_boundaries_read && !has_boundaries_write &&
- !has_boundaries_flush)
- {
- block_latency_histograms_clear(stats);
- return;
- }
-
- if (has_boundaries || has_boundaries_read) {
- ret = block_latency_histogram_set(
- stats, BLOCK_ACCT_READ,
- has_boundaries_read ? boundaries_read : boundaries);
- if (ret) {
- error_setg(errp, "Device '%s' set read boundaries fail", id);
- return;
- }
- }
-
- if (has_boundaries || has_boundaries_write) {
- ret = block_latency_histogram_set(
- stats, BLOCK_ACCT_WRITE,
- has_boundaries_write ? boundaries_write : boundaries);
- if (ret) {
- error_setg(errp, "Device '%s' set write boundaries fail", id);
- return;
- }
- }
-
- if (has_boundaries || has_boundaries_flush) {
- ret = block_latency_histogram_set(
- stats, BLOCK_ACCT_FLUSH,
- has_boundaries_flush ? boundaries_flush : boundaries);
- if (ret) {
- error_setg(errp, "Device '%s' set flush boundaries fail", id);
- return;
- }
- }
-}
-
QemuOptsList qemu_common_drive_opts = {
.name = "drive",
.head = QTAILQ_HEAD_INITIALIZER(qemu_common_drive_opts.head),
},{
.name = "aio",
.type = QEMU_OPT_STRING,
- .help = "host AIO implementation (threads, native)",
+ .help = "host AIO implementation (threads, native, io_uring)",
},{
.name = BDRV_OPT_CACHE_WB,
.type = QEMU_OPT_BOOL,