Block layer patches
-----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABAgAGBQJX5RkyAAoJEH8JsnLIjy/WMnYP/i03Ii6nt8VY2PMX10NK3z+H 5QskSnGzBgQg0OVFPQkvV1nW8bXPN07n/L2Q0H9FzQXTUzCbAkQC4MkzBZTMgaUp 63XVRG151+AjqctvIncWQktUgMg6ywKBCug8G6gwMQ1BVsLerUJmE2tM0JGZF6WL q+F6uTtVMLNKR6miaTsJtFJA+ts9gGEecGNITRByEWbtD7ESF8TOXhCfpV/Ni45s 5pMVOQT0o9jwgjekrUbJ9PrlxGSLfe/bi3ypqy6boe8EXQS6DImAiDKWkTQjGj2P cGlZ0oxWHq0g/15sgZOzqDtOXqE02+RK9C1UcASgObfdUos6gFpi6G7cAffzP9aq wzhi8u8Beth2WZP8tLLAJtoQjJhcjutWSw60HPhEcHZNkkaZF3KMXGDk8j1xp5EN 8VVkWVZr+1ZOP+HsHCNrpvag+IP49DJ5j50W+oVqSKSzG37AC6SxNo3PEsg1urAi m5APFJbCgxMfDSnb8yw6ClBIe1IH624VMoELVzY1C9AqOnTxfJ08o4MbE8t1DEoa dQV/R3Mrqt3W+YflWNPXzVhRxD/mZW+RXPlBARYvFzHW12fh1PcwFWrB+ivdqu+4 x0VvmZebJcEP+CxmRQOat80Zhos1Hs+ZyxUHyA5a0+Nt3YhK7k3sr4CQXxr5MIHA 1c/D8znmWf9VksmW33U5 =JG9f -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging Block layer patches # gpg: Signature made Fri 23 Sep 2016 12:59:46 BST # gpg: using RSA key 0x7F09B272C88F2FD6 # gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" # Primary key fingerprint: DC3D EB15 9A9A F95D 3D74 56FE 7F09 B272 C88F 2FD6 * remotes/kevin/tags/for-upstream: (33 commits) block: Remove BB interface from blockdev-add/del qemu-iotests/141: Avoid blockdev-add with id block: Avoid printing NULL string in error messages qemu-iotests/139: Avoid blockdev-add with id qemu-iotests/124: Avoid blockdev-add with id qemu-iotests/118: Avoid blockdev-add with id qemu-iotests/117: Avoid blockdev-add with id qemu-iotests/087: Avoid blockdev-add with id qemu-iotests/081: Avoid blockdev-add with id qemu-iotests/071: Avoid blockdev-add with id qemu-iotests/067: Avoid blockdev-add with id qemu-iotests/041: Avoid blockdev-add with id qemu-iotests/118: Test media change with qdev name block: Accept device model name for block_set_io_throttle block: Accept device model name for blockdev-change-medium block: Accept device model name for eject block: Accept device model name for x-blockdev-remove-medium block: Accept device model name for x-blockdev-insert-medium block: Accept device model name for blockdev-open/close-tray qdev-monitor: Add blk_by_qdev_id() ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
		
						commit
						3b71ec8516
					
				
							
								
								
									
										83
									
								
								block.c
									
									
									
									
									
								
							
							
						
						
									
										83
									
								
								block.c
									
									
									
									
									
								
							@ -733,6 +733,9 @@ static void bdrv_temp_snapshot_options(int *child_flags, QDict *child_options,
 | 
			
		||||
    qdict_set_default_str(child_options, BDRV_OPT_CACHE_DIRECT, "off");
 | 
			
		||||
    qdict_set_default_str(child_options, BDRV_OPT_CACHE_NO_FLUSH, "on");
 | 
			
		||||
 | 
			
		||||
    /* Copy the read-only option from the parent */
 | 
			
		||||
    qdict_copy_default(child_options, parent_options, BDRV_OPT_READ_ONLY);
 | 
			
		||||
 | 
			
		||||
    /* aio=native doesn't work for cache.direct=off, so disable it for the
 | 
			
		||||
     * temporary snapshot */
 | 
			
		||||
    *child_flags &= ~BDRV_O_NATIVE_AIO;
 | 
			
		||||
@ -755,6 +758,9 @@ static void bdrv_inherited_options(int *child_flags, QDict *child_options,
 | 
			
		||||
    qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_DIRECT);
 | 
			
		||||
    qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_NO_FLUSH);
 | 
			
		||||
 | 
			
		||||
    /* Inherit the read-only option from the parent if it's not set */
 | 
			
		||||
    qdict_copy_default(child_options, parent_options, BDRV_OPT_READ_ONLY);
 | 
			
		||||
 | 
			
		||||
    /* Our block drivers take care to send flushes and respect unmap policy,
 | 
			
		||||
     * so we can default to enable both on lower layers regardless of the
 | 
			
		||||
     * corresponding parent options. */
 | 
			
		||||
@ -808,7 +814,8 @@ static void bdrv_backing_options(int *child_flags, QDict *child_options,
 | 
			
		||||
    qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_NO_FLUSH);
 | 
			
		||||
 | 
			
		||||
    /* backing files always opened read-only */
 | 
			
		||||
    flags &= ~(BDRV_O_RDWR | BDRV_O_COPY_ON_READ);
 | 
			
		||||
    qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "on");
 | 
			
		||||
    flags &= ~BDRV_O_COPY_ON_READ;
 | 
			
		||||
 | 
			
		||||
    /* snapshot=on is handled on the top layer */
 | 
			
		||||
    flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_TEMPORARY);
 | 
			
		||||
@ -855,6 +862,14 @@ static void update_flags_from_options(int *flags, QemuOpts *opts)
 | 
			
		||||
    if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_DIRECT, false)) {
 | 
			
		||||
        *flags |= BDRV_O_NOCACHE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    *flags &= ~BDRV_O_RDWR;
 | 
			
		||||
 | 
			
		||||
    assert(qemu_opt_find(opts, BDRV_OPT_READ_ONLY));
 | 
			
		||||
    if (!qemu_opt_get_bool(opts, BDRV_OPT_READ_ONLY, false)) {
 | 
			
		||||
        *flags |= BDRV_O_RDWR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void update_options_from_flags(QDict *options, int flags)
 | 
			
		||||
@ -867,6 +882,10 @@ static void update_options_from_flags(QDict *options, int flags)
 | 
			
		||||
        qdict_put(options, BDRV_OPT_CACHE_NO_FLUSH,
 | 
			
		||||
                  qbool_from_bool(flags & BDRV_O_NO_FLUSH));
 | 
			
		||||
    }
 | 
			
		||||
    if (!qdict_haskey(options, BDRV_OPT_READ_ONLY)) {
 | 
			
		||||
        qdict_put(options, BDRV_OPT_READ_ONLY,
 | 
			
		||||
                  qbool_from_bool(!(flags & BDRV_O_RDWR)));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void bdrv_assign_node_name(BlockDriverState *bs,
 | 
			
		||||
@ -930,6 +949,11 @@ static QemuOptsList bdrv_runtime_opts = {
 | 
			
		||||
            .type = QEMU_OPT_BOOL,
 | 
			
		||||
            .help = "Ignore flush requests",
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            .name = BDRV_OPT_READ_ONLY,
 | 
			
		||||
            .type = QEMU_OPT_BOOL,
 | 
			
		||||
            .help = "Node is opened in read-only mode",
 | 
			
		||||
        },
 | 
			
		||||
        { /* end of list */ }
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
@ -961,6 +985,8 @@ static int bdrv_open_common(BlockDriverState *bs, BdrvChild *file,
 | 
			
		||||
        goto fail_opts;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    update_flags_from_options(&bs->open_flags, opts);
 | 
			
		||||
 | 
			
		||||
    driver_name = qemu_opt_get(opts, "driver");
 | 
			
		||||
    drv = bdrv_find_format(driver_name);
 | 
			
		||||
    assert(drv != NULL);
 | 
			
		||||
@ -1022,9 +1048,6 @@ static int bdrv_open_common(BlockDriverState *bs, BdrvChild *file,
 | 
			
		||||
    bs->drv = drv;
 | 
			
		||||
    bs->opaque = g_malloc0(drv->instance_size);
 | 
			
		||||
 | 
			
		||||
    /* Apply cache mode options */
 | 
			
		||||
    update_flags_from_options(&bs->open_flags, opts);
 | 
			
		||||
 | 
			
		||||
    /* Open the image, either directly or using a protocol */
 | 
			
		||||
    open_flags = bdrv_open_flags(bs, bs->open_flags);
 | 
			
		||||
    if (drv->bdrv_file_open) {
 | 
			
		||||
@ -1675,6 +1698,25 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Set the BDRV_O_RDWR and BDRV_O_ALLOW_RDWR flags.
 | 
			
		||||
     * FIXME: we're parsing the QDict to avoid having to create a
 | 
			
		||||
     * QemuOpts just for this, but neither option is optimal. */
 | 
			
		||||
    if (g_strcmp0(qdict_get_try_str(options, BDRV_OPT_READ_ONLY), "on") &&
 | 
			
		||||
        !qdict_get_try_bool(options, BDRV_OPT_READ_ONLY, false)) {
 | 
			
		||||
        flags |= (BDRV_O_RDWR | BDRV_O_ALLOW_RDWR);
 | 
			
		||||
    } else {
 | 
			
		||||
        flags &= ~BDRV_O_RDWR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (flags & BDRV_O_SNAPSHOT) {
 | 
			
		||||
        snapshot_options = qdict_new();
 | 
			
		||||
        bdrv_temp_snapshot_options(&snapshot_flags, snapshot_options,
 | 
			
		||||
                                   flags, options);
 | 
			
		||||
        /* Let bdrv_backing_options() override "read-only" */
 | 
			
		||||
        qdict_del(options, BDRV_OPT_READ_ONLY);
 | 
			
		||||
        bdrv_backing_options(&flags, options, flags, options);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bs->open_flags = flags;
 | 
			
		||||
    bs->options = options;
 | 
			
		||||
    options = qdict_clone_shallow(options);
 | 
			
		||||
@ -1699,18 +1741,6 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
 | 
			
		||||
 | 
			
		||||
    /* Open image file without format layer */
 | 
			
		||||
    if ((flags & BDRV_O_PROTOCOL) == 0) {
 | 
			
		||||
        if (flags & BDRV_O_RDWR) {
 | 
			
		||||
            flags |= BDRV_O_ALLOW_RDWR;
 | 
			
		||||
        }
 | 
			
		||||
        if (flags & BDRV_O_SNAPSHOT) {
 | 
			
		||||
            snapshot_options = qdict_new();
 | 
			
		||||
            bdrv_temp_snapshot_options(&snapshot_flags, snapshot_options,
 | 
			
		||||
                                       flags, options);
 | 
			
		||||
            bdrv_backing_options(&flags, options, flags, options);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        bs->open_flags = flags;
 | 
			
		||||
 | 
			
		||||
        file = bdrv_open_child(filename, options, "file", bs,
 | 
			
		||||
                               &child_file, true, &local_err);
 | 
			
		||||
        if (local_err) {
 | 
			
		||||
@ -1895,6 +1925,13 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
 | 
			
		||||
        options = qdict_new();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Check if this BlockDriverState is already in the queue */
 | 
			
		||||
    QSIMPLEQ_FOREACH(bs_entry, bs_queue, entry) {
 | 
			
		||||
        if (bs == bs_entry->state.bs) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Precedence of options:
 | 
			
		||||
     * 1. Explicitly passed in options (highest)
 | 
			
		||||
@ -1915,7 +1952,11 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Old explicitly set values (don't overwrite by inherited value) */
 | 
			
		||||
    if (bs_entry) {
 | 
			
		||||
        old_options = qdict_clone_shallow(bs_entry->state.explicit_options);
 | 
			
		||||
    } else {
 | 
			
		||||
        old_options = qdict_clone_shallow(bs->explicit_options);
 | 
			
		||||
    }
 | 
			
		||||
    bdrv_join_options(bs, options, old_options);
 | 
			
		||||
    QDECREF(old_options);
 | 
			
		||||
 | 
			
		||||
@ -1954,8 +1995,13 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
 | 
			
		||||
                                child->role, options, flags);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!bs_entry) {
 | 
			
		||||
        bs_entry = g_new0(BlockReopenQueueEntry, 1);
 | 
			
		||||
        QSIMPLEQ_INSERT_TAIL(bs_queue, bs_entry, entry);
 | 
			
		||||
    } else {
 | 
			
		||||
        QDECREF(bs_entry->state.options);
 | 
			
		||||
        QDECREF(bs_entry->state.explicit_options);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bs_entry->state.bs = bs;
 | 
			
		||||
    bs_entry->state.options = options;
 | 
			
		||||
@ -3013,11 +3059,6 @@ bool bdrv_debug_is_suspended(BlockDriverState *bs, const char *tag)
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int bdrv_is_snapshot(BlockDriverState *bs)
 | 
			
		||||
{
 | 
			
		||||
    return !!(bs->open_flags & BDRV_O_SNAPSHOT);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* backing_file can either be relative, or absolute, or a protocol.  If it is
 | 
			
		||||
 * relative, it must be relative to the chain.  So, passing in bs->filename
 | 
			
		||||
 * from a BDS as backing_file should not be done, as that may be relative to
 | 
			
		||||
 | 
			
		||||
@ -559,6 +559,25 @@ void *blk_get_attached_dev(BlockBackend *blk)
 | 
			
		||||
    return blk->dev;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Return the BlockBackend which has the device model @dev attached if it
 | 
			
		||||
 * exists, else null.
 | 
			
		||||
 *
 | 
			
		||||
 * @dev must not be null.
 | 
			
		||||
 */
 | 
			
		||||
BlockBackend *blk_by_dev(void *dev)
 | 
			
		||||
{
 | 
			
		||||
    BlockBackend *blk = NULL;
 | 
			
		||||
 | 
			
		||||
    assert(dev != NULL);
 | 
			
		||||
    while ((blk = blk_all_next(blk)) != NULL) {
 | 
			
		||||
        if (blk->dev == dev) {
 | 
			
		||||
            return blk;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Set @blk's device model callbacks to @ops.
 | 
			
		||||
 * @opaque is the opaque argument to pass to the callbacks.
 | 
			
		||||
 | 
			
		||||
@ -242,14 +242,14 @@ void commit_start(const char *job_id, BlockDriverState *bs,
 | 
			
		||||
    orig_overlay_flags = bdrv_get_flags(overlay_bs);
 | 
			
		||||
 | 
			
		||||
    /* convert base & overlay_bs to r/w, if necessary */
 | 
			
		||||
    if (!(orig_overlay_flags & BDRV_O_RDWR)) {
 | 
			
		||||
        reopen_queue = bdrv_reopen_queue(reopen_queue, overlay_bs, NULL,
 | 
			
		||||
                                         orig_overlay_flags | BDRV_O_RDWR);
 | 
			
		||||
    }
 | 
			
		||||
    if (!(orig_base_flags & BDRV_O_RDWR)) {
 | 
			
		||||
        reopen_queue = bdrv_reopen_queue(reopen_queue, base, NULL,
 | 
			
		||||
                                         orig_base_flags | BDRV_O_RDWR);
 | 
			
		||||
    }
 | 
			
		||||
    if (!(orig_overlay_flags & BDRV_O_RDWR)) {
 | 
			
		||||
        reopen_queue = bdrv_reopen_queue(reopen_queue, overlay_bs, NULL,
 | 
			
		||||
                                         orig_overlay_flags | BDRV_O_RDWR);
 | 
			
		||||
    }
 | 
			
		||||
    if (reopen_queue) {
 | 
			
		||||
        bdrv_reopen_multiple(reopen_queue, &local_err);
 | 
			
		||||
        if (local_err != NULL) {
 | 
			
		||||
 | 
			
		||||
@ -429,7 +429,7 @@ static int coroutine_fn do_perform_cow(BlockDriverState *bs,
 | 
			
		||||
 | 
			
		||||
    if (bs->encrypted) {
 | 
			
		||||
        Error *err = NULL;
 | 
			
		||||
        int64_t sector = (cluster_offset + offset_in_cluster)
 | 
			
		||||
        int64_t sector = (src_cluster_offset + offset_in_cluster)
 | 
			
		||||
                         >> BDRV_SECTOR_BITS;
 | 
			
		||||
        assert(s->cipher);
 | 
			
		||||
        assert((offset_in_cluster & ~BDRV_SECTOR_MASK) == 0);
 | 
			
		||||
 | 
			
		||||
@ -2971,7 +2971,8 @@ static BlockDriver vvfat_write_target = {
 | 
			
		||||
static void vvfat_qcow_options(int *child_flags, QDict *child_options,
 | 
			
		||||
                               int parent_flags, QDict *parent_options)
 | 
			
		||||
{
 | 
			
		||||
    *child_flags = BDRV_O_RDWR | BDRV_O_NO_FLUSH;
 | 
			
		||||
    qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "off");
 | 
			
		||||
    *child_flags = BDRV_O_NO_FLUSH;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const BdrvChildRole child_vvfat_qcow = {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										251
									
								
								blockdev.c
									
									
									
									
									
								
							
							
						
						
									
										251
									
								
								blockdev.c
									
									
									
									
									
								
							@ -56,7 +56,8 @@
 | 
			
		||||
static QTAILQ_HEAD(, BlockDriverState) monitor_bdrv_states =
 | 
			
		||||
    QTAILQ_HEAD_INITIALIZER(monitor_bdrv_states);
 | 
			
		||||
 | 
			
		||||
static int do_open_tray(const char *device, bool force, Error **errp);
 | 
			
		||||
static int do_open_tray(const char *blk_name, const char *qdev_id,
 | 
			
		||||
                        bool force, Error **errp);
 | 
			
		||||
 | 
			
		||||
static const char *const if_name[IF_COUNT] = {
 | 
			
		||||
    [IF_NONE] = "none",
 | 
			
		||||
@ -360,9 +361,6 @@ static void extract_common_blockdev_options(QemuOpts *opts, int *bdrv_flags,
 | 
			
		||||
    const char *aio;
 | 
			
		||||
 | 
			
		||||
    if (bdrv_flags) {
 | 
			
		||||
        if (!qemu_opt_get_bool(opts, "read-only", false)) {
 | 
			
		||||
            *bdrv_flags |= BDRV_O_RDWR;
 | 
			
		||||
        }
 | 
			
		||||
        if (qemu_opt_get_bool(opts, "copy-on-read", false)) {
 | 
			
		||||
            *bdrv_flags |= BDRV_O_COPY_ON_READ;
 | 
			
		||||
        }
 | 
			
		||||
@ -471,7 +469,7 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
 | 
			
		||||
    int bdrv_flags = 0;
 | 
			
		||||
    int on_read_error, on_write_error;
 | 
			
		||||
    bool account_invalid, account_failed;
 | 
			
		||||
    bool writethrough;
 | 
			
		||||
    bool writethrough, read_only;
 | 
			
		||||
    BlockBackend *blk;
 | 
			
		||||
    BlockDriverState *bs;
 | 
			
		||||
    ThrottleConfig cfg;
 | 
			
		||||
@ -567,6 +565,8 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
 | 
			
		||||
        bdrv_flags |= BDRV_O_SNAPSHOT;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    read_only = qemu_opt_get_bool(opts, BDRV_OPT_READ_ONLY, false);
 | 
			
		||||
 | 
			
		||||
    /* init */
 | 
			
		||||
    if ((!file || !*file) && !qdict_size(bs_opts)) {
 | 
			
		||||
        BlockBackendRootState *blk_rs;
 | 
			
		||||
@ -574,7 +574,7 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
 | 
			
		||||
        blk = blk_new();
 | 
			
		||||
        blk_rs = blk_get_root_state(blk);
 | 
			
		||||
        blk_rs->open_flags    = bdrv_flags;
 | 
			
		||||
        blk_rs->read_only     = !(bdrv_flags & BDRV_O_RDWR);
 | 
			
		||||
        blk_rs->read_only     = read_only;
 | 
			
		||||
        blk_rs->detect_zeroes = detect_zeroes;
 | 
			
		||||
 | 
			
		||||
        QDECREF(bs_opts);
 | 
			
		||||
@ -588,6 +588,8 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
 | 
			
		||||
         * Apply the defaults here instead. */
 | 
			
		||||
        qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_DIRECT, "off");
 | 
			
		||||
        qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_NO_FLUSH, "off");
 | 
			
		||||
        qdict_set_default_str(bs_opts, BDRV_OPT_READ_ONLY,
 | 
			
		||||
                              read_only ? "on" : "off");
 | 
			
		||||
        assert((bdrv_flags & BDRV_O_CACHE_MASK) == 0);
 | 
			
		||||
 | 
			
		||||
        if (runstate_check(RUN_STATE_INMIGRATE)) {
 | 
			
		||||
@ -682,6 +684,7 @@ static BlockDriverState *bds_tree_init(QDict *bs_opts, Error **errp)
 | 
			
		||||
     * Apply the defaults here instead. */
 | 
			
		||||
    qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_DIRECT, "off");
 | 
			
		||||
    qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_NO_FLUSH, "off");
 | 
			
		||||
    qdict_set_default_str(bs_opts, BDRV_OPT_READ_ONLY, "off");
 | 
			
		||||
 | 
			
		||||
    if (runstate_check(RUN_STATE_INMIGRATE)) {
 | 
			
		||||
        bdrv_flags |= BDRV_O_INACTIVE;
 | 
			
		||||
@ -805,7 +808,7 @@ QemuOptsList qemu_legacy_drive_opts = {
 | 
			
		||||
 | 
			
		||||
        /* Options that are passed on, but have special semantics with -drive */
 | 
			
		||||
        {
 | 
			
		||||
            .name = "read-only",
 | 
			
		||||
            .name = BDRV_OPT_READ_ONLY,
 | 
			
		||||
            .type = QEMU_OPT_BOOL,
 | 
			
		||||
            .help = "open drive file as read-only",
 | 
			
		||||
        },{
 | 
			
		||||
@ -871,7 +874,7 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
 | 
			
		||||
 | 
			
		||||
        { "group",          "throttling.group" },
 | 
			
		||||
 | 
			
		||||
        { "readonly",       "read-only" },
 | 
			
		||||
        { "readonly",       BDRV_OPT_READ_ONLY },
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < ARRAY_SIZE(opt_renames); i++) {
 | 
			
		||||
@ -943,7 +946,7 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* copy-on-read is disabled with a warning for read-only devices */
 | 
			
		||||
    read_only |= qemu_opt_get_bool(legacy_opts, "read-only", false);
 | 
			
		||||
    read_only |= qemu_opt_get_bool(legacy_opts, BDRV_OPT_READ_ONLY, false);
 | 
			
		||||
    copy_on_read = qemu_opt_get_bool(legacy_opts, "copy-on-read", false);
 | 
			
		||||
 | 
			
		||||
    if (read_only && copy_on_read) {
 | 
			
		||||
@ -951,7 +954,7 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
 | 
			
		||||
        copy_on_read = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    qdict_put(bs_opts, "read-only",
 | 
			
		||||
    qdict_put(bs_opts, BDRV_OPT_READ_ONLY,
 | 
			
		||||
              qstring_from_str(read_only ? "on" : "off"));
 | 
			
		||||
    qdict_put(bs_opts, "copy-on-read",
 | 
			
		||||
              qstring_from_str(copy_on_read ? "on" :"off"));
 | 
			
		||||
@ -1196,6 +1199,29 @@ static BlockDriverState *qmp_get_root_bs(const char *name, Error **errp)
 | 
			
		||||
    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");
 | 
			
		||||
@ -1777,8 +1803,7 @@ static void external_snapshot_prepare(BlkActionState *common,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (bdrv_has_blk(state->new_bs)) {
 | 
			
		||||
        error_setg(errp, "The snapshot is already in use by %s",
 | 
			
		||||
                   bdrv_get_parent_name(state->new_bs));
 | 
			
		||||
        error_setg(errp, "The snapshot is already in use");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -2239,7 +2264,9 @@ exit:
 | 
			
		||||
    block_job_txn_unref(block_job_txn);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void qmp_eject(const char *device, bool has_force, bool force, Error **errp)
 | 
			
		||||
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;
 | 
			
		||||
@ -2248,14 +2275,16 @@ void qmp_eject(const char *device, bool has_force, bool force, Error **errp)
 | 
			
		||||
        force = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    rc = do_open_tray(device, force, &local_err);
 | 
			
		||||
    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);
 | 
			
		||||
 | 
			
		||||
    qmp_x_blockdev_remove_medium(device, errp);
 | 
			
		||||
    qmp_x_blockdev_remove_medium(has_device, device, has_id, id, errp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void qmp_block_passwd(bool has_device, const char *device,
 | 
			
		||||
@ -2293,15 +2322,15 @@ void qmp_block_passwd(bool has_device, const char *device,
 | 
			
		||||
 * If the guest was asked to open the tray, return -EINPROGRESS.
 | 
			
		||||
 * Else, return 0.
 | 
			
		||||
 */
 | 
			
		||||
static int do_open_tray(const char *device, bool force, Error **errp)
 | 
			
		||||
static int do_open_tray(const char *blk_name, const char *qdev_id,
 | 
			
		||||
                        bool force, Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    BlockBackend *blk;
 | 
			
		||||
    const char *device = qdev_id ?: blk_name;
 | 
			
		||||
    bool locked;
 | 
			
		||||
 | 
			
		||||
    blk = blk_by_name(device);
 | 
			
		||||
    blk = qmp_get_blk(blk_name, qdev_id, errp);
 | 
			
		||||
    if (!blk) {
 | 
			
		||||
        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
 | 
			
		||||
                  "Device '%s' not found", device);
 | 
			
		||||
        return -ENODEV;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -2337,7 +2366,9 @@ static int do_open_tray(const char *device, bool force, Error **errp)
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void qmp_blockdev_open_tray(const char *device, bool has_force, bool force,
 | 
			
		||||
void qmp_blockdev_open_tray(bool has_device, const char *device,
 | 
			
		||||
                            bool has_id, const char *id,
 | 
			
		||||
                            bool has_force, bool force,
 | 
			
		||||
                            Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    Error *local_err = NULL;
 | 
			
		||||
@ -2346,7 +2377,9 @@ void qmp_blockdev_open_tray(const char *device, bool has_force, bool force,
 | 
			
		||||
    if (!has_force) {
 | 
			
		||||
        force = false;
 | 
			
		||||
    }
 | 
			
		||||
    rc = do_open_tray(device, force, &local_err);
 | 
			
		||||
    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;
 | 
			
		||||
@ -2354,19 +2387,22 @@ void qmp_blockdev_open_tray(const char *device, bool has_force, bool force,
 | 
			
		||||
    error_free(local_err);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void qmp_blockdev_close_tray(const char *device, Error **errp)
 | 
			
		||||
void qmp_blockdev_close_tray(bool has_device, const char *device,
 | 
			
		||||
                             bool has_id, const char *id,
 | 
			
		||||
                             Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    BlockBackend *blk;
 | 
			
		||||
 | 
			
		||||
    blk = blk_by_name(device);
 | 
			
		||||
    device = has_device ? device : NULL;
 | 
			
		||||
    id = has_id ? id : NULL;
 | 
			
		||||
 | 
			
		||||
    blk = qmp_get_blk(device, id, errp);
 | 
			
		||||
    if (!blk) {
 | 
			
		||||
        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
 | 
			
		||||
                  "Device '%s' not found", device);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!blk_dev_has_removable_media(blk)) {
 | 
			
		||||
        error_setg(errp, "Device '%s' is not removable", device);
 | 
			
		||||
        error_setg(errp, "Device '%s' is not removable", device ?: id);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -2382,30 +2418,34 @@ void qmp_blockdev_close_tray(const char *device, Error **errp)
 | 
			
		||||
    blk_dev_change_media_cb(blk, true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void qmp_x_blockdev_remove_medium(const char *device, Error **errp)
 | 
			
		||||
void qmp_x_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_device;
 | 
			
		||||
    bool has_attached_device;
 | 
			
		||||
 | 
			
		||||
    blk = blk_by_name(device);
 | 
			
		||||
    device = has_device ? device : NULL;
 | 
			
		||||
    id = has_id ? id : NULL;
 | 
			
		||||
 | 
			
		||||
    blk = qmp_get_blk(device, id, errp);
 | 
			
		||||
    if (!blk) {
 | 
			
		||||
        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
 | 
			
		||||
                  "Device '%s' not found", device);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* For BBs without a device, we can exchange the BDS tree at will */
 | 
			
		||||
    has_device = blk_get_attached_dev(blk);
 | 
			
		||||
    has_attached_device = blk_get_attached_dev(blk);
 | 
			
		||||
 | 
			
		||||
    if (has_device && !blk_dev_has_removable_media(blk)) {
 | 
			
		||||
        error_setg(errp, "Device '%s' is not removable", device);
 | 
			
		||||
    if (has_attached_device && !blk_dev_has_removable_media(blk)) {
 | 
			
		||||
        error_setg(errp, "Device '%s' is not removable", device ?: id);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
    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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -2435,34 +2475,26 @@ out:
 | 
			
		||||
    aio_context_release(aio_context);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void qmp_blockdev_insert_anon_medium(const char *device,
 | 
			
		||||
static void qmp_blockdev_insert_anon_medium(BlockBackend *blk,
 | 
			
		||||
                                            BlockDriverState *bs, Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    BlockBackend *blk;
 | 
			
		||||
    bool has_device;
 | 
			
		||||
 | 
			
		||||
    blk = blk_by_name(device);
 | 
			
		||||
    if (!blk) {
 | 
			
		||||
        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
 | 
			
		||||
                  "Device '%s' not found", device);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* 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 '%s' is not removable", device);
 | 
			
		||||
        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 device '%s' is not open", device);
 | 
			
		||||
        error_setg(errp, "Tray of the device is not open");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (blk_bs(blk)) {
 | 
			
		||||
        error_setg(errp, "There already is a medium in device '%s'", device);
 | 
			
		||||
        error_setg(errp, "There already is a medium in the device");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -2478,11 +2510,20 @@ static void qmp_blockdev_insert_anon_medium(const char *device,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void qmp_x_blockdev_insert_medium(const char *device, const char *node_name,
 | 
			
		||||
                                  Error **errp)
 | 
			
		||||
void qmp_x_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);
 | 
			
		||||
@ -2490,15 +2531,16 @@ void qmp_x_blockdev_insert_medium(const char *device, const char *node_name,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (bdrv_has_blk(bs)) {
 | 
			
		||||
        error_setg(errp, "Node '%s' is already in use by '%s'", node_name,
 | 
			
		||||
                   bdrv_get_parent_name(bs));
 | 
			
		||||
        error_setg(errp, "Node '%s' is already in use", node_name);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    qmp_blockdev_insert_anon_medium(device, bs, errp);
 | 
			
		||||
    qmp_blockdev_insert_anon_medium(blk, bs, errp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void qmp_blockdev_change_medium(const char *device, const char *filename,
 | 
			
		||||
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,
 | 
			
		||||
@ -2511,10 +2553,10 @@ void qmp_blockdev_change_medium(const char *device, const char *filename,
 | 
			
		||||
    QDict *options = NULL;
 | 
			
		||||
    Error *err = NULL;
 | 
			
		||||
 | 
			
		||||
    blk = blk_by_name(device);
 | 
			
		||||
    blk = qmp_get_blk(has_device ? device : NULL,
 | 
			
		||||
                      has_id ? id : NULL,
 | 
			
		||||
                      errp);
 | 
			
		||||
    if (!blk) {
 | 
			
		||||
        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
 | 
			
		||||
                  "Device '%s' not found", device);
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -2562,7 +2604,9 @@ void qmp_blockdev_change_medium(const char *device, const char *filename,
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    rc = do_open_tray(device, false, &err);
 | 
			
		||||
    rc = do_open_tray(has_device ? device : NULL,
 | 
			
		||||
                      has_id ? id : NULL,
 | 
			
		||||
                      false, &err);
 | 
			
		||||
    if (rc && rc != -ENOSYS) {
 | 
			
		||||
        error_propagate(errp, err);
 | 
			
		||||
        goto fail;
 | 
			
		||||
@ -2570,13 +2614,13 @@ void qmp_blockdev_change_medium(const char *device, const char *filename,
 | 
			
		||||
    error_free(err);
 | 
			
		||||
    err = NULL;
 | 
			
		||||
 | 
			
		||||
    qmp_x_blockdev_remove_medium(device, &err);
 | 
			
		||||
    qmp_x_blockdev_remove_medium(has_device, device, has_id, id, errp);
 | 
			
		||||
    if (err) {
 | 
			
		||||
        error_propagate(errp, err);
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    qmp_blockdev_insert_anon_medium(device, medium_bs, &err);
 | 
			
		||||
    qmp_blockdev_insert_anon_medium(blk, medium_bs, &err);
 | 
			
		||||
    if (err) {
 | 
			
		||||
        error_propagate(errp, err);
 | 
			
		||||
        goto fail;
 | 
			
		||||
@ -2584,7 +2628,7 @@ void qmp_blockdev_change_medium(const char *device, const char *filename,
 | 
			
		||||
 | 
			
		||||
    blk_apply_root_state(blk, medium_bs);
 | 
			
		||||
 | 
			
		||||
    qmp_blockdev_close_tray(device, errp);
 | 
			
		||||
    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
 | 
			
		||||
@ -2601,10 +2645,10 @@ void qmp_block_set_io_throttle(BlockIOThrottle *arg, Error **errp)
 | 
			
		||||
    BlockBackend *blk;
 | 
			
		||||
    AioContext *aio_context;
 | 
			
		||||
 | 
			
		||||
    blk = blk_by_name(arg->device);
 | 
			
		||||
    blk = qmp_get_blk(arg->has_device ? arg->device : NULL,
 | 
			
		||||
                      arg->has_id ? arg->id : NULL,
 | 
			
		||||
                      errp);
 | 
			
		||||
    if (!blk) {
 | 
			
		||||
        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
 | 
			
		||||
                  "Device '%s' not found", arg->device);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -2613,7 +2657,7 @@ void qmp_block_set_io_throttle(BlockIOThrottle *arg, Error **errp)
 | 
			
		||||
 | 
			
		||||
    bs = blk_bs(blk);
 | 
			
		||||
    if (!bs) {
 | 
			
		||||
        error_setg(errp, "Device '%s' has no medium", arg->device);
 | 
			
		||||
        error_setg(errp, "Device has no medium");
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -2677,7 +2721,9 @@ void qmp_block_set_io_throttle(BlockIOThrottle *arg, Error **errp)
 | 
			
		||||
         * just update the throttling group. */
 | 
			
		||||
        if (!blk_get_public(blk)->throttle_state) {
 | 
			
		||||
            blk_io_limits_enable(blk,
 | 
			
		||||
                                 arg->has_group ? arg->group : arg->device);
 | 
			
		||||
                                 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);
 | 
			
		||||
        }
 | 
			
		||||
@ -2798,7 +2844,7 @@ void hmp_drive_del(Monitor *mon, const QDict *qdict)
 | 
			
		||||
 | 
			
		||||
    bs = bdrv_find_node(id);
 | 
			
		||||
    if (bs) {
 | 
			
		||||
        qmp_x_blockdev_del(false, NULL, true, id, &local_err);
 | 
			
		||||
        qmp_x_blockdev_del(id, &local_err);
 | 
			
		||||
        if (local_err) {
 | 
			
		||||
            error_report_err(local_err);
 | 
			
		||||
        }
 | 
			
		||||
@ -3781,7 +3827,6 @@ out:
 | 
			
		||||
void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    BlockDriverState *bs;
 | 
			
		||||
    BlockBackend *blk = NULL;
 | 
			
		||||
    QObject *obj;
 | 
			
		||||
    Visitor *v = qmp_output_visitor_new(&obj);
 | 
			
		||||
    QDict *qdict;
 | 
			
		||||
@ -3813,18 +3858,8 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
 | 
			
		||||
 | 
			
		||||
    qdict_flatten(qdict);
 | 
			
		||||
 | 
			
		||||
    if (options->has_id) {
 | 
			
		||||
        blk = blockdev_init(NULL, qdict, &local_err);
 | 
			
		||||
        if (local_err) {
 | 
			
		||||
            error_propagate(errp, local_err);
 | 
			
		||||
            goto fail;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        bs = blk_bs(blk);
 | 
			
		||||
    } else {
 | 
			
		||||
    if (!qdict_get_try_str(qdict, "node-name")) {
 | 
			
		||||
            error_setg(errp, "'id' and/or 'node-name' need to be specified for "
 | 
			
		||||
                       "the root node");
 | 
			
		||||
        error_setg(errp, "'node-name' must be specified for the root node");
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -3834,16 +3869,10 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    QTAILQ_INSERT_TAIL(&monitor_bdrv_states, bs, monitor_list);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (bs && bdrv_key_required(bs)) {
 | 
			
		||||
        if (blk) {
 | 
			
		||||
            monitor_remove_blk(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 fail;
 | 
			
		||||
    }
 | 
			
		||||
@ -3852,62 +3881,28 @@ fail:
 | 
			
		||||
    visit_free(v);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void qmp_x_blockdev_del(bool has_id, const char *id,
 | 
			
		||||
                        bool has_node_name, const char *node_name, Error **errp)
 | 
			
		||||
void qmp_x_blockdev_del(const char *node_name, Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    AioContext *aio_context;
 | 
			
		||||
    BlockBackend *blk;
 | 
			
		||||
    BlockDriverState *bs;
 | 
			
		||||
 | 
			
		||||
    if (has_id && has_node_name) {
 | 
			
		||||
        error_setg(errp, "Only one of id and node-name must be specified");
 | 
			
		||||
        return;
 | 
			
		||||
    } else if (!has_id && !has_node_name) {
 | 
			
		||||
        error_setg(errp, "No block device specified");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (has_id) {
 | 
			
		||||
        /* blk_by_name() never returns a BB that is not owned by the monitor */
 | 
			
		||||
        blk = blk_by_name(id);
 | 
			
		||||
        if (!blk) {
 | 
			
		||||
            error_setg(errp, "Cannot find block backend %s", id);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        if (blk_legacy_dinfo(blk)) {
 | 
			
		||||
            error_setg(errp, "Deleting block backend added with drive-add"
 | 
			
		||||
                       " is not supported");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        if (blk_get_refcnt(blk) > 1) {
 | 
			
		||||
            error_setg(errp, "Block backend %s is in use", id);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        bs = blk_bs(blk);
 | 
			
		||||
        aio_context = blk_get_aio_context(blk);
 | 
			
		||||
    } else {
 | 
			
		||||
        blk = NULL;
 | 
			
		||||
    bs = bdrv_find_node(node_name);
 | 
			
		||||
    if (!bs) {
 | 
			
		||||
        error_setg(errp, "Cannot find node %s", node_name);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    if (bdrv_has_blk(bs)) {
 | 
			
		||||
            error_setg(errp, "Node %s is in use by %s",
 | 
			
		||||
                       node_name, bdrv_get_parent_name(bs));
 | 
			
		||||
        error_setg(errp, "Node %s is in use", node_name);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    aio_context = bdrv_get_aio_context(bs);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    aio_context_acquire(aio_context);
 | 
			
		||||
 | 
			
		||||
    if (bs) {
 | 
			
		||||
    if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_DRIVE_DEL, errp)) {
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        if (!blk && !QTAILQ_IN_USE(bs, monitor_list)) {
 | 
			
		||||
    if (!bs->monitor_list.tqe_prev) {
 | 
			
		||||
        error_setg(errp, "Node %s is not owned by the monitor",
 | 
			
		||||
                   bs->node_name);
 | 
			
		||||
        goto out;
 | 
			
		||||
@ -3918,15 +3913,9 @@ void qmp_x_blockdev_del(bool has_id, const char *id,
 | 
			
		||||
                   bdrv_get_device_or_node_name(bs));
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (blk) {
 | 
			
		||||
        monitor_remove_blk(blk);
 | 
			
		||||
        blk_unref(blk);
 | 
			
		||||
    } else {
 | 
			
		||||
    QTAILQ_REMOVE(&monitor_bdrv_states, bs, monitor_list);
 | 
			
		||||
    bdrv_unref(bs);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
    aio_context_release(aio_context);
 | 
			
		||||
@ -4040,7 +4029,7 @@ QemuOptsList qemu_common_drive_opts = {
 | 
			
		||||
            .type = QEMU_OPT_STRING,
 | 
			
		||||
            .help = "write error action",
 | 
			
		||||
        },{
 | 
			
		||||
            .name = "read-only",
 | 
			
		||||
            .name = BDRV_OPT_READ_ONLY,
 | 
			
		||||
            .type = QEMU_OPT_BOOL,
 | 
			
		||||
            .help = "open drive file as read-only",
 | 
			
		||||
        },{
 | 
			
		||||
@ -4158,10 +4147,6 @@ static QemuOptsList qemu_root_bds_opts = {
 | 
			
		||||
            .name = "aio",
 | 
			
		||||
            .type = QEMU_OPT_STRING,
 | 
			
		||||
            .help = "host AIO implementation (threads, native)",
 | 
			
		||||
        },{
 | 
			
		||||
            .name = "read-only",
 | 
			
		||||
            .type = QEMU_OPT_BOOL,
 | 
			
		||||
            .help = "open drive file as read-only",
 | 
			
		||||
        },{
 | 
			
		||||
            .name = "copy-on-read",
 | 
			
		||||
            .type = QEMU_OPT_BOOL,
 | 
			
		||||
 | 
			
		||||
@ -72,12 +72,14 @@ Eject a removable medium.
 | 
			
		||||
 | 
			
		||||
Arguments:
 | 
			
		||||
 | 
			
		||||
- force: force ejection (json-bool, optional)
 | 
			
		||||
- device: device name (json-string)
 | 
			
		||||
- "force": force ejection (json-bool, optional)
 | 
			
		||||
- "device": block device name (deprecated, use @id instead)
 | 
			
		||||
            (json-string, optional)
 | 
			
		||||
- "id": the name or QOM path of the guest device (json-string, optional)
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
 | 
			
		||||
-> { "execute": "eject", "arguments": { "device": "ide1-cd0" } }
 | 
			
		||||
-> { "execute": "eject", "arguments": { "id": "ide0-1-0" } }
 | 
			
		||||
<- { "return": {} }
 | 
			
		||||
 | 
			
		||||
Note: The "force" argument defaults to false.
 | 
			
		||||
@ -1457,7 +1459,9 @@ Change I/O throttle limits for a block drive.
 | 
			
		||||
 | 
			
		||||
Arguments:
 | 
			
		||||
 | 
			
		||||
- "device": device name (json-string)
 | 
			
		||||
- "device": block device name (deprecated, use @id instead)
 | 
			
		||||
            (json-string, optional)
 | 
			
		||||
- "id": the name or QOM path of the guest device (json-string, optional)
 | 
			
		||||
- "bps": total throughput limit in bytes per second (json-int)
 | 
			
		||||
- "bps_rd": read throughput limit in bytes per second (json-int)
 | 
			
		||||
- "bps_wr": write throughput limit in bytes per second (json-int)
 | 
			
		||||
@ -1481,7 +1485,7 @@ Arguments:
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
 | 
			
		||||
-> { "execute": "block_set_io_throttle", "arguments": { "device": "virtio0",
 | 
			
		||||
-> { "execute": "block_set_io_throttle", "arguments": { "id": "ide0-1-0",
 | 
			
		||||
                                               "bps": 1000000,
 | 
			
		||||
                                               "bps_rd": 0,
 | 
			
		||||
                                               "bps_wr": 0,
 | 
			
		||||
@ -3137,7 +3141,7 @@ Example (2):
 | 
			
		||||
     "arguments": {
 | 
			
		||||
         "options": {
 | 
			
		||||
           "driver": "qcow2",
 | 
			
		||||
           "id": "my_disk",
 | 
			
		||||
           "node-name": "my_disk",
 | 
			
		||||
           "discard": "unmap",
 | 
			
		||||
           "cache": {
 | 
			
		||||
               "direct": true,
 | 
			
		||||
@ -3164,18 +3168,9 @@ x-blockdev-del
 | 
			
		||||
------------
 | 
			
		||||
Since 2.5
 | 
			
		||||
 | 
			
		||||
Deletes a block device thas has been added using blockdev-add.
 | 
			
		||||
The selected device can be either a block backend or a graph node.
 | 
			
		||||
 | 
			
		||||
In the former case the backend will be destroyed, along with its
 | 
			
		||||
inserted medium if there's any. The command will fail if the backend
 | 
			
		||||
or its medium are in use.
 | 
			
		||||
 | 
			
		||||
In the latter case the node will be destroyed. The command will fail
 | 
			
		||||
if the node is attached to a block backend or is otherwise being
 | 
			
		||||
used.
 | 
			
		||||
 | 
			
		||||
One of "id" or "node-name" must be specified, but not both.
 | 
			
		||||
Deletes a block device that has been added using blockdev-add.
 | 
			
		||||
The command will fail if the node is attached to a device or is
 | 
			
		||||
otherwise being used.
 | 
			
		||||
 | 
			
		||||
This command is still a work in progress and is considered
 | 
			
		||||
experimental. Stay away from it unless you want to help with its
 | 
			
		||||
@ -3183,8 +3178,7 @@ development.
 | 
			
		||||
 | 
			
		||||
Arguments:
 | 
			
		||||
 | 
			
		||||
- "id": Name of the block backend device to delete (json-string, optional)
 | 
			
		||||
- "node-name": Name of the graph node to delete (json-string, optional)
 | 
			
		||||
- "node-name": Name of the graph node to delete (json-string)
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
 | 
			
		||||
@ -3192,7 +3186,7 @@ Example:
 | 
			
		||||
     "arguments": {
 | 
			
		||||
         "options": {
 | 
			
		||||
             "driver": "qcow2",
 | 
			
		||||
             "id": "drive0",
 | 
			
		||||
             "node-name": "node0",
 | 
			
		||||
             "file": {
 | 
			
		||||
                 "driver": "file",
 | 
			
		||||
                 "filename": "test.qcow2"
 | 
			
		||||
@ -3204,7 +3198,7 @@ Example:
 | 
			
		||||
<- { "return": {} }
 | 
			
		||||
 | 
			
		||||
-> { "execute": "x-blockdev-del",
 | 
			
		||||
     "arguments": { "id": "drive0" }
 | 
			
		||||
     "arguments": { "node-name": "node0" }
 | 
			
		||||
   }
 | 
			
		||||
<- { "return": {} }
 | 
			
		||||
 | 
			
		||||
@ -3228,7 +3222,9 @@ which no such event will be generated, these include:
 | 
			
		||||
 | 
			
		||||
Arguments:
 | 
			
		||||
 | 
			
		||||
- "device": block device name (json-string)
 | 
			
		||||
- "device": block device name (deprecated, use @id instead)
 | 
			
		||||
            (json-string, optional)
 | 
			
		||||
- "id": the name or QOM path of the guest device (json-string, optional)
 | 
			
		||||
- "force": if false (the default), an eject request will be sent to the guest if
 | 
			
		||||
           it has locked the tray (and the tray will not be opened immediately);
 | 
			
		||||
           if true, the tray will be opened regardless of whether it is locked
 | 
			
		||||
@ -3237,7 +3233,7 @@ Arguments:
 | 
			
		||||
Example:
 | 
			
		||||
 | 
			
		||||
-> { "execute": "blockdev-open-tray",
 | 
			
		||||
     "arguments": { "device": "ide1-cd0" } }
 | 
			
		||||
     "arguments": { "id": "ide0-1-0" } }
 | 
			
		||||
 | 
			
		||||
<- { "timestamp": { "seconds": 1418751016,
 | 
			
		||||
                    "microseconds": 716996 },
 | 
			
		||||
@ -3258,12 +3254,14 @@ If the tray was already closed before, this will be a no-op.
 | 
			
		||||
 | 
			
		||||
Arguments:
 | 
			
		||||
 | 
			
		||||
- "device": block device name (json-string)
 | 
			
		||||
- "device": block device name (deprecated, use @id instead)
 | 
			
		||||
            (json-string, optional)
 | 
			
		||||
- "id": the name or QOM path of the guest device (json-string, optional)
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
 | 
			
		||||
-> { "execute": "blockdev-close-tray",
 | 
			
		||||
     "arguments": { "device": "ide1-cd0" } }
 | 
			
		||||
     "arguments": { "id": "ide0-1-0" } }
 | 
			
		||||
 | 
			
		||||
<- { "timestamp": { "seconds": 1418751345,
 | 
			
		||||
                    "microseconds": 272147 },
 | 
			
		||||
@ -3286,18 +3284,20 @@ Stay away from it unless you want to help with its development.
 | 
			
		||||
 | 
			
		||||
Arguments:
 | 
			
		||||
 | 
			
		||||
- "device": block device name (json-string)
 | 
			
		||||
- "device": block device name (deprecated, use @id instead)
 | 
			
		||||
            (json-string, optional)
 | 
			
		||||
- "id": the name or QOM path of the guest device (json-string, optional)
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
 | 
			
		||||
-> { "execute": "x-blockdev-remove-medium",
 | 
			
		||||
     "arguments": { "device": "ide1-cd0" } }
 | 
			
		||||
     "arguments": { "id": "ide0-1-0" } }
 | 
			
		||||
 | 
			
		||||
<- { "error": { "class": "GenericError",
 | 
			
		||||
                "desc": "Tray of device 'ide1-cd0' is not open" } }
 | 
			
		||||
                "desc": "Tray of device 'ide0-1-0' is not open" } }
 | 
			
		||||
 | 
			
		||||
-> { "execute": "blockdev-open-tray",
 | 
			
		||||
     "arguments": { "device": "ide1-cd0" } }
 | 
			
		||||
     "arguments": { "id": "ide0-1-0" } }
 | 
			
		||||
 | 
			
		||||
<- { "timestamp": { "seconds": 1418751627,
 | 
			
		||||
                    "microseconds": 549958 },
 | 
			
		||||
@ -3308,7 +3308,7 @@ Example:
 | 
			
		||||
<- { "return": {} }
 | 
			
		||||
 | 
			
		||||
-> { "execute": "x-blockdev-remove-medium",
 | 
			
		||||
     "arguments": { "device": "ide1-cd0" } }
 | 
			
		||||
     "arguments": { "device": "ide0-1-0" } }
 | 
			
		||||
 | 
			
		||||
<- { "return": {} }
 | 
			
		||||
 | 
			
		||||
@ -3324,7 +3324,9 @@ Stay away from it unless you want to help with its development.
 | 
			
		||||
 | 
			
		||||
Arguments:
 | 
			
		||||
 | 
			
		||||
- "device": block device name (json-string)
 | 
			
		||||
- "device": block device name (deprecated, use @id instead)
 | 
			
		||||
            (json-string, optional)
 | 
			
		||||
- "id": the name or QOM path of the guest device (json-string, optional)
 | 
			
		||||
- "node-name": root node of the BDS tree to insert into the block device
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
@ -3338,7 +3340,7 @@ Example:
 | 
			
		||||
<- { "return": {} }
 | 
			
		||||
 | 
			
		||||
-> { "execute": "x-blockdev-insert-medium",
 | 
			
		||||
     "arguments": { "device": "ide1-cd0",
 | 
			
		||||
     "arguments": { "id": "ide0-1-0",
 | 
			
		||||
                    "node-name": "node0" } }
 | 
			
		||||
 | 
			
		||||
<- { "return": {} }
 | 
			
		||||
@ -3448,7 +3450,9 @@ and loading a new image file which is inserted as the new medium.
 | 
			
		||||
 | 
			
		||||
Arguments:
 | 
			
		||||
 | 
			
		||||
- "device": device name (json-string)
 | 
			
		||||
- "device": block device name (deprecated, use @id instead)
 | 
			
		||||
            (json-string, optional)
 | 
			
		||||
- "id": the name or QOM path of the guest device (json-string, optional)
 | 
			
		||||
- "filename": filename of the new image (json-string)
 | 
			
		||||
- "format": format of the new image (json-string, optional)
 | 
			
		||||
- "read-only-mode": new read-only mode (json-string, optional)
 | 
			
		||||
@ -3459,7 +3463,7 @@ Examples:
 | 
			
		||||
1. Change a removable medium
 | 
			
		||||
 | 
			
		||||
-> { "execute": "blockdev-change-medium",
 | 
			
		||||
             "arguments": { "device": "ide1-cd0",
 | 
			
		||||
             "arguments": { "id": "ide0-1-0",
 | 
			
		||||
                            "filename": "/srv/images/Fedora-12-x86_64-DVD.iso",
 | 
			
		||||
                            "format": "raw" } }
 | 
			
		||||
<- { "return": {} }
 | 
			
		||||
@ -3467,7 +3471,7 @@ Examples:
 | 
			
		||||
2. Load a read-only medium into a writable drive
 | 
			
		||||
 | 
			
		||||
-> { "execute": "blockdev-change-medium",
 | 
			
		||||
             "arguments": { "device": "isa-fd0",
 | 
			
		||||
             "arguments": { "id": "floppyA",
 | 
			
		||||
                            "filename": "/srv/images/ro.img",
 | 
			
		||||
                            "format": "raw",
 | 
			
		||||
                            "read-only-mode": "retain" } }
 | 
			
		||||
@ -3477,7 +3481,7 @@ Examples:
 | 
			
		||||
       "desc": "Could not open '/srv/images/ro.img': Permission denied" } }
 | 
			
		||||
 | 
			
		||||
-> { "execute": "blockdev-change-medium",
 | 
			
		||||
             "arguments": { "device": "isa-fd0",
 | 
			
		||||
             "arguments": { "id": "floppyA",
 | 
			
		||||
                            "filename": "/srv/images/ro.img",
 | 
			
		||||
                            "format": "raw",
 | 
			
		||||
                            "read-only-mode": "read-only" } }
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										15
									
								
								hmp.c
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								hmp.c
									
									
									
									
									
								
							@ -1376,7 +1376,7 @@ void hmp_eject(Monitor *mon, const QDict *qdict)
 | 
			
		||||
    const char *device = qdict_get_str(qdict, "device");
 | 
			
		||||
    Error *err = NULL;
 | 
			
		||||
 | 
			
		||||
    qmp_eject(device, true, force, &err);
 | 
			
		||||
    qmp_eject(true, device, false, NULL, true, force, &err);
 | 
			
		||||
    hmp_handle_error(mon, &err);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1422,8 +1422,9 @@ void hmp_change(Monitor *mon, const QDict *qdict)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        qmp_blockdev_change_medium(device, target, !!arg, arg,
 | 
			
		||||
                                   !!read_only, read_only_mode, &err);
 | 
			
		||||
        qmp_blockdev_change_medium(true, device, false, NULL, target,
 | 
			
		||||
                                   !!arg, arg, !!read_only, read_only_mode,
 | 
			
		||||
                                   &err);
 | 
			
		||||
        if (err &&
 | 
			
		||||
            error_get_class(err) == ERROR_CLASS_DEVICE_ENCRYPTED) {
 | 
			
		||||
            error_free(err);
 | 
			
		||||
@ -1924,6 +1925,7 @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict)
 | 
			
		||||
{
 | 
			
		||||
    BlockBackend *blk;
 | 
			
		||||
    BlockBackend *local_blk = NULL;
 | 
			
		||||
    AioContext *aio_context;
 | 
			
		||||
    const char* device = qdict_get_str(qdict, "device");
 | 
			
		||||
    const char* command = qdict_get_str(qdict, "command");
 | 
			
		||||
    Error *err = NULL;
 | 
			
		||||
@ -1939,17 +1941,12 @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (blk) {
 | 
			
		||||
        AioContext *aio_context = blk_get_aio_context(blk);
 | 
			
		||||
    aio_context = blk_get_aio_context(blk);
 | 
			
		||||
    aio_context_acquire(aio_context);
 | 
			
		||||
 | 
			
		||||
    qemuio_command(blk, command);
 | 
			
		||||
 | 
			
		||||
    aio_context_release(aio_context);
 | 
			
		||||
    } else {
 | 
			
		||||
        error_set(&err, ERROR_CLASS_DEVICE_NOT_FOUND,
 | 
			
		||||
                  "Device '%s' not found", device);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
fail:
 | 
			
		||||
    blk_unref(local_blk);
 | 
			
		||||
 | 
			
		||||
@ -107,6 +107,7 @@ typedef struct HDGeometry {
 | 
			
		||||
#define BDRV_OPT_CACHE_WB       "cache.writeback"
 | 
			
		||||
#define BDRV_OPT_CACHE_DIRECT   "cache.direct"
 | 
			
		||||
#define BDRV_OPT_CACHE_NO_FLUSH "cache.no-flush"
 | 
			
		||||
#define BDRV_OPT_READ_ONLY      "read-only"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define BDRV_SECTOR_BITS   9
 | 
			
		||||
@ -414,7 +415,6 @@ void bdrv_get_full_backing_filename_from_filename(const char *backed,
 | 
			
		||||
                                                  const char *backing,
 | 
			
		||||
                                                  char *dest, size_t sz,
 | 
			
		||||
                                                  Error **errp);
 | 
			
		||||
int bdrv_is_snapshot(BlockDriverState *bs);
 | 
			
		||||
 | 
			
		||||
int path_has_protocol(const char *path);
 | 
			
		||||
int path_is_absolute(const char *path);
 | 
			
		||||
 | 
			
		||||
@ -111,6 +111,8 @@ int blk_attach_dev(BlockBackend *blk, void *dev);
 | 
			
		||||
void blk_attach_dev_nofail(BlockBackend *blk, void *dev);
 | 
			
		||||
void blk_detach_dev(BlockBackend *blk, void *dev);
 | 
			
		||||
void *blk_get_attached_dev(BlockBackend *blk);
 | 
			
		||||
BlockBackend *blk_by_dev(void *dev);
 | 
			
		||||
BlockBackend *blk_by_qdev_id(const char *id, Error **errp);
 | 
			
		||||
void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops, void *opaque);
 | 
			
		||||
int blk_pread_unthrottled(BlockBackend *blk, int64_t offset, uint8_t *buf,
 | 
			
		||||
                          int count);
 | 
			
		||||
 | 
			
		||||
@ -900,7 +900,7 @@
 | 
			
		||||
#          otherwise. (Since 2.4)
 | 
			
		||||
#
 | 
			
		||||
# @compress: #optional true to compress data, if the target format supports it.
 | 
			
		||||
#            (default: false) (since 2.7)
 | 
			
		||||
#            (default: false) (since 2.8)
 | 
			
		||||
#
 | 
			
		||||
# @on-source-error: #optional the action to take on an error on the source,
 | 
			
		||||
#                   default 'report'.  'stop' and 'enospc' can only be used
 | 
			
		||||
@ -941,7 +941,7 @@
 | 
			
		||||
#         for unlimited.
 | 
			
		||||
#
 | 
			
		||||
# @compress: #optional true to compress data, if the target format supports it.
 | 
			
		||||
#            (default: false) (since 2.7)
 | 
			
		||||
#            (default: false) (since 2.8)
 | 
			
		||||
#
 | 
			
		||||
# @on-source-error: #optional the action to take on an error on the source,
 | 
			
		||||
#                   default 'report'.  'stop' and 'enospc' can only be used
 | 
			
		||||
@ -1377,7 +1377,9 @@
 | 
			
		||||
#
 | 
			
		||||
# A set of parameters describing block throttling.
 | 
			
		||||
#
 | 
			
		||||
# @device: The name of the device
 | 
			
		||||
# @device: #optional Block device name (deprecated, use @id instead)
 | 
			
		||||
#
 | 
			
		||||
# @id: #optional The name or QOM path of the guest device (since: 2.8)
 | 
			
		||||
#
 | 
			
		||||
# @bps: total throughput limit in bytes per second
 | 
			
		||||
#
 | 
			
		||||
@ -1446,8 +1448,8 @@
 | 
			
		||||
# Since: 1.1
 | 
			
		||||
##
 | 
			
		||||
{ 'struct': 'BlockIOThrottle',
 | 
			
		||||
  'data': { 'device': 'str', 'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
 | 
			
		||||
            'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int',
 | 
			
		||||
  'data': { '*device': 'str', '*id': 'str', 'bps': 'int', 'bps_rd': 'int',
 | 
			
		||||
            'bps_wr': 'int', 'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int',
 | 
			
		||||
            '*bps_max': 'int', '*bps_rd_max': 'int',
 | 
			
		||||
            '*bps_wr_max': 'int', '*iops_max': 'int',
 | 
			
		||||
            '*iops_rd_max': 'int', '*iops_wr_max': 'int',
 | 
			
		||||
@ -2215,13 +2217,8 @@
 | 
			
		||||
# block devices, independent of the block driver:
 | 
			
		||||
#
 | 
			
		||||
# @driver:        block driver name
 | 
			
		||||
# @id:            #optional id by which the new block device can be referred to.
 | 
			
		||||
#                 This option is only allowed on the top level of blockdev-add.
 | 
			
		||||
#                 A BlockBackend will be created by blockdev-add if and only if
 | 
			
		||||
#                 this option is given.
 | 
			
		||||
# @node-name:     #optional the name of a block driver state node (Since 2.0).
 | 
			
		||||
#                 This option is required on the top level of blockdev-add if
 | 
			
		||||
#                 the @id option is not given there.
 | 
			
		||||
# @node-name:     #optional the node name of the new node (Since 2.0).
 | 
			
		||||
#                 This option is required on the top level of blockdev-add.
 | 
			
		||||
# @discard:       #optional discard-related options (default: ignore)
 | 
			
		||||
# @cache:         #optional cache-related options
 | 
			
		||||
# @aio:           #optional AIO backend (default: threads)
 | 
			
		||||
@ -2236,8 +2233,6 @@
 | 
			
		||||
##
 | 
			
		||||
{ 'union': 'BlockdevOptions',
 | 
			
		||||
  'base': { 'driver': 'BlockdevDriver',
 | 
			
		||||
# TODO 'id' is a BB-level option, remove it
 | 
			
		||||
            '*id': 'str',
 | 
			
		||||
            '*node-name': 'str',
 | 
			
		||||
            '*discard': 'BlockdevDiscardOptions',
 | 
			
		||||
            '*cache': 'BlockdevCacheOptions',
 | 
			
		||||
@ -2321,29 +2316,18 @@
 | 
			
		||||
# @x-blockdev-del:
 | 
			
		||||
#
 | 
			
		||||
# Deletes a block device that has been added using blockdev-add.
 | 
			
		||||
# The selected device can be either a block backend or a graph node.
 | 
			
		||||
#
 | 
			
		||||
# In the former case the backend will be destroyed, along with its
 | 
			
		||||
# inserted medium if there's any. The command will fail if the backend
 | 
			
		||||
# or its medium are in use.
 | 
			
		||||
#
 | 
			
		||||
# In the latter case the node will be destroyed. The command will fail
 | 
			
		||||
# if the node is attached to a block backend or is otherwise being
 | 
			
		||||
# used.
 | 
			
		||||
#
 | 
			
		||||
# One of @id or @node-name must be specified, but not both.
 | 
			
		||||
# The command will fail if the node is attached to a device or is
 | 
			
		||||
# otherwise being used.
 | 
			
		||||
#
 | 
			
		||||
# This command is still a work in progress and is considered
 | 
			
		||||
# experimental. Stay away from it unless you want to help with its
 | 
			
		||||
# development.
 | 
			
		||||
#
 | 
			
		||||
# @id: #optional Name of the block backend device to delete.
 | 
			
		||||
#
 | 
			
		||||
# @node-name: #optional Name of the graph node to delete.
 | 
			
		||||
# @node-name: Name of the graph node to delete.
 | 
			
		||||
#
 | 
			
		||||
# Since: 2.5
 | 
			
		||||
##
 | 
			
		||||
{ 'command': 'x-blockdev-del', 'data': { '*id': 'str', '*node-name': 'str' } }
 | 
			
		||||
{ 'command': 'x-blockdev-del', 'data': { 'node-name': 'str' } }
 | 
			
		||||
 | 
			
		||||
##
 | 
			
		||||
# @blockdev-open-tray:
 | 
			
		||||
@ -2363,7 +2347,9 @@
 | 
			
		||||
#   to it
 | 
			
		||||
# - if the guest device does not have an actual tray
 | 
			
		||||
#
 | 
			
		||||
# @device: block device name
 | 
			
		||||
# @device: #optional Block device name (deprecated, use @id instead)
 | 
			
		||||
#
 | 
			
		||||
# @id:     #optional The name or QOM path of the guest device (since: 2.8)
 | 
			
		||||
#
 | 
			
		||||
# @force:  #optional if false (the default), an eject request will be sent to
 | 
			
		||||
#          the guest if it has locked the tray (and the tray will not be opened
 | 
			
		||||
@ -2373,7 +2359,8 @@
 | 
			
		||||
# Since: 2.5
 | 
			
		||||
##
 | 
			
		||||
{ 'command': 'blockdev-open-tray',
 | 
			
		||||
  'data': { 'device': 'str',
 | 
			
		||||
  'data': { '*device': 'str',
 | 
			
		||||
            '*id': 'str',
 | 
			
		||||
            '*force': 'bool' } }
 | 
			
		||||
 | 
			
		||||
##
 | 
			
		||||
@ -2385,12 +2372,15 @@
 | 
			
		||||
#
 | 
			
		||||
# If the tray was already closed before, this will be a no-op.
 | 
			
		||||
#
 | 
			
		||||
# @device: block device name
 | 
			
		||||
# @device:  #optional Block device name (deprecated, use @id instead)
 | 
			
		||||
#
 | 
			
		||||
# @id:      #optional The name or QOM path of the guest device (since: 2.8)
 | 
			
		||||
#
 | 
			
		||||
# Since: 2.5
 | 
			
		||||
##
 | 
			
		||||
{ 'command': 'blockdev-close-tray',
 | 
			
		||||
  'data': { 'device': 'str' } }
 | 
			
		||||
  'data': { '*device': 'str',
 | 
			
		||||
            '*id': 'str' } }
 | 
			
		||||
 | 
			
		||||
##
 | 
			
		||||
# @x-blockdev-remove-medium:
 | 
			
		||||
@ -2404,12 +2394,15 @@
 | 
			
		||||
# This command is still a work in progress and is considered experimental.
 | 
			
		||||
# Stay away from it unless you want to help with its development.
 | 
			
		||||
#
 | 
			
		||||
# @device: block device name
 | 
			
		||||
# @device: #optional Block device name (deprecated, use @id instead)
 | 
			
		||||
#
 | 
			
		||||
# @id:     #optional The name or QOM path of the guest device (since: 2.8)
 | 
			
		||||
#
 | 
			
		||||
# Since: 2.5
 | 
			
		||||
##
 | 
			
		||||
{ 'command': 'x-blockdev-remove-medium',
 | 
			
		||||
  'data': { 'device': 'str' } }
 | 
			
		||||
  'data': { '*device': 'str',
 | 
			
		||||
            '*id': 'str' } }
 | 
			
		||||
 | 
			
		||||
##
 | 
			
		||||
# @x-blockdev-insert-medium:
 | 
			
		||||
@ -2421,14 +2414,17 @@
 | 
			
		||||
# This command is still a work in progress and is considered experimental.
 | 
			
		||||
# Stay away from it unless you want to help with its development.
 | 
			
		||||
#
 | 
			
		||||
# @device:    block device name
 | 
			
		||||
# @device:    #optional Block device name (deprecated, use @id instead)
 | 
			
		||||
#
 | 
			
		||||
# @id:        #optional The name or QOM path of the guest device (since: 2.8)
 | 
			
		||||
#
 | 
			
		||||
# @node-name: name of a node in the block driver state graph
 | 
			
		||||
#
 | 
			
		||||
# Since: 2.5
 | 
			
		||||
##
 | 
			
		||||
{ 'command': 'x-blockdev-insert-medium',
 | 
			
		||||
  'data': { 'device': 'str',
 | 
			
		||||
  'data': { '*device': 'str',
 | 
			
		||||
            '*id': 'str',
 | 
			
		||||
            'node-name': 'str'} }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -2458,7 +2454,10 @@
 | 
			
		||||
# combines blockdev-open-tray, x-blockdev-remove-medium,
 | 
			
		||||
# x-blockdev-insert-medium and blockdev-close-tray).
 | 
			
		||||
#
 | 
			
		||||
# @device:          block device name
 | 
			
		||||
# @device:          #optional Block device name (deprecated, use @id instead)
 | 
			
		||||
#
 | 
			
		||||
# @id:              #optional The name or QOM path of the guest device
 | 
			
		||||
#                   (since: 2.8)
 | 
			
		||||
#
 | 
			
		||||
# @filename:        filename of the new image to be loaded
 | 
			
		||||
#
 | 
			
		||||
@ -2471,7 +2470,8 @@
 | 
			
		||||
# Since: 2.5
 | 
			
		||||
##
 | 
			
		||||
{ 'command': 'blockdev-change-medium',
 | 
			
		||||
  'data': { 'device': 'str',
 | 
			
		||||
  'data': { '*device': 'str',
 | 
			
		||||
            '*id': 'str',
 | 
			
		||||
            'filename': 'str',
 | 
			
		||||
            '*format': 'str',
 | 
			
		||||
            '*read-only-mode': 'BlockdevChangeReadOnlyMode' } }
 | 
			
		||||
 | 
			
		||||
@ -125,7 +125,9 @@
 | 
			
		||||
#
 | 
			
		||||
# Ejects a device from a removable drive.
 | 
			
		||||
#
 | 
			
		||||
# @device:  The name of the device
 | 
			
		||||
# @device:  #optional Block device name (deprecated, use @id instead)
 | 
			
		||||
#
 | 
			
		||||
# @id:      #optional The name or QOM path of the guest device (since: 2.8)
 | 
			
		||||
#
 | 
			
		||||
# @force:   @optional If true, eject regardless of whether the drive is locked.
 | 
			
		||||
#           If not specified, the default value is false.
 | 
			
		||||
@ -137,7 +139,10 @@
 | 
			
		||||
#
 | 
			
		||||
# Since: 0.14.0
 | 
			
		||||
##
 | 
			
		||||
{ 'command': 'eject', 'data': {'device': 'str', '*force': 'bool'} }
 | 
			
		||||
{ 'command': 'eject',
 | 
			
		||||
  'data': { '*device': 'str',
 | 
			
		||||
            '*id': 'str',
 | 
			
		||||
            '*force': 'bool' } }
 | 
			
		||||
 | 
			
		||||
##
 | 
			
		||||
# @nbd-server-start:
 | 
			
		||||
 | 
			
		||||
@ -28,6 +28,7 @@
 | 
			
		||||
#include "qemu/config-file.h"
 | 
			
		||||
#include "qemu/error-report.h"
 | 
			
		||||
#include "qemu/help_option.h"
 | 
			
		||||
#include "sysemu/block-backend.h"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Aliases were a bad idea from the start.  Let's keep them
 | 
			
		||||
@ -801,7 +802,7 @@ void qmp_device_add(QDict *qdict, QObject **ret_data, Error **errp)
 | 
			
		||||
    object_unref(OBJECT(dev));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void qmp_device_del(const char *id, Error **errp)
 | 
			
		||||
static DeviceState *find_device_state(const char *id, Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    Object *obj;
 | 
			
		||||
 | 
			
		||||
@ -819,15 +820,40 @@ void qmp_device_del(const char *id, Error **errp)
 | 
			
		||||
    if (!obj) {
 | 
			
		||||
        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
 | 
			
		||||
                  "Device '%s' not found", id);
 | 
			
		||||
        return;
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!object_dynamic_cast(obj, TYPE_DEVICE)) {
 | 
			
		||||
        error_setg(errp, "%s is not a hotpluggable device", id);
 | 
			
		||||
        return;
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    qdev_unplug(DEVICE(obj), errp);
 | 
			
		||||
    return DEVICE(obj);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void qmp_device_del(const char *id, Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    DeviceState *dev = find_device_state(id, errp);
 | 
			
		||||
    if (dev != NULL) {
 | 
			
		||||
        qdev_unplug(dev, errp);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BlockBackend *blk_by_qdev_id(const char *id, Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    DeviceState *dev;
 | 
			
		||||
    BlockBackend *blk;
 | 
			
		||||
 | 
			
		||||
    dev = find_device_state(id, errp);
 | 
			
		||||
    if (dev == NULL) {
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    blk = blk_by_dev(dev);
 | 
			
		||||
    if (!blk) {
 | 
			
		||||
        error_setg(errp, "Device does not have a block device backend");
 | 
			
		||||
    }
 | 
			
		||||
    return blk;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void qdev_machine_init(void)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										4
									
								
								qmp.c
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								qmp.c
									
									
									
									
									
								
							@ -431,8 +431,8 @@ void qmp_change(const char *device, const char *target,
 | 
			
		||||
    if (strcmp(device, "vnc") == 0) {
 | 
			
		||||
        qmp_change_vnc(target, has_arg, arg, errp);
 | 
			
		||||
    } else {
 | 
			
		||||
        qmp_blockdev_change_medium(device, target, has_arg, arg, false, 0,
 | 
			
		||||
                                   errp);
 | 
			
		||||
        qmp_blockdev_change_medium(true, device, false, NULL, target,
 | 
			
		||||
                                   has_arg, arg, false, 0, errp);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,10 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
 | 
			
		||||
FORMAT_LIST="raw qcow2 qed vmdk vpc"
 | 
			
		||||
if [ "$#" -ne 0 ]; then
 | 
			
		||||
    FORMAT_LIST="$@"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
export QEMU_PROG="$(pwd)/x86_64-softmmu/qemu-system-x86_64"
 | 
			
		||||
export QEMU_IMG_PROG="$(pwd)/qemu-img"
 | 
			
		||||
export QEMU_IO_PROG="$(pwd)/qemu-io"
 | 
			
		||||
@ -12,10 +17,8 @@ fi
 | 
			
		||||
cd tests/qemu-iotests
 | 
			
		||||
 | 
			
		||||
ret=0
 | 
			
		||||
./check -T -nocache -raw || ret=1
 | 
			
		||||
./check -T -nocache -qcow2 || ret=1
 | 
			
		||||
./check -T -nocache -qed|| ret=1
 | 
			
		||||
./check -T -nocache -vmdk|| ret=1
 | 
			
		||||
./check -T -nocache -vpc || ret=1
 | 
			
		||||
for FMT in $FORMAT_LIST ; do
 | 
			
		||||
    ./check -T -nocache -$FMT || ret=1
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
exit $ret
 | 
			
		||||
 | 
			
		||||
@ -782,7 +782,7 @@ class TestRepairQuorum(iotests.QMPTestCase):
 | 
			
		||||
        self.vm.launch()
 | 
			
		||||
 | 
			
		||||
        #assemble the quorum block device from the individual files
 | 
			
		||||
        args = { "options" : { "driver": "quorum", "id": "quorum0",
 | 
			
		||||
        args = { "options" : { "driver": "quorum", "node-name": "quorum0",
 | 
			
		||||
                 "vote-threshold": 2, "children": [ "img0", "img1", "img2" ] } }
 | 
			
		||||
        if self.has_quorum():
 | 
			
		||||
            result = self.vm.qmp("blockdev-add", **args)
 | 
			
		||||
@ -804,13 +804,12 @@ class TestRepairQuorum(iotests.QMPTestCase):
 | 
			
		||||
 | 
			
		||||
        self.assert_no_active_block_jobs()
 | 
			
		||||
 | 
			
		||||
        result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
 | 
			
		||||
                             node_name="repair0",
 | 
			
		||||
                             replaces="img1",
 | 
			
		||||
        result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0',
 | 
			
		||||
                             sync='full', node_name="repair0", replaces="img1",
 | 
			
		||||
                             target=quorum_repair_img, format=iotests.imgfmt)
 | 
			
		||||
        self.assert_qmp(result, 'return', {})
 | 
			
		||||
 | 
			
		||||
        self.complete_and_wait(drive="quorum0")
 | 
			
		||||
        self.complete_and_wait(drive="job0")
 | 
			
		||||
        self.assert_has_block_node("repair0", quorum_repair_img)
 | 
			
		||||
        # TODO: a better test requiring some QEMU infrastructure will be added
 | 
			
		||||
        #       to check that this file is really driven by quorum
 | 
			
		||||
@ -824,13 +823,12 @@ class TestRepairQuorum(iotests.QMPTestCase):
 | 
			
		||||
 | 
			
		||||
        self.assert_no_active_block_jobs()
 | 
			
		||||
 | 
			
		||||
        result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
 | 
			
		||||
                             node_name="repair0",
 | 
			
		||||
                             replaces="img1",
 | 
			
		||||
        result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0',
 | 
			
		||||
                             sync='full', node_name="repair0", replaces="img1",
 | 
			
		||||
                             target=quorum_repair_img, format=iotests.imgfmt)
 | 
			
		||||
        self.assert_qmp(result, 'return', {})
 | 
			
		||||
 | 
			
		||||
        self.cancel_and_wait(drive="quorum0", force=True)
 | 
			
		||||
        self.cancel_and_wait(drive="job0", force=True)
 | 
			
		||||
        # here we check that the last registered quorum file has not been
 | 
			
		||||
        # swapped out and unref
 | 
			
		||||
        self.assert_has_block_node(None, quorum_img3)
 | 
			
		||||
@ -842,13 +840,12 @@ class TestRepairQuorum(iotests.QMPTestCase):
 | 
			
		||||
 | 
			
		||||
        self.assert_no_active_block_jobs()
 | 
			
		||||
 | 
			
		||||
        result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
 | 
			
		||||
                             node_name="repair0",
 | 
			
		||||
                             replaces="img1",
 | 
			
		||||
        result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0',
 | 
			
		||||
                             sync='full', node_name="repair0", replaces="img1",
 | 
			
		||||
                             target=quorum_repair_img, format=iotests.imgfmt)
 | 
			
		||||
        self.assert_qmp(result, 'return', {})
 | 
			
		||||
 | 
			
		||||
        self.wait_ready_and_cancel(drive="quorum0")
 | 
			
		||||
        self.wait_ready_and_cancel(drive="job0")
 | 
			
		||||
        # here we check that the last registered quorum file has not been
 | 
			
		||||
        # swapped out and unref
 | 
			
		||||
        self.assert_has_block_node(None, quorum_img3)
 | 
			
		||||
@ -862,13 +859,12 @@ class TestRepairQuorum(iotests.QMPTestCase):
 | 
			
		||||
 | 
			
		||||
        self.assert_no_active_block_jobs()
 | 
			
		||||
 | 
			
		||||
        result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
 | 
			
		||||
                             node_name="repair0",
 | 
			
		||||
                             replaces="img1",
 | 
			
		||||
        result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0',
 | 
			
		||||
                             sync='full', node_name="repair0", replaces="img1",
 | 
			
		||||
                             target=quorum_repair_img, format=iotests.imgfmt)
 | 
			
		||||
        self.assert_qmp(result, 'return', {})
 | 
			
		||||
 | 
			
		||||
        result = self.vm.qmp('block-job-pause', device='quorum0')
 | 
			
		||||
        result = self.vm.qmp('block-job-pause', device='job0')
 | 
			
		||||
        self.assert_qmp(result, 'return', {})
 | 
			
		||||
 | 
			
		||||
        time.sleep(1)
 | 
			
		||||
@ -879,10 +875,10 @@ class TestRepairQuorum(iotests.QMPTestCase):
 | 
			
		||||
        result = self.vm.qmp('query-block-jobs')
 | 
			
		||||
        self.assert_qmp(result, 'return[0]/offset', offset)
 | 
			
		||||
 | 
			
		||||
        result = self.vm.qmp('block-job-resume', device='quorum0')
 | 
			
		||||
        result = self.vm.qmp('block-job-resume', device='job0')
 | 
			
		||||
        self.assert_qmp(result, 'return', {})
 | 
			
		||||
 | 
			
		||||
        self.complete_and_wait(drive="quorum0")
 | 
			
		||||
        self.complete_and_wait(drive="job0")
 | 
			
		||||
        self.vm.shutdown()
 | 
			
		||||
        self.assertTrue(iotests.compare_images(quorum_img2, quorum_repair_img),
 | 
			
		||||
                        'target image does not match source after mirroring')
 | 
			
		||||
@ -894,7 +890,7 @@ class TestRepairQuorum(iotests.QMPTestCase):
 | 
			
		||||
        if iotests.qemu_default_machine != 'pc':
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        result = self.vm.qmp('drive-mirror', device='drive0', # CD-ROM
 | 
			
		||||
        result = self.vm.qmp('drive-mirror', job_id='job0', device='drive0', # CD-ROM
 | 
			
		||||
                             sync='full',
 | 
			
		||||
                             node_name='repair0',
 | 
			
		||||
                             replaces='img1',
 | 
			
		||||
@ -905,18 +901,18 @@ class TestRepairQuorum(iotests.QMPTestCase):
 | 
			
		||||
        if not self.has_quorum():
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
 | 
			
		||||
                             node_name='repair0',
 | 
			
		||||
                             replaces='img1',
 | 
			
		||||
                             mode='existing',
 | 
			
		||||
                             target=quorum_repair_img, format=iotests.imgfmt)
 | 
			
		||||
        result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0',
 | 
			
		||||
                             sync='full', node_name='repair0', replaces='img1',
 | 
			
		||||
                             mode='existing', target=quorum_repair_img,
 | 
			
		||||
                             format=iotests.imgfmt)
 | 
			
		||||
        self.assert_qmp(result, 'error/class', 'GenericError')
 | 
			
		||||
 | 
			
		||||
    def test_device_not_found(self):
 | 
			
		||||
        if not self.has_quorum():
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        result = self.vm.qmp('drive-mirror', device='nonexistent', sync='full',
 | 
			
		||||
        result = self.vm.qmp('drive-mirror', job_id='job0',
 | 
			
		||||
                             device='nonexistent', sync='full',
 | 
			
		||||
                             node_name='repair0',
 | 
			
		||||
                             replaces='img1',
 | 
			
		||||
                             target=quorum_repair_img, format=iotests.imgfmt)
 | 
			
		||||
@ -926,7 +922,7 @@ class TestRepairQuorum(iotests.QMPTestCase):
 | 
			
		||||
        if not self.has_quorum():
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        result = self.vm.qmp('drive-mirror', device='quorum0',
 | 
			
		||||
        result = self.vm.qmp('drive-mirror', device='quorum0', job_id='job0',
 | 
			
		||||
                             node_name='repair0',
 | 
			
		||||
                             replaces='img1',
 | 
			
		||||
                             target=quorum_repair_img, format=iotests.imgfmt)
 | 
			
		||||
@ -936,8 +932,8 @@ class TestRepairQuorum(iotests.QMPTestCase):
 | 
			
		||||
        if not self.has_quorum():
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
 | 
			
		||||
                             replaces='img1',
 | 
			
		||||
        result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0',
 | 
			
		||||
                             sync='full', replaces='img1',
 | 
			
		||||
                             target=quorum_repair_img, format=iotests.imgfmt)
 | 
			
		||||
        self.assert_qmp(result, 'error/class', 'GenericError')
 | 
			
		||||
 | 
			
		||||
@ -945,9 +941,8 @@ class TestRepairQuorum(iotests.QMPTestCase):
 | 
			
		||||
        if not self.has_quorum():
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
 | 
			
		||||
                             node_name='repair0',
 | 
			
		||||
                             replaces='img77',
 | 
			
		||||
        result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0',
 | 
			
		||||
                             sync='full', node_name='repair0', replaces='img77',
 | 
			
		||||
                             target=quorum_repair_img, format=iotests.imgfmt)
 | 
			
		||||
        self.assert_qmp(result, 'error/class', 'GenericError')
 | 
			
		||||
 | 
			
		||||
@ -959,19 +954,17 @@ class TestRepairQuorum(iotests.QMPTestCase):
 | 
			
		||||
                             snapshot_file=quorum_snapshot_file,
 | 
			
		||||
                             snapshot_node_name="snap1");
 | 
			
		||||
 | 
			
		||||
        result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
 | 
			
		||||
                             node_name='repair0',
 | 
			
		||||
                             replaces="img1",
 | 
			
		||||
        result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0',
 | 
			
		||||
                             sync='full', node_name='repair0', replaces="img1",
 | 
			
		||||
                             target=quorum_repair_img, format=iotests.imgfmt)
 | 
			
		||||
        self.assert_qmp(result, 'error/class', 'GenericError')
 | 
			
		||||
 | 
			
		||||
        result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
 | 
			
		||||
                             node_name='repair0',
 | 
			
		||||
                             replaces="snap1",
 | 
			
		||||
        result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0',
 | 
			
		||||
                             sync='full', node_name='repair0', replaces="snap1",
 | 
			
		||||
                             target=quorum_repair_img, format=iotests.imgfmt)
 | 
			
		||||
        self.assert_qmp(result, 'return', {})
 | 
			
		||||
 | 
			
		||||
        self.complete_and_wait(drive="quorum0")
 | 
			
		||||
        self.complete_and_wait('job0')
 | 
			
		||||
        self.assert_has_block_node("repair0", quorum_repair_img)
 | 
			
		||||
        # TODO: a better test requiring some QEMU infrastructure will be added
 | 
			
		||||
        #       to check that this file is really driven by quorum
 | 
			
		||||
 | 
			
		||||
@ -121,7 +121,7 @@ run_qemu <<EOF
 | 
			
		||||
  "arguments": {
 | 
			
		||||
      "options": {
 | 
			
		||||
        "driver": "$IMGFMT",
 | 
			
		||||
        "id": "disk",
 | 
			
		||||
        "node-name": "disk",
 | 
			
		||||
        "file": {
 | 
			
		||||
            "driver": "file",
 | 
			
		||||
            "filename": "$TEST_IMG"
 | 
			
		||||
@ -129,13 +129,13 @@ run_qemu <<EOF
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
{ "execute": "query-block" }
 | 
			
		||||
{ "execute": "query-named-block-nodes" }
 | 
			
		||||
{ "execute": "device_add",
 | 
			
		||||
   "arguments": { "driver": "virtio-blk", "drive": "disk",
 | 
			
		||||
                  "id": "virtio0" } }
 | 
			
		||||
{ "execute": "device_del", "arguments": { "id": "virtio0" } }
 | 
			
		||||
{ "execute": "system_reset" }
 | 
			
		||||
{ "execute": "query-block" }
 | 
			
		||||
{ "execute": "query-named-block-nodes" }
 | 
			
		||||
{ "execute": "quit" }
 | 
			
		||||
EOF
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -258,10 +258,6 @@ Testing:
 | 
			
		||||
{
 | 
			
		||||
    "return": [
 | 
			
		||||
        {
 | 
			
		||||
            "device": "disk",
 | 
			
		||||
            "locked": false,
 | 
			
		||||
            "removable": true,
 | 
			
		||||
            "inserted": {
 | 
			
		||||
            "iops_rd": 0,
 | 
			
		||||
            "detect_zeroes": "off",
 | 
			
		||||
            "image": {
 | 
			
		||||
@ -283,7 +279,7 @@ Testing:
 | 
			
		||||
            },
 | 
			
		||||
            "iops_wr": 0,
 | 
			
		||||
            "ro": false,
 | 
			
		||||
                "node-name": "NODE_NAME",
 | 
			
		||||
            "node-name": "disk",
 | 
			
		||||
            "backing_file_depth": 0,
 | 
			
		||||
            "drv": "qcow2",
 | 
			
		||||
            "iops": 0,
 | 
			
		||||
@ -300,7 +296,34 @@ Testing:
 | 
			
		||||
            "file": "TEST_DIR/t.qcow2",
 | 
			
		||||
            "encryption_key_missing": false
 | 
			
		||||
        },
 | 
			
		||||
            "type": "unknown"
 | 
			
		||||
        {
 | 
			
		||||
            "iops_rd": 0,
 | 
			
		||||
            "detect_zeroes": "off",
 | 
			
		||||
            "image": {
 | 
			
		||||
                "virtual-size": 197120,
 | 
			
		||||
                "filename": "TEST_DIR/t.qcow2",
 | 
			
		||||
                "format": "file",
 | 
			
		||||
                "actual-size": SIZE,
 | 
			
		||||
                "dirty-flag": false
 | 
			
		||||
            },
 | 
			
		||||
            "iops_wr": 0,
 | 
			
		||||
            "ro": false,
 | 
			
		||||
            "node-name": "NODE_NAME",
 | 
			
		||||
            "backing_file_depth": 0,
 | 
			
		||||
            "drv": "file",
 | 
			
		||||
            "iops": 0,
 | 
			
		||||
            "bps_wr": 0,
 | 
			
		||||
            "write_threshold": 0,
 | 
			
		||||
            "encrypted": false,
 | 
			
		||||
            "bps": 0,
 | 
			
		||||
            "bps_rd": 0,
 | 
			
		||||
            "cache": {
 | 
			
		||||
                "no-flush": false,
 | 
			
		||||
                "direct": false,
 | 
			
		||||
                "writeback": true
 | 
			
		||||
            },
 | 
			
		||||
            "file": "TEST_DIR/t.qcow2",
 | 
			
		||||
            "encryption_key_missing": false
 | 
			
		||||
        }
 | 
			
		||||
    ]
 | 
			
		||||
}
 | 
			
		||||
@ -319,11 +342,6 @@ Testing:
 | 
			
		||||
{
 | 
			
		||||
    "return": [
 | 
			
		||||
        {
 | 
			
		||||
            "io-status": "ok",
 | 
			
		||||
            "device": "disk",
 | 
			
		||||
            "locked": false,
 | 
			
		||||
            "removable": true,
 | 
			
		||||
            "inserted": {
 | 
			
		||||
            "iops_rd": 0,
 | 
			
		||||
            "detect_zeroes": "off",
 | 
			
		||||
            "image": {
 | 
			
		||||
@ -345,7 +363,7 @@ Testing:
 | 
			
		||||
            },
 | 
			
		||||
            "iops_wr": 0,
 | 
			
		||||
            "ro": false,
 | 
			
		||||
                "node-name": "NODE_NAME",
 | 
			
		||||
            "node-name": "disk",
 | 
			
		||||
            "backing_file_depth": 0,
 | 
			
		||||
            "drv": "qcow2",
 | 
			
		||||
            "iops": 0,
 | 
			
		||||
@ -362,7 +380,34 @@ Testing:
 | 
			
		||||
            "file": "TEST_DIR/t.qcow2",
 | 
			
		||||
            "encryption_key_missing": false
 | 
			
		||||
        },
 | 
			
		||||
            "type": "unknown"
 | 
			
		||||
        {
 | 
			
		||||
            "iops_rd": 0,
 | 
			
		||||
            "detect_zeroes": "off",
 | 
			
		||||
            "image": {
 | 
			
		||||
                "virtual-size": 197120,
 | 
			
		||||
                "filename": "TEST_DIR/t.qcow2",
 | 
			
		||||
                "format": "file",
 | 
			
		||||
                "actual-size": SIZE,
 | 
			
		||||
                "dirty-flag": false
 | 
			
		||||
            },
 | 
			
		||||
            "iops_wr": 0,
 | 
			
		||||
            "ro": false,
 | 
			
		||||
            "node-name": "NODE_NAME",
 | 
			
		||||
            "backing_file_depth": 0,
 | 
			
		||||
            "drv": "file",
 | 
			
		||||
            "iops": 0,
 | 
			
		||||
            "bps_wr": 0,
 | 
			
		||||
            "write_threshold": 0,
 | 
			
		||||
            "encrypted": false,
 | 
			
		||||
            "bps": 0,
 | 
			
		||||
            "bps_rd": 0,
 | 
			
		||||
            "cache": {
 | 
			
		||||
                "no-flush": false,
 | 
			
		||||
                "direct": false,
 | 
			
		||||
                "writeback": true
 | 
			
		||||
            },
 | 
			
		||||
            "file": "TEST_DIR/t.qcow2",
 | 
			
		||||
            "encryption_key_missing": false
 | 
			
		||||
        }
 | 
			
		||||
    ]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -118,7 +118,7 @@ run_qemu <<EOF
 | 
			
		||||
    "arguments": {
 | 
			
		||||
        "options": {
 | 
			
		||||
            "driver": "$IMGFMT",
 | 
			
		||||
            "id": "drive0-debug",
 | 
			
		||||
            "node-name": "drive0-debug",
 | 
			
		||||
            "file": {
 | 
			
		||||
                "driver": "blkdebug",
 | 
			
		||||
                "image": "drive0",
 | 
			
		||||
@ -159,7 +159,7 @@ run_qemu <<EOF
 | 
			
		||||
    "arguments": {
 | 
			
		||||
        "options": {
 | 
			
		||||
            "driver": "blkverify",
 | 
			
		||||
            "id": "drive0-verify",
 | 
			
		||||
            "node-name": "drive0-verify",
 | 
			
		||||
            "test": "drive0",
 | 
			
		||||
            "raw": {
 | 
			
		||||
                "driver": "file",
 | 
			
		||||
@ -195,7 +195,7 @@ run_qemu <<EOF
 | 
			
		||||
    "arguments": {
 | 
			
		||||
        "options": {
 | 
			
		||||
            "driver": "blkverify",
 | 
			
		||||
            "id": "drive0-verify",
 | 
			
		||||
            "node-name": "drive0-verify",
 | 
			
		||||
            "test": {
 | 
			
		||||
                "driver": "$IMGFMT",
 | 
			
		||||
                "file": {
 | 
			
		||||
@ -234,7 +234,7 @@ run_qemu <<EOF
 | 
			
		||||
    "arguments": {
 | 
			
		||||
        "options": {
 | 
			
		||||
            "driver": "$IMGFMT",
 | 
			
		||||
            "id": "drive0-debug",
 | 
			
		||||
            "node-name": "drive0-debug",
 | 
			
		||||
            "file": {
 | 
			
		||||
                "driver": "blkdebug",
 | 
			
		||||
                "image": "drive0",
 | 
			
		||||
 | 
			
		||||
@ -119,7 +119,7 @@ run_qemu <<EOF
 | 
			
		||||
    "arguments": {
 | 
			
		||||
        "options": {
 | 
			
		||||
            "driver": "quorum",
 | 
			
		||||
            "id": "drive0-quorum",
 | 
			
		||||
            "node-name": "drive0-quorum",
 | 
			
		||||
            "vote-threshold": 2,
 | 
			
		||||
            "children": [
 | 
			
		||||
                {
 | 
			
		||||
 | 
			
		||||
@ -68,9 +68,9 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/
 | 
			
		||||
 | 
			
		||||
=== Invalid command - snapshot node used as active layer ===
 | 
			
		||||
 | 
			
		||||
{"error": {"class": "GenericError", "desc": "The snapshot is already in use by virtio0"}}
 | 
			
		||||
{"error": {"class": "GenericError", "desc": "The snapshot is already in use by virtio0"}}
 | 
			
		||||
{"error": {"class": "GenericError", "desc": "The snapshot is already in use by virtio1"}}
 | 
			
		||||
{"error": {"class": "GenericError", "desc": "The snapshot is already in use"}}
 | 
			
		||||
{"error": {"class": "GenericError", "desc": "The snapshot is already in use"}}
 | 
			
		||||
{"error": {"class": "GenericError", "desc": "The snapshot is already in use"}}
 | 
			
		||||
 | 
			
		||||
=== Invalid command - snapshot node used as backing hd ===
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -77,50 +77,12 @@ echo
 | 
			
		||||
echo === Duplicate ID ===
 | 
			
		||||
echo
 | 
			
		||||
 | 
			
		||||
run_qemu <<EOF
 | 
			
		||||
run_qemu -drive driver=$IMGFMT,id=disk,node-name=test-node,file="$TEST_IMG" <<EOF
 | 
			
		||||
{ "execute": "qmp_capabilities" }
 | 
			
		||||
{ "execute": "blockdev-add",
 | 
			
		||||
  "arguments": {
 | 
			
		||||
      "options": {
 | 
			
		||||
        "driver": "$IMGFMT",
 | 
			
		||||
        "id": "disk",
 | 
			
		||||
        "node-name": "test-node",
 | 
			
		||||
        "file": {
 | 
			
		||||
            "driver": "file",
 | 
			
		||||
            "filename": "$TEST_IMG"
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
{ "execute": "blockdev-add",
 | 
			
		||||
  "arguments": {
 | 
			
		||||
      "options": {
 | 
			
		||||
        "driver": "$IMGFMT",
 | 
			
		||||
        "id": "disk",
 | 
			
		||||
        "file": {
 | 
			
		||||
            "driver": "file",
 | 
			
		||||
            "filename": "$TEST_IMG"
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
{ "execute": "blockdev-add",
 | 
			
		||||
  "arguments": {
 | 
			
		||||
      "options": {
 | 
			
		||||
        "driver": "$IMGFMT",
 | 
			
		||||
        "id": "test-node",
 | 
			
		||||
        "file": {
 | 
			
		||||
            "driver": "file",
 | 
			
		||||
            "filename": "$TEST_IMG"
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
{ "execute": "blockdev-add",
 | 
			
		||||
  "arguments": {
 | 
			
		||||
      "options": {
 | 
			
		||||
        "driver": "$IMGFMT",
 | 
			
		||||
        "id": "disk2",
 | 
			
		||||
        "node-name": "disk",
 | 
			
		||||
        "file": {
 | 
			
		||||
            "driver": "file",
 | 
			
		||||
@ -133,7 +95,6 @@ run_qemu <<EOF
 | 
			
		||||
  "arguments": {
 | 
			
		||||
      "options": {
 | 
			
		||||
        "driver": "$IMGFMT",
 | 
			
		||||
        "id": "disk2",
 | 
			
		||||
        "node-name": "test-node",
 | 
			
		||||
        "file": {
 | 
			
		||||
            "driver": "file",
 | 
			
		||||
@ -142,19 +103,6 @@ run_qemu <<EOF
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
{ "execute": "blockdev-add",
 | 
			
		||||
  "arguments": {
 | 
			
		||||
      "options": {
 | 
			
		||||
        "driver": "$IMGFMT",
 | 
			
		||||
        "id": "disk3",
 | 
			
		||||
        "node-name": "disk3",
 | 
			
		||||
        "file": {
 | 
			
		||||
            "driver": "file",
 | 
			
		||||
            "filename": "$TEST_IMG"
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
{ "execute": "quit" }
 | 
			
		||||
EOF
 | 
			
		||||
 | 
			
		||||
@ -168,7 +116,7 @@ run_qemu <<EOF
 | 
			
		||||
  "arguments": {
 | 
			
		||||
      "options": {
 | 
			
		||||
        "driver": "$IMGFMT",
 | 
			
		||||
        "id": "disk",
 | 
			
		||||
        "node-name": "disk",
 | 
			
		||||
        "aio": "native",
 | 
			
		||||
        "file": {
 | 
			
		||||
            "driver": "file",
 | 
			
		||||
@ -191,7 +139,7 @@ run_qemu -S <<EOF
 | 
			
		||||
  "arguments": {
 | 
			
		||||
      "options": {
 | 
			
		||||
        "driver": "$IMGFMT",
 | 
			
		||||
        "id": "disk",
 | 
			
		||||
        "node-name": "disk",
 | 
			
		||||
        "file": {
 | 
			
		||||
            "driver": "file",
 | 
			
		||||
            "filename": "$TEST_IMG"
 | 
			
		||||
@ -208,7 +156,7 @@ run_qemu <<EOF
 | 
			
		||||
  "arguments": {
 | 
			
		||||
      "options": {
 | 
			
		||||
        "driver": "$IMGFMT",
 | 
			
		||||
        "id": "disk",
 | 
			
		||||
        "node-name": "disk",
 | 
			
		||||
        "file": {
 | 
			
		||||
            "driver": "file",
 | 
			
		||||
            "filename": "$TEST_IMG"
 | 
			
		||||
@ -229,7 +177,7 @@ run_qemu -S <<EOF
 | 
			
		||||
{ "execute": "blockdev-add",
 | 
			
		||||
  "arguments": {
 | 
			
		||||
      "options": {
 | 
			
		||||
        "id": "disk"
 | 
			
		||||
        "node-name": "disk"
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -6,22 +6,18 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
 | 
			
		||||
Testing:
 | 
			
		||||
QMP_VERSION
 | 
			
		||||
{"return": {}}
 | 
			
		||||
{"error": {"class": "GenericError", "desc": "'id' and/or 'node-name' need to be specified for the root node"}}
 | 
			
		||||
{"error": {"class": "GenericError", "desc": "'node-name' must be specified for the root node"}}
 | 
			
		||||
{"return": {}}
 | 
			
		||||
{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
=== Duplicate ID ===
 | 
			
		||||
 | 
			
		||||
Testing:
 | 
			
		||||
Testing: -drive driver=IMGFMT,id=disk,node-name=test-node,file=TEST_DIR/t.IMGFMT
 | 
			
		||||
QMP_VERSION
 | 
			
		||||
{"return": {}}
 | 
			
		||||
{"return": {}}
 | 
			
		||||
{"error": {"class": "GenericError", "desc": "Device with id 'disk' already exists"}}
 | 
			
		||||
{"error": {"class": "GenericError", "desc": "Device name 'test-node' conflicts with an existing node name"}}
 | 
			
		||||
{"error": {"class": "GenericError", "desc": "node-name=disk is conflicting with a device id"}}
 | 
			
		||||
{"error": {"class": "GenericError", "desc": "Duplicate node name"}}
 | 
			
		||||
{"error": {"class": "GenericError", "desc": "Device name 'disk3' conflicts with an existing node name"}}
 | 
			
		||||
{"return": {}}
 | 
			
		||||
{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -52,14 +52,14 @@ _send_qemu_cmd $QEMU_HANDLE \
 | 
			
		||||
 | 
			
		||||
_send_qemu_cmd $QEMU_HANDLE \
 | 
			
		||||
    "{ 'execute': 'blockdev-add',
 | 
			
		||||
       'arguments': { 'options': { 'id': 'protocol',
 | 
			
		||||
       'arguments': { 'options': { 'node-name': 'protocol',
 | 
			
		||||
                                   'driver': 'file',
 | 
			
		||||
                                   'filename': '$TEST_IMG' } } }" \
 | 
			
		||||
    'return'
 | 
			
		||||
 | 
			
		||||
_send_qemu_cmd $QEMU_HANDLE \
 | 
			
		||||
    "{ 'execute': 'blockdev-add',
 | 
			
		||||
       'arguments': { 'options': { 'id': 'format',
 | 
			
		||||
       'arguments': { 'options': { 'node-name': 'format',
 | 
			
		||||
                                   'driver': '$IMGFMT',
 | 
			
		||||
                                   'file': 'protocol' } } }" \
 | 
			
		||||
    'return'
 | 
			
		||||
 | 
			
		||||
@ -62,6 +62,9 @@ class ChangeBaseClass(iotests.QMPTestCase):
 | 
			
		||||
            self.fail('Timeout while waiting for the tray to close')
 | 
			
		||||
 | 
			
		||||
class GeneralChangeTestsBaseClass(ChangeBaseClass):
 | 
			
		||||
 | 
			
		||||
    device_name = None
 | 
			
		||||
 | 
			
		||||
    def test_change(self):
 | 
			
		||||
        result = self.vm.qmp('change', device='drive0', target=new_img,
 | 
			
		||||
                                       arg=iotests.imgfmt)
 | 
			
		||||
@ -76,9 +79,15 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
 | 
			
		||||
        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
 | 
			
		||||
 | 
			
		||||
    def test_blockdev_change_medium(self):
 | 
			
		||||
        result = self.vm.qmp('blockdev-change-medium', device='drive0',
 | 
			
		||||
                                                       filename=new_img,
 | 
			
		||||
        if self.device_name is not None:
 | 
			
		||||
            result = self.vm.qmp('blockdev-change-medium',
 | 
			
		||||
                                 id=self.device_name, filename=new_img,
 | 
			
		||||
                                 format=iotests.imgfmt)
 | 
			
		||||
        else:
 | 
			
		||||
            result = self.vm.qmp('blockdev-change-medium',
 | 
			
		||||
                                 device='drive0', filename=new_img,
 | 
			
		||||
                                 format=iotests.imgfmt)
 | 
			
		||||
 | 
			
		||||
        self.assert_qmp(result, 'return', {})
 | 
			
		||||
 | 
			
		||||
        self.wait_for_open()
 | 
			
		||||
@ -90,6 +99,9 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
 | 
			
		||||
        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
 | 
			
		||||
 | 
			
		||||
    def test_eject(self):
 | 
			
		||||
        if self.device_name is not None:
 | 
			
		||||
            result = self.vm.qmp('eject', id=self.device_name, force=True)
 | 
			
		||||
        else:
 | 
			
		||||
            result = self.vm.qmp('eject', device='drive0', force=True)
 | 
			
		||||
        self.assert_qmp(result, 'return', {})
 | 
			
		||||
 | 
			
		||||
@ -101,6 +113,9 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
 | 
			
		||||
        self.assert_qmp_absent(result, 'return[0]/inserted')
 | 
			
		||||
 | 
			
		||||
    def test_tray_eject_change(self):
 | 
			
		||||
        if self.device_name is not None:
 | 
			
		||||
            result = self.vm.qmp('eject', id=self.device_name, force=True)
 | 
			
		||||
        else:
 | 
			
		||||
            result = self.vm.qmp('eject', device='drive0', force=True)
 | 
			
		||||
        self.assert_qmp(result, 'return', {})
 | 
			
		||||
 | 
			
		||||
@ -111,9 +126,12 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
 | 
			
		||||
            self.assert_qmp(result, 'return[0]/tray_open', True)
 | 
			
		||||
        self.assert_qmp_absent(result, 'return[0]/inserted')
 | 
			
		||||
 | 
			
		||||
        if self.device_name is not None:
 | 
			
		||||
            result = self.vm.qmp('blockdev-change-medium', id=self.device_name,
 | 
			
		||||
                                 filename=new_img, format=iotests.imgfmt)
 | 
			
		||||
        else:
 | 
			
		||||
            result = self.vm.qmp('blockdev-change-medium', device='drive0',
 | 
			
		||||
                                                       filename=new_img,
 | 
			
		||||
                                                       format=iotests.imgfmt)
 | 
			
		||||
                                 filename=new_img, format=iotests.imgfmt)
 | 
			
		||||
        self.assert_qmp(result, 'return', {})
 | 
			
		||||
 | 
			
		||||
        self.wait_for_close()
 | 
			
		||||
@ -124,7 +142,12 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
 | 
			
		||||
        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
 | 
			
		||||
 | 
			
		||||
    def test_tray_open_close(self):
 | 
			
		||||
        result = self.vm.qmp('blockdev-open-tray', device='drive0', force=True)
 | 
			
		||||
        if self.device_name is not None:
 | 
			
		||||
            result = self.vm.qmp('blockdev-open-tray',
 | 
			
		||||
                                 id=self.device_name, force=True)
 | 
			
		||||
        else:
 | 
			
		||||
            result = self.vm.qmp('blockdev-open-tray',
 | 
			
		||||
                                 device='drive0', force=True)
 | 
			
		||||
        self.assert_qmp(result, 'return', {})
 | 
			
		||||
 | 
			
		||||
        self.wait_for_open()
 | 
			
		||||
@ -137,6 +160,9 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
 | 
			
		||||
        else:
 | 
			
		||||
            self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
 | 
			
		||||
 | 
			
		||||
        if self.device_name is not None:
 | 
			
		||||
            result = self.vm.qmp('blockdev-close-tray', id=self.device_name)
 | 
			
		||||
        else:
 | 
			
		||||
            result = self.vm.qmp('blockdev-close-tray', device='drive0')
 | 
			
		||||
        self.assert_qmp(result, 'return', {})
 | 
			
		||||
 | 
			
		||||
@ -162,6 +188,9 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
 | 
			
		||||
            self.assert_qmp(result, 'return[0]/tray_open', True)
 | 
			
		||||
        self.assert_qmp_absent(result, 'return[0]/inserted')
 | 
			
		||||
 | 
			
		||||
        if self.device_name is not None:
 | 
			
		||||
            result = self.vm.qmp('blockdev-close-tray', id=self.device_name)
 | 
			
		||||
        else:
 | 
			
		||||
            result = self.vm.qmp('blockdev-close-tray', device='drive0')
 | 
			
		||||
        self.assert_qmp(result, 'return', {})
 | 
			
		||||
 | 
			
		||||
@ -206,7 +235,12 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
 | 
			
		||||
                                               'driver': 'file'}})
 | 
			
		||||
        self.assert_qmp(result, 'return', {})
 | 
			
		||||
 | 
			
		||||
        result = self.vm.qmp('blockdev-open-tray', device='drive0', force=True)
 | 
			
		||||
        if self.device_name is not None:
 | 
			
		||||
            result = self.vm.qmp('blockdev-open-tray',
 | 
			
		||||
                                 id=self.device_name, force=True)
 | 
			
		||||
        else:
 | 
			
		||||
            result = self.vm.qmp('blockdev-open-tray',
 | 
			
		||||
                                 device='drive0', force=True)
 | 
			
		||||
        self.assert_qmp(result, 'return', {})
 | 
			
		||||
 | 
			
		||||
        self.wait_for_open()
 | 
			
		||||
@ -219,6 +253,10 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
 | 
			
		||||
        else:
 | 
			
		||||
            self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
 | 
			
		||||
 | 
			
		||||
        if self.device_name is not None:
 | 
			
		||||
            result = self.vm.qmp('x-blockdev-remove-medium',
 | 
			
		||||
                                 id=self.device_name)
 | 
			
		||||
        else:
 | 
			
		||||
            result = self.vm.qmp('x-blockdev-remove-medium', device='drive0')
 | 
			
		||||
        self.assert_qmp(result, 'return', {})
 | 
			
		||||
 | 
			
		||||
@ -227,8 +265,12 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
 | 
			
		||||
            self.assert_qmp(result, 'return[0]/tray_open', True)
 | 
			
		||||
        self.assert_qmp_absent(result, 'return[0]/inserted')
 | 
			
		||||
 | 
			
		||||
        result = self.vm.qmp('x-blockdev-insert-medium', device='drive0',
 | 
			
		||||
                                                       node_name='new')
 | 
			
		||||
        if self.device_name is not None:
 | 
			
		||||
            result = self.vm.qmp('x-blockdev-insert-medium',
 | 
			
		||||
                                 id=self.device_name, node_name='new')
 | 
			
		||||
        else:
 | 
			
		||||
            result = self.vm.qmp('x-blockdev-insert-medium',
 | 
			
		||||
                                 device='drive0', node_name='new')
 | 
			
		||||
        self.assert_qmp(result, 'return', {})
 | 
			
		||||
 | 
			
		||||
        result = self.vm.qmp('query-block')
 | 
			
		||||
@ -236,6 +278,9 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
 | 
			
		||||
            self.assert_qmp(result, 'return[0]/tray_open', True)
 | 
			
		||||
        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
 | 
			
		||||
 | 
			
		||||
        if self.device_name is not None:
 | 
			
		||||
            result = self.vm.qmp('blockdev-close-tray', id=self.device_name)
 | 
			
		||||
        else:
 | 
			
		||||
            result = self.vm.qmp('blockdev-close-tray', device='drive0')
 | 
			
		||||
        self.assert_qmp(result, 'return', {})
 | 
			
		||||
 | 
			
		||||
@ -280,7 +325,13 @@ class TestInitiallyFilled(GeneralChangeTestsBaseClass):
 | 
			
		||||
    def setUp(self, media, interface):
 | 
			
		||||
        qemu_img('create', '-f', iotests.imgfmt, old_img, '1440k')
 | 
			
		||||
        qemu_img('create', '-f', iotests.imgfmt, new_img, '1440k')
 | 
			
		||||
        self.vm = iotests.VM().add_drive(old_img, 'media=%s' % media, interface)
 | 
			
		||||
        self.vm = iotests.VM()
 | 
			
		||||
        if interface == 'ide':
 | 
			
		||||
            self.device_name = 'qdev0'
 | 
			
		||||
            self.vm.add_drive(old_img, 'media=%s' % media, 'none')
 | 
			
		||||
            self.vm.add_device('ide-cd,drive=drive0,id=%s' % self.device_name)
 | 
			
		||||
        else:
 | 
			
		||||
            self.vm.add_drive(old_img, 'media=%s' % media, interface)
 | 
			
		||||
        self.vm.launch()
 | 
			
		||||
 | 
			
		||||
    def tearDown(self):
 | 
			
		||||
@ -597,13 +648,9 @@ class TestBlockJobsAfterCycle(ChangeBaseClass):
 | 
			
		||||
        qemu_img('create', '-f', iotests.imgfmt, old_img, '1M')
 | 
			
		||||
 | 
			
		||||
        self.vm = iotests.VM()
 | 
			
		||||
        self.vm.add_drive_raw("id=drive0,driver=null-co,if=none")
 | 
			
		||||
        self.vm.launch()
 | 
			
		||||
 | 
			
		||||
        result = self.vm.qmp('blockdev-add',
 | 
			
		||||
                             options={'id': 'drive0',
 | 
			
		||||
                                      'driver': 'null-co'})
 | 
			
		||||
        self.assert_qmp(result, 'return', {})
 | 
			
		||||
 | 
			
		||||
        result = self.vm.qmp('query-block')
 | 
			
		||||
        self.assert_qmp(result, 'return[0]/inserted/image/format', 'null-co')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -49,8 +49,8 @@ def transaction_bitmap_clear(node, name, **kwargs):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def transaction_drive_backup(device, target, **kwargs):
 | 
			
		||||
    return transaction_action('drive-backup', device=device, target=target,
 | 
			
		||||
                              **kwargs)
 | 
			
		||||
    return transaction_action('drive-backup', job_id=device, device=device,
 | 
			
		||||
                              target=target, **kwargs)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Bitmap:
 | 
			
		||||
@ -177,7 +177,8 @@ class TestIncrementalBackupBase(iotests.QMPTestCase):
 | 
			
		||||
    def create_anchor_backup(self, drive=None):
 | 
			
		||||
        if drive is None:
 | 
			
		||||
            drive = self.drives[-1]
 | 
			
		||||
        res = self.do_qmp_backup(device=drive['id'], sync='full',
 | 
			
		||||
        res = self.do_qmp_backup(job_id=drive['id'],
 | 
			
		||||
                                 device=drive['id'], sync='full',
 | 
			
		||||
                                 format=drive['fmt'], target=drive['backup'])
 | 
			
		||||
        self.assertTrue(res)
 | 
			
		||||
        self.files.append(drive['backup'])
 | 
			
		||||
@ -188,7 +189,8 @@ class TestIncrementalBackupBase(iotests.QMPTestCase):
 | 
			
		||||
        if bitmap is None:
 | 
			
		||||
            bitmap = self.bitmaps[-1]
 | 
			
		||||
        _, reference = bitmap.last_target()
 | 
			
		||||
        res = self.do_qmp_backup(device=bitmap.drive['id'], sync='full',
 | 
			
		||||
        res = self.do_qmp_backup(job_id=bitmap.drive['id'],
 | 
			
		||||
                                 device=bitmap.drive['id'], sync='full',
 | 
			
		||||
                                 format=bitmap.drive['fmt'], target=reference)
 | 
			
		||||
        self.assertTrue(res)
 | 
			
		||||
 | 
			
		||||
@ -221,7 +223,8 @@ class TestIncrementalBackupBase(iotests.QMPTestCase):
 | 
			
		||||
            parent, _ = bitmap.last_target()
 | 
			
		||||
 | 
			
		||||
        target = self.prepare_backup(bitmap, parent)
 | 
			
		||||
        res = self.do_qmp_backup(device=bitmap.drive['id'],
 | 
			
		||||
        res = self.do_qmp_backup(job_id=bitmap.drive['id'],
 | 
			
		||||
                                 device=bitmap.drive['id'],
 | 
			
		||||
                                 sync='incremental', bitmap=bitmap.name,
 | 
			
		||||
                                 format=bitmap.drive['fmt'], target=target,
 | 
			
		||||
                                 mode='existing')
 | 
			
		||||
@ -414,7 +417,7 @@ class TestIncrementalBackup(TestIncrementalBackupBase):
 | 
			
		||||
 | 
			
		||||
        # Create a blkdebug interface to this img as 'drive1'
 | 
			
		||||
        result = self.vm.qmp('blockdev-add', options={
 | 
			
		||||
            'id': drive1['id'],
 | 
			
		||||
            'node-name': drive1['id'],
 | 
			
		||||
            'driver': drive1['fmt'],
 | 
			
		||||
            'file': {
 | 
			
		||||
                'driver': 'blkdebug',
 | 
			
		||||
@ -558,7 +561,7 @@ class TestIncrementalBackupBlkdebug(TestIncrementalBackupBase):
 | 
			
		||||
 | 
			
		||||
        drive0 = self.drives[0]
 | 
			
		||||
        result = self.vm.qmp('blockdev-add', options={
 | 
			
		||||
            'id': drive0['id'],
 | 
			
		||||
            'node-name': drive0['id'],
 | 
			
		||||
            'driver': drive0['fmt'],
 | 
			
		||||
            'file': {
 | 
			
		||||
                'driver': 'blkdebug',
 | 
			
		||||
 | 
			
		||||
@ -31,6 +31,7 @@ class TestBlockdevDel(iotests.QMPTestCase):
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        iotests.qemu_img('create', '-f', iotests.imgfmt, base_img, '1M')
 | 
			
		||||
        self.vm = iotests.VM()
 | 
			
		||||
        self.vm.add_device("virtio-scsi-pci,id=virtio-scsi")
 | 
			
		||||
        self.vm.launch()
 | 
			
		||||
 | 
			
		||||
    def tearDown(self):
 | 
			
		||||
@ -39,18 +40,6 @@ class TestBlockdevDel(iotests.QMPTestCase):
 | 
			
		||||
        if os.path.isfile(new_img):
 | 
			
		||||
            os.remove(new_img)
 | 
			
		||||
 | 
			
		||||
    # Check whether a BlockBackend exists
 | 
			
		||||
    def checkBlockBackend(self, backend, node, must_exist = True):
 | 
			
		||||
        result = self.vm.qmp('query-block')
 | 
			
		||||
        backends = filter(lambda x: x['device'] == backend, result['return'])
 | 
			
		||||
        self.assertLessEqual(len(backends), 1)
 | 
			
		||||
        self.assertEqual(must_exist, len(backends) == 1)
 | 
			
		||||
        if must_exist:
 | 
			
		||||
            if node:
 | 
			
		||||
                self.assertEqual(backends[0]['inserted']['node-name'], node)
 | 
			
		||||
            else:
 | 
			
		||||
                self.assertFalse(backends[0].has_key('inserted'))
 | 
			
		||||
 | 
			
		||||
    # Check whether a BlockDriverState exists
 | 
			
		||||
    def checkBlockDriverState(self, node, must_exist = True):
 | 
			
		||||
        result = self.vm.qmp('query-named-block-nodes')
 | 
			
		||||
@ -58,24 +47,6 @@ class TestBlockdevDel(iotests.QMPTestCase):
 | 
			
		||||
        self.assertLessEqual(len(nodes), 1)
 | 
			
		||||
        self.assertEqual(must_exist, len(nodes) == 1)
 | 
			
		||||
 | 
			
		||||
    # Add a new BlockBackend (with its attached BlockDriverState)
 | 
			
		||||
    def addBlockBackend(self, backend, node):
 | 
			
		||||
        file_node = '%s_file' % node
 | 
			
		||||
        self.checkBlockBackend(backend, node, False)
 | 
			
		||||
        self.checkBlockDriverState(node, False)
 | 
			
		||||
        self.checkBlockDriverState(file_node, False)
 | 
			
		||||
        opts = {'driver': iotests.imgfmt,
 | 
			
		||||
                'id': backend,
 | 
			
		||||
                'node-name': node,
 | 
			
		||||
                'file': {'driver': 'file',
 | 
			
		||||
                         'node-name': file_node,
 | 
			
		||||
                         'filename': base_img}}
 | 
			
		||||
        result = self.vm.qmp('blockdev-add', conv_keys = False, options = opts)
 | 
			
		||||
        self.assert_qmp(result, 'return', {})
 | 
			
		||||
        self.checkBlockBackend(backend, node)
 | 
			
		||||
        self.checkBlockDriverState(node)
 | 
			
		||||
        self.checkBlockDriverState(file_node)
 | 
			
		||||
 | 
			
		||||
    # Add a BlockDriverState without a BlockBackend
 | 
			
		||||
    def addBlockDriverState(self, node):
 | 
			
		||||
        file_node = '%s_file' % node
 | 
			
		||||
@ -105,23 +76,6 @@ class TestBlockdevDel(iotests.QMPTestCase):
 | 
			
		||||
        self.assert_qmp(result, 'return', {})
 | 
			
		||||
        self.checkBlockDriverState(node)
 | 
			
		||||
 | 
			
		||||
    # Delete a BlockBackend
 | 
			
		||||
    def delBlockBackend(self, backend, node, expect_error = False,
 | 
			
		||||
                        destroys_media = True):
 | 
			
		||||
        self.checkBlockBackend(backend, node)
 | 
			
		||||
        if node:
 | 
			
		||||
            self.checkBlockDriverState(node)
 | 
			
		||||
        result = self.vm.qmp('x-blockdev-del', id = backend)
 | 
			
		||||
        if expect_error:
 | 
			
		||||
            self.assert_qmp(result, 'error/class', 'GenericError')
 | 
			
		||||
            if node:
 | 
			
		||||
                self.checkBlockDriverState(node)
 | 
			
		||||
        else:
 | 
			
		||||
            self.assert_qmp(result, 'return', {})
 | 
			
		||||
            if node:
 | 
			
		||||
                self.checkBlockDriverState(node, not destroys_media)
 | 
			
		||||
        self.checkBlockBackend(backend, node, must_exist = expect_error)
 | 
			
		||||
 | 
			
		||||
    # Delete a BlockDriverState
 | 
			
		||||
    def delBlockDriverState(self, node, expect_error = False):
 | 
			
		||||
        self.checkBlockDriverState(node)
 | 
			
		||||
@ -133,19 +87,20 @@ class TestBlockdevDel(iotests.QMPTestCase):
 | 
			
		||||
        self.checkBlockDriverState(node, expect_error)
 | 
			
		||||
 | 
			
		||||
    # Add a device model
 | 
			
		||||
    def addDeviceModel(self, device, backend):
 | 
			
		||||
    def addDeviceModel(self, device, backend, driver = 'virtio-blk-pci'):
 | 
			
		||||
        result = self.vm.qmp('device_add', id = device,
 | 
			
		||||
                             driver = 'virtio-blk-pci', drive = backend)
 | 
			
		||||
                             driver = driver, drive = backend)
 | 
			
		||||
        self.assert_qmp(result, 'return', {})
 | 
			
		||||
 | 
			
		||||
    # Delete a device model
 | 
			
		||||
    def delDeviceModel(self, device):
 | 
			
		||||
    def delDeviceModel(self, device, is_virtio_blk = True):
 | 
			
		||||
        result = self.vm.qmp('device_del', id = device)
 | 
			
		||||
        self.assert_qmp(result, 'return', {})
 | 
			
		||||
 | 
			
		||||
        result = self.vm.qmp('system_reset')
 | 
			
		||||
        self.assert_qmp(result, 'return', {})
 | 
			
		||||
 | 
			
		||||
        if is_virtio_blk:
 | 
			
		||||
            device_path = '/machine/peripheral/%s/virtio-backend' % device
 | 
			
		||||
            event = self.vm.event_wait(name="DEVICE_DELETED",
 | 
			
		||||
                                       match={'data': {'path': device_path}})
 | 
			
		||||
@ -156,28 +111,23 @@ class TestBlockdevDel(iotests.QMPTestCase):
 | 
			
		||||
        self.assertNotEqual(event, None)
 | 
			
		||||
 | 
			
		||||
    # Remove a BlockDriverState
 | 
			
		||||
    def ejectDrive(self, backend, node, expect_error = False,
 | 
			
		||||
    def ejectDrive(self, device, node, expect_error = False,
 | 
			
		||||
                   destroys_media = True):
 | 
			
		||||
        self.checkBlockBackend(backend, node)
 | 
			
		||||
        self.checkBlockDriverState(node)
 | 
			
		||||
        result = self.vm.qmp('eject', device = backend)
 | 
			
		||||
        result = self.vm.qmp('eject', id = device)
 | 
			
		||||
        if expect_error:
 | 
			
		||||
            self.assert_qmp(result, 'error/class', 'GenericError')
 | 
			
		||||
            self.checkBlockDriverState(node)
 | 
			
		||||
            self.checkBlockBackend(backend, node)
 | 
			
		||||
        else:
 | 
			
		||||
            self.assert_qmp(result, 'return', {})
 | 
			
		||||
            self.checkBlockDriverState(node, not destroys_media)
 | 
			
		||||
            self.checkBlockBackend(backend, None)
 | 
			
		||||
 | 
			
		||||
    # Insert a BlockDriverState
 | 
			
		||||
    def insertDrive(self, backend, node):
 | 
			
		||||
        self.checkBlockBackend(backend, None)
 | 
			
		||||
    def insertDrive(self, device, node):
 | 
			
		||||
        self.checkBlockDriverState(node)
 | 
			
		||||
        result = self.vm.qmp('x-blockdev-insert-medium',
 | 
			
		||||
                             device = backend, node_name = node)
 | 
			
		||||
                             id = device, node_name = node)
 | 
			
		||||
        self.assert_qmp(result, 'return', {})
 | 
			
		||||
        self.checkBlockBackend(backend, node)
 | 
			
		||||
        self.checkBlockDriverState(node)
 | 
			
		||||
 | 
			
		||||
    # Create a snapshot using 'blockdev-snapshot-sync'
 | 
			
		||||
@ -204,26 +154,23 @@ class TestBlockdevDel(iotests.QMPTestCase):
 | 
			
		||||
        self.checkBlockDriverState(overlay)
 | 
			
		||||
 | 
			
		||||
    # Create a mirror
 | 
			
		||||
    def createMirror(self, backend, node, new_node):
 | 
			
		||||
        self.checkBlockBackend(backend, node)
 | 
			
		||||
    def createMirror(self, node, new_node):
 | 
			
		||||
        self.checkBlockDriverState(new_node, False)
 | 
			
		||||
        opts = {'device': backend,
 | 
			
		||||
        opts = {'device': node,
 | 
			
		||||
                'job-id': node,
 | 
			
		||||
                'target': new_img,
 | 
			
		||||
                'node-name': new_node,
 | 
			
		||||
                'sync': 'top',
 | 
			
		||||
                'format': iotests.imgfmt}
 | 
			
		||||
        result = self.vm.qmp('drive-mirror', conv_keys=False, **opts)
 | 
			
		||||
        self.assert_qmp(result, 'return', {})
 | 
			
		||||
        self.checkBlockBackend(backend, node)
 | 
			
		||||
        self.checkBlockDriverState(new_node)
 | 
			
		||||
 | 
			
		||||
    # Complete an existing block job
 | 
			
		||||
    def completeBlockJob(self, backend, node_before, node_after):
 | 
			
		||||
        self.checkBlockBackend(backend, node_before)
 | 
			
		||||
        result = self.vm.qmp('block-job-complete', device=backend)
 | 
			
		||||
    def completeBlockJob(self, id, node_before, node_after):
 | 
			
		||||
        result = self.vm.qmp('block-job-complete', device=id)
 | 
			
		||||
        self.assert_qmp(result, 'return', {})
 | 
			
		||||
        self.wait_until_completed(backend)
 | 
			
		||||
        self.checkBlockBackend(backend, node_after)
 | 
			
		||||
        self.wait_until_completed(id)
 | 
			
		||||
 | 
			
		||||
    # Add a BlkDebug node
 | 
			
		||||
    # Note that the purpose of this is to test the x-blockdev-del
 | 
			
		||||
@ -297,89 +244,78 @@ class TestBlockdevDel(iotests.QMPTestCase):
 | 
			
		||||
    # The tests start here #
 | 
			
		||||
    ########################
 | 
			
		||||
 | 
			
		||||
    def testWrongParameters(self):
 | 
			
		||||
        self.addBlockBackend('drive0', 'node0')
 | 
			
		||||
        result = self.vm.qmp('x-blockdev-del')
 | 
			
		||||
        self.assert_qmp(result, 'error/class', 'GenericError')
 | 
			
		||||
        result = self.vm.qmp('x-blockdev-del', id='drive0', node_name='node0')
 | 
			
		||||
        self.assert_qmp(result, 'error/class', 'GenericError')
 | 
			
		||||
        self.delBlockBackend('drive0', 'node0')
 | 
			
		||||
 | 
			
		||||
    def testBlockBackend(self):
 | 
			
		||||
        self.addBlockBackend('drive0', 'node0')
 | 
			
		||||
        # You cannot delete a BDS that is attached to a backend
 | 
			
		||||
        self.delBlockDriverState('node0', expect_error = True)
 | 
			
		||||
        self.delBlockBackend('drive0', 'node0')
 | 
			
		||||
 | 
			
		||||
    def testBlockDriverState(self):
 | 
			
		||||
        self.addBlockDriverState('node0')
 | 
			
		||||
        # You cannot delete a file BDS directly
 | 
			
		||||
        self.delBlockDriverState('node0_file', expect_error = True)
 | 
			
		||||
        self.delBlockDriverState('node0')
 | 
			
		||||
 | 
			
		||||
    def testEject(self):
 | 
			
		||||
        self.addBlockBackend('drive0', 'node0')
 | 
			
		||||
        self.ejectDrive('drive0', 'node0')
 | 
			
		||||
        self.delBlockBackend('drive0', None)
 | 
			
		||||
 | 
			
		||||
    def testDeviceModel(self):
 | 
			
		||||
        self.addBlockBackend('drive0', 'node0')
 | 
			
		||||
        self.addDeviceModel('device0', 'drive0')
 | 
			
		||||
        self.ejectDrive('drive0', 'node0', expect_error = True)
 | 
			
		||||
        self.delBlockBackend('drive0', 'node0', expect_error = True)
 | 
			
		||||
        self.addBlockDriverState('node0')
 | 
			
		||||
        self.addDeviceModel('device0', 'node0')
 | 
			
		||||
        self.ejectDrive('device0', 'node0', expect_error = True)
 | 
			
		||||
        self.delBlockDriverState('node0', expect_error = True)
 | 
			
		||||
        self.delDeviceModel('device0')
 | 
			
		||||
        self.delBlockBackend('drive0', 'node0')
 | 
			
		||||
        self.delBlockDriverState('node0')
 | 
			
		||||
 | 
			
		||||
    def testAttachMedia(self):
 | 
			
		||||
        # This creates a BlockBackend and removes its media
 | 
			
		||||
        self.addBlockBackend('drive0', 'node0')
 | 
			
		||||
        self.ejectDrive('drive0', 'node0')
 | 
			
		||||
        # This creates a new BlockDriverState and inserts it into the backend
 | 
			
		||||
        self.addBlockDriverState('node0')
 | 
			
		||||
        self.addDeviceModel('device0', 'node0', 'scsi-cd')
 | 
			
		||||
        self.ejectDrive('device0', 'node0', destroys_media = False)
 | 
			
		||||
        self.delBlockDriverState('node0')
 | 
			
		||||
 | 
			
		||||
        # This creates a new BlockDriverState and inserts it into the device
 | 
			
		||||
        self.addBlockDriverState('node1')
 | 
			
		||||
        self.insertDrive('drive0', 'node1')
 | 
			
		||||
        # The backend can't be removed: the new BDS has an extra reference
 | 
			
		||||
        self.delBlockBackend('drive0', 'node1', expect_error = True)
 | 
			
		||||
        self.insertDrive('device0', 'node1')
 | 
			
		||||
        # The node can't be removed: the new device has an extra reference
 | 
			
		||||
        self.delBlockDriverState('node1', expect_error = True)
 | 
			
		||||
        # The BDS still exists after being ejected, but now it can be removed
 | 
			
		||||
        self.ejectDrive('drive0', 'node1', destroys_media = False)
 | 
			
		||||
        self.ejectDrive('device0', 'node1', destroys_media = False)
 | 
			
		||||
        self.delBlockDriverState('node1')
 | 
			
		||||
        self.delBlockBackend('drive0', None)
 | 
			
		||||
        self.delDeviceModel('device0', False)
 | 
			
		||||
 | 
			
		||||
    def testSnapshotSync(self):
 | 
			
		||||
        self.addBlockBackend('drive0', 'node0')
 | 
			
		||||
        self.addBlockDriverState('node0')
 | 
			
		||||
        self.addDeviceModel('device0', 'node0')
 | 
			
		||||
        self.createSnapshotSync('node0', 'overlay0')
 | 
			
		||||
        # This fails because node0 is now being used as a backing image
 | 
			
		||||
        self.delBlockDriverState('node0', expect_error = True)
 | 
			
		||||
        # This succeeds because overlay0 only has the backend reference
 | 
			
		||||
        self.delBlockBackend('drive0', 'overlay0')
 | 
			
		||||
        self.checkBlockDriverState('node0', False)
 | 
			
		||||
        self.delBlockDriverState('overlay0', expect_error = True)
 | 
			
		||||
        # This succeeds because device0 only has the backend reference
 | 
			
		||||
        self.delDeviceModel('device0')
 | 
			
		||||
        # FIXME Would still be there if blockdev-snapshot-sync took a ref
 | 
			
		||||
        self.checkBlockDriverState('overlay0', False)
 | 
			
		||||
        self.delBlockDriverState('node0')
 | 
			
		||||
 | 
			
		||||
    def testSnapshot(self):
 | 
			
		||||
        self.addBlockBackend('drive0', 'node0')
 | 
			
		||||
        self.addBlockDriverState('node0')
 | 
			
		||||
        self.addDeviceModel('device0', 'node0', 'scsi-cd')
 | 
			
		||||
        self.addBlockDriverStateOverlay('overlay0')
 | 
			
		||||
        self.createSnapshot('node0', 'overlay0')
 | 
			
		||||
        self.delBlockBackend('drive0', 'overlay0', expect_error = True)
 | 
			
		||||
        self.delBlockDriverState('node0', expect_error = True)
 | 
			
		||||
        self.delBlockDriverState('overlay0', expect_error = True)
 | 
			
		||||
        self.ejectDrive('drive0', 'overlay0', destroys_media = False)
 | 
			
		||||
        self.delBlockBackend('drive0', None)
 | 
			
		||||
        self.ejectDrive('device0', 'overlay0', destroys_media = False)
 | 
			
		||||
        self.delBlockDriverState('node0', expect_error = True)
 | 
			
		||||
        self.delBlockDriverState('overlay0')
 | 
			
		||||
        self.checkBlockDriverState('node0', False)
 | 
			
		||||
        self.delBlockDriverState('node0')
 | 
			
		||||
 | 
			
		||||
    def testMirror(self):
 | 
			
		||||
        self.addBlockBackend('drive0', 'node0')
 | 
			
		||||
        self.createMirror('drive0', 'node0', 'mirror0')
 | 
			
		||||
        self.addBlockDriverState('node0')
 | 
			
		||||
        self.addDeviceModel('device0', 'node0', 'scsi-cd')
 | 
			
		||||
        self.createMirror('node0', 'mirror0')
 | 
			
		||||
        # The block job prevents removing the device
 | 
			
		||||
        self.delBlockBackend('drive0', 'node0', expect_error = True)
 | 
			
		||||
        self.delBlockDriverState('node0', expect_error = True)
 | 
			
		||||
        self.delBlockDriverState('mirror0', expect_error = True)
 | 
			
		||||
        self.wait_ready('drive0')
 | 
			
		||||
        self.completeBlockJob('drive0', 'node0', 'mirror0')
 | 
			
		||||
        self.wait_ready('node0')
 | 
			
		||||
        self.completeBlockJob('node0', 'node0', 'mirror0')
 | 
			
		||||
        self.assert_no_active_block_jobs()
 | 
			
		||||
        self.checkBlockDriverState('node0', False)
 | 
			
		||||
        # This succeeds because the backend now points to mirror0
 | 
			
		||||
        self.delBlockBackend('drive0', 'mirror0')
 | 
			
		||||
        # This succeeds because the device now points to mirror0
 | 
			
		||||
        self.delBlockDriverState('node0')
 | 
			
		||||
        self.delBlockDriverState('mirror0', expect_error = True)
 | 
			
		||||
        self.delDeviceModel('device0', False)
 | 
			
		||||
        # FIXME mirror0 disappears, drive-mirror doesn't take a reference
 | 
			
		||||
        #self.delBlockDriverState('mirror0')
 | 
			
		||||
 | 
			
		||||
    def testBlkDebug(self):
 | 
			
		||||
        self.addBlkDebug('debug0', 'node0')
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
............
 | 
			
		||||
.........
 | 
			
		||||
----------------------------------------------------------------------
 | 
			
		||||
Ran 12 tests
 | 
			
		||||
Ran 9 tests
 | 
			
		||||
 | 
			
		||||
OK
 | 
			
		||||
 | 
			
		||||
@ -51,7 +51,7 @@ test_blockjob()
 | 
			
		||||
        "{'execute': 'blockdev-add',
 | 
			
		||||
          'arguments': {
 | 
			
		||||
              'options': {
 | 
			
		||||
                  'id': 'drv0',
 | 
			
		||||
                  'node-name': 'drv0',
 | 
			
		||||
                  'driver': '$IMGFMT',
 | 
			
		||||
                  'file': {
 | 
			
		||||
                      'driver': 'file',
 | 
			
		||||
@ -66,18 +66,18 @@ test_blockjob()
 | 
			
		||||
 | 
			
		||||
    # We want this to return an error because the block job is still running
 | 
			
		||||
    _send_qemu_cmd $QEMU_HANDLE \
 | 
			
		||||
        "{'execute': 'x-blockdev-remove-medium',
 | 
			
		||||
          'arguments': {'device': 'drv0'}}" \
 | 
			
		||||
        "{'execute': 'x-blockdev-del',
 | 
			
		||||
          'arguments': {'node-name': 'drv0'}}" \
 | 
			
		||||
        'error'
 | 
			
		||||
 | 
			
		||||
    _send_qemu_cmd $QEMU_HANDLE \
 | 
			
		||||
        "{'execute': 'block-job-cancel',
 | 
			
		||||
          'arguments': {'device': 'drv0'}}" \
 | 
			
		||||
          'arguments': {'device': 'job0'}}" \
 | 
			
		||||
        "$3"
 | 
			
		||||
 | 
			
		||||
    _send_qemu_cmd $QEMU_HANDLE \
 | 
			
		||||
        "{'execute': 'x-blockdev-del',
 | 
			
		||||
          'arguments': {'id': 'drv0'}}" \
 | 
			
		||||
          'arguments': {'node-name': 'drv0'}}" \
 | 
			
		||||
        'return'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -101,7 +101,8 @@ echo
 | 
			
		||||
 | 
			
		||||
test_blockjob \
 | 
			
		||||
    "{'execute': 'drive-backup',
 | 
			
		||||
      'arguments': {'device': 'drv0',
 | 
			
		||||
      'arguments': {'job-id': 'job0',
 | 
			
		||||
                    'device': 'drv0',
 | 
			
		||||
                    'target': '$TEST_DIR/o.$IMGFMT',
 | 
			
		||||
                    'format': '$IMGFMT',
 | 
			
		||||
                    'sync': 'none'}}" \
 | 
			
		||||
@ -117,7 +118,8 @@ echo
 | 
			
		||||
 | 
			
		||||
test_blockjob \
 | 
			
		||||
    "{'execute': 'drive-mirror',
 | 
			
		||||
      'arguments': {'device': 'drv0',
 | 
			
		||||
      'arguments': {'job-id': 'job0',
 | 
			
		||||
                    'device': 'drv0',
 | 
			
		||||
                    'target': '$TEST_DIR/o.$IMGFMT',
 | 
			
		||||
                    'format': '$IMGFMT',
 | 
			
		||||
                    'sync': 'none'}}" \
 | 
			
		||||
@ -134,7 +136,7 @@ echo
 | 
			
		||||
 | 
			
		||||
test_blockjob \
 | 
			
		||||
    "{'execute': 'block-commit',
 | 
			
		||||
      'arguments': {'device': 'drv0'}}" \
 | 
			
		||||
      'arguments': {'job-id': 'job0', 'device': 'drv0'}}" \
 | 
			
		||||
    'BLOCK_JOB_READY' \
 | 
			
		||||
    'BLOCK_JOB_COMPLETED'
 | 
			
		||||
 | 
			
		||||
@ -150,7 +152,8 @@ $QEMU_IO -c 'write 0 1M' "$TEST_DIR/m.$IMGFMT" | _filter_qemu_io
 | 
			
		||||
 | 
			
		||||
test_blockjob \
 | 
			
		||||
    "{'execute': 'block-commit',
 | 
			
		||||
      'arguments': {'device': 'drv0',
 | 
			
		||||
      'arguments': {'job-id': 'job0',
 | 
			
		||||
                    'device': 'drv0',
 | 
			
		||||
                    'top':    '$TEST_DIR/m.$IMGFMT',
 | 
			
		||||
                    'speed':  1}}" \
 | 
			
		||||
    'return' \
 | 
			
		||||
@ -172,7 +175,8 @@ $QEMU_IO -c 'write 0 1M' "$TEST_DIR/b.$IMGFMT" | _filter_qemu_io
 | 
			
		||||
 | 
			
		||||
test_blockjob \
 | 
			
		||||
    "{'execute': 'block-stream',
 | 
			
		||||
      'arguments': {'device': 'drv0',
 | 
			
		||||
      'arguments': {'job-id': 'job0',
 | 
			
		||||
                    'device': 'drv0',
 | 
			
		||||
                    'speed': 1}}" \
 | 
			
		||||
    'return' \
 | 
			
		||||
    'BLOCK_JOB_CANCELLED'
 | 
			
		||||
 | 
			
		||||
@ -9,30 +9,30 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/m.
 | 
			
		||||
{"return": {}}
 | 
			
		||||
Formatting 'TEST_DIR/o.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT backing_fmt=IMGFMT
 | 
			
		||||
{"return": {}}
 | 
			
		||||
{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: block device is in use by block job: backup"}}
 | 
			
		||||
{"error": {"class": "GenericError", "desc": "Node drv0 is in use"}}
 | 
			
		||||
{"return": {}}
 | 
			
		||||
{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "drv0", "len": 1048576, "offset": 0, "speed": 0, "type": "backup"}}
 | 
			
		||||
{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "job0", "len": 1048576, "offset": 0, "speed": 0, "type": "backup"}}
 | 
			
		||||
{"return": {}}
 | 
			
		||||
 | 
			
		||||
=== Testing drive-mirror ===
 | 
			
		||||
 | 
			
		||||
{"return": {}}
 | 
			
		||||
Formatting 'TEST_DIR/o.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT backing_fmt=IMGFMT
 | 
			
		||||
{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "drv0", "len": 0, "offset": 0, "speed": 0, "type": "mirror"}}
 | 
			
		||||
{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "mirror"}}
 | 
			
		||||
{"return": {}}
 | 
			
		||||
{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: block device is in use by block job: mirror"}}
 | 
			
		||||
{"error": {"class": "GenericError", "desc": "Node drv0 is in use"}}
 | 
			
		||||
{"return": {}}
 | 
			
		||||
{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "drv0", "len": 0, "offset": 0, "speed": 0, "type": "mirror"}}
 | 
			
		||||
{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "mirror"}}
 | 
			
		||||
{"return": {}}
 | 
			
		||||
 | 
			
		||||
=== Testing active block-commit ===
 | 
			
		||||
 | 
			
		||||
{"return": {}}
 | 
			
		||||
{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "drv0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}}
 | 
			
		||||
{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}}
 | 
			
		||||
{"return": {}}
 | 
			
		||||
{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: block device is in use by block job: commit"}}
 | 
			
		||||
{"error": {"class": "GenericError", "desc": "Node drv0 is in use"}}
 | 
			
		||||
{"return": {}}
 | 
			
		||||
{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "drv0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}}
 | 
			
		||||
{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}}
 | 
			
		||||
{"return": {}}
 | 
			
		||||
 | 
			
		||||
=== Testing non-active block-commit ===
 | 
			
		||||
@ -41,9 +41,9 @@ wrote 1048576/1048576 bytes at offset 0
 | 
			
		||||
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 | 
			
		||||
{"return": {}}
 | 
			
		||||
{"return": {}}
 | 
			
		||||
{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: block device is in use by block job: commit"}}
 | 
			
		||||
{"error": {"class": "GenericError", "desc": "Node drv0 is in use"}}
 | 
			
		||||
{"return": {}}
 | 
			
		||||
{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "drv0", "len": 1048576, "offset": 524288, "speed": 1, "type": "commit"}}
 | 
			
		||||
{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "job0", "len": 1048576, "offset": 524288, "speed": 1, "type": "commit"}}
 | 
			
		||||
{"return": {}}
 | 
			
		||||
 | 
			
		||||
=== Testing block-stream ===
 | 
			
		||||
@ -52,8 +52,8 @@ wrote 1048576/1048576 bytes at offset 0
 | 
			
		||||
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 | 
			
		||||
{"return": {}}
 | 
			
		||||
{"return": {}}
 | 
			
		||||
{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: block device is in use by block job: stream"}}
 | 
			
		||||
{"error": {"class": "GenericError", "desc": "Node drv0 is in use"}}
 | 
			
		||||
{"return": {}}
 | 
			
		||||
{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "drv0", "len": 1048576, "offset": 524288, "speed": 1, "type": "stream"}}
 | 
			
		||||
{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "job0", "len": 1048576, "offset": 524288, "speed": 1, "type": "stream"}}
 | 
			
		||||
{"return": {}}
 | 
			
		||||
*** done
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										80
									
								
								tests/qemu-iotests/158
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										80
									
								
								tests/qemu-iotests/158
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,80 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
#
 | 
			
		||||
# Test encrypted read/write using backing files
 | 
			
		||||
#
 | 
			
		||||
# Copyright (C) 2015 Red Hat, Inc.
 | 
			
		||||
#
 | 
			
		||||
# This program is free software; you can redistribute it and/or modify
 | 
			
		||||
# it under the terms of the GNU General Public License as published by
 | 
			
		||||
# the Free Software Foundation; either version 2 of the License, or
 | 
			
		||||
# (at your option) any later version.
 | 
			
		||||
#
 | 
			
		||||
# This program is distributed in the hope that it will be useful,
 | 
			
		||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
# GNU General Public License for more details.
 | 
			
		||||
#
 | 
			
		||||
# You should have received a copy of the GNU General Public License
 | 
			
		||||
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
# creator
 | 
			
		||||
owner=berrange@redhat.com
 | 
			
		||||
 | 
			
		||||
seq=`basename $0`
 | 
			
		||||
echo "QA output created by $seq"
 | 
			
		||||
 | 
			
		||||
here=`pwd`
 | 
			
		||||
status=1	# failure is the default!
 | 
			
		||||
 | 
			
		||||
_cleanup()
 | 
			
		||||
{
 | 
			
		||||
	_cleanup_test_img
 | 
			
		||||
}
 | 
			
		||||
trap "_cleanup; exit \$status" 0 1 2 3 15
 | 
			
		||||
 | 
			
		||||
# get standard environment, filters and checks
 | 
			
		||||
. ./common.rc
 | 
			
		||||
. ./common.filter
 | 
			
		||||
 | 
			
		||||
_supported_fmt qcow2
 | 
			
		||||
_supported_proto generic
 | 
			
		||||
_supported_os Linux
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
size=128M
 | 
			
		||||
TEST_IMG_BASE=$TEST_IMG.base
 | 
			
		||||
 | 
			
		||||
TEST_IMG_SAVE=$TEST_IMG
 | 
			
		||||
TEST_IMG=$TEST_IMG_BASE
 | 
			
		||||
echo "== create base =="
 | 
			
		||||
IMGOPTS="encryption=on" _make_test_img $size
 | 
			
		||||
TEST_IMG=$TEST_IMG_SAVE
 | 
			
		||||
 | 
			
		||||
echo
 | 
			
		||||
echo "== writing whole image =="
 | 
			
		||||
echo "astrochicken" | $QEMU_IO -c "write -P 0xa 0 $size" "$TEST_IMG_BASE" | _filter_qemu_io | _filter_testdir
 | 
			
		||||
 | 
			
		||||
echo
 | 
			
		||||
echo "== verify pattern =="
 | 
			
		||||
echo "astrochicken" | $QEMU_IO -c "read -P 0xa 0 $size" "$TEST_IMG_BASE" | _filter_qemu_io | _filter_testdir
 | 
			
		||||
 | 
			
		||||
echo "== create overlay =="
 | 
			
		||||
IMGOPTS="encryption=on" _make_test_img -b "$TEST_IMG_BASE" $size
 | 
			
		||||
 | 
			
		||||
echo
 | 
			
		||||
echo "== writing part of a cluster =="
 | 
			
		||||
echo "astrochicken" | $QEMU_IO -c "write -P 0xe 0 1024" "$TEST_IMG" | _filter_qemu_io | _filter_testdir
 | 
			
		||||
 | 
			
		||||
echo
 | 
			
		||||
echo "== verify pattern =="
 | 
			
		||||
echo "astrochicken" | $QEMU_IO -c "read -P 0xe 0 1024" "$TEST_IMG" | _filter_qemu_io | _filter_testdir
 | 
			
		||||
echo
 | 
			
		||||
echo "== verify pattern =="
 | 
			
		||||
echo "astrochicken" | $QEMU_IO -c "read -P 0xa 1024 64512" "$TEST_IMG" | _filter_qemu_io | _filter_testdir
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# success, all done
 | 
			
		||||
echo "*** done"
 | 
			
		||||
rm -f $seq.full
 | 
			
		||||
status=0
 | 
			
		||||
							
								
								
									
										36
									
								
								tests/qemu-iotests/158.out
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								tests/qemu-iotests/158.out
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,36 @@
 | 
			
		||||
QA output created by 158
 | 
			
		||||
== create base ==
 | 
			
		||||
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 encryption=on
 | 
			
		||||
 | 
			
		||||
== writing whole image ==
 | 
			
		||||
Disk image 'TEST_DIR/t.qcow2.base' is encrypted.
 | 
			
		||||
password:
 | 
			
		||||
wrote 134217728/134217728 bytes at offset 0
 | 
			
		||||
128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 | 
			
		||||
 | 
			
		||||
== verify pattern ==
 | 
			
		||||
Disk image 'TEST_DIR/t.qcow2.base' is encrypted.
 | 
			
		||||
password:
 | 
			
		||||
read 134217728/134217728 bytes at offset 0
 | 
			
		||||
128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 | 
			
		||||
== create overlay ==
 | 
			
		||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base encryption=on
 | 
			
		||||
 | 
			
		||||
== writing part of a cluster ==
 | 
			
		||||
Disk image 'TEST_DIR/t.qcow2' is encrypted.
 | 
			
		||||
password:
 | 
			
		||||
wrote 1024/1024 bytes at offset 0
 | 
			
		||||
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 | 
			
		||||
 | 
			
		||||
== verify pattern ==
 | 
			
		||||
Disk image 'TEST_DIR/t.qcow2' is encrypted.
 | 
			
		||||
password:
 | 
			
		||||
read 1024/1024 bytes at offset 0
 | 
			
		||||
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 | 
			
		||||
 | 
			
		||||
== verify pattern ==
 | 
			
		||||
Disk image 'TEST_DIR/t.qcow2' is encrypted.
 | 
			
		||||
password:
 | 
			
		||||
read 64512/64512 bytes at offset 1024
 | 
			
		||||
63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 | 
			
		||||
*** done
 | 
			
		||||
@ -157,6 +157,7 @@
 | 
			
		||||
155 rw auto
 | 
			
		||||
156 rw auto quick
 | 
			
		||||
157 auto
 | 
			
		||||
158 rw auto quick
 | 
			
		||||
159 rw auto quick
 | 
			
		||||
160 rw auto quick
 | 
			
		||||
162 auto quick
 | 
			
		||||
 | 
			
		||||
@ -139,6 +139,11 @@ class VM(qtest.QEMUQtestMachine):
 | 
			
		||||
            self._debug = True
 | 
			
		||||
        self._num_drives = 0
 | 
			
		||||
 | 
			
		||||
    def add_device(self, opts):
 | 
			
		||||
        self._args.append('-device')
 | 
			
		||||
        self._args.append(opts)
 | 
			
		||||
        return self
 | 
			
		||||
 | 
			
		||||
    def add_drive_raw(self, opts):
 | 
			
		||||
        self._args.append('-drive')
 | 
			
		||||
        self._args.append(opts)
 | 
			
		||||
 | 
			
		||||
@ -1085,7 +1085,8 @@ QemuCocoaView *cocoaView;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Error *err = NULL;
 | 
			
		||||
    qmp_eject([drive cStringUsingEncoding: NSASCIIStringEncoding], false, false, &err);
 | 
			
		||||
    qmp_eject(true, [drive cStringUsingEncoding: NSASCIIStringEncoding],
 | 
			
		||||
              false, NULL, false, false, &err);
 | 
			
		||||
    handleAnyDeviceErrors(err);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1118,8 +1119,10 @@ QemuCocoaView *cocoaView;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Error *err = NULL;
 | 
			
		||||
        qmp_blockdev_change_medium([drive cStringUsingEncoding:
 | 
			
		||||
        qmp_blockdev_change_medium(true,
 | 
			
		||||
                                   [drive cStringUsingEncoding:
 | 
			
		||||
                                          NSASCIIStringEncoding],
 | 
			
		||||
                                   false, NULL,
 | 
			
		||||
                                   [file cStringUsingEncoding:
 | 
			
		||||
                                         NSASCIIStringEncoding],
 | 
			
		||||
                                   true, "raw",
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user