Block layer patches
-----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABAgAGBQJW+7EyAAoJEH8JsnLIjy/WzXEP/0grmb7+Pu36dT835sLQonzB eIK5WIIlVDQsvW/pRXefsRZiZxlXPPMBfk5VmegtcjKycIDxZ8thDa4wOQMzMuD2 nOGyG0lo7tLcx+/t2P6sICGYLpHgvfbObtnEQuSpi6wk2fg6Mg3K9Nhxqs8kyn0B ADs8Bx+FrzSK4rOVfgZP9AvLJUgz1/Keq4i8pdIIBuXP/ZQOQlaDQwF4IgxCXBJL ETS0q3JySiy6F1nt5HNzj8AcJFUEYVqUc+Og2/lry1/ZR3r/iaX63sRKqlb/kV/J g/Hh+075D0RQlp1I4Nl/0MvBBAYZ53JmURLc8nFFnFF8+vwiLxZR5LkwNkMfdyrI masbxmhEpHHuAqdOabSp4lSNIGYarKSc3n/HrC5lMGBNnxPuWfeM4t88JlYUSxKu Km9ofhdaTqDXDm5P2l4nrJcCMwOzVZaddaZYpj6vAxuRpCe91rbZZVvhtjHe6WE7 jspMLzcr5yUlOBa8+hPvWiIq29U+qnEdTAqq+3sYzvN2cvTNsveRgQMG7J+c1Bsn 2EWZz+m+ni2Uz+mDKX4oC6dqwcAjg+RB/b1I5Zsf6kEpoyq+mULdruevE6lFVHhX bMKKXOxJErxc40IrvXfAAYLJzbZyMBD3V5cbulOqIJiPAio94F8WEuye1gacEi7g rwpsqg/wi7jwc9pWsBcr =+NOQ -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging Block layer patches # gpg: Signature made Wed 30 Mar 2016 11:57:54 BST using RSA key ID C88F2FD6 # gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" * remotes/kevin/tags/for-upstream: (48 commits) iotests: Test qemu-img convert -S 0 behavior block/null-{co,aio}: Implement get_block_status() block/null-{co,aio}: Allow reading zeroes qemu-img: Fix preallocation with -S 0 for convert block: Remove bdrv_(set_)enable_write_cache() block: Remove BDRV_O_CACHE_WB block: Remove bdrv_parse_cache_flags() qemu-io: Use bdrv_parse_cache_mode() in reopen_f() block: Use bdrv_parse_cache_mode() in drive_init() raw: Support BDRV_REQ_FUA nbd: Support BDRV_REQ_FUA iscsi: Support BDRV_REQ_FUA block: Introduce bdrv_co_writev_flags() block/qapi: Use blk_enable_write_cache() block: Move enable_write_cache to BB level block: Handle flush error in bdrv_pwrite_sync() block: Always set writeback mode in blk_new_open() block: blockdev_init(): Call blk_set_enable_write_cache() explicitly xen_disk: Call blk_set_enable_write_cache() explicitly qemu-img: Call blk_set_enable_write_cache() explicitly ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
b9c27e7ae6
111
block.c
111
block.c
@ -289,6 +289,11 @@ static int bdrv_is_whitelisted(BlockDriver *drv, bool read_only)
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool bdrv_uses_whitelist(void)
|
||||
{
|
||||
return use_bdrv_whitelist;
|
||||
}
|
||||
|
||||
typedef struct CreateCo {
|
||||
BlockDriver *drv;
|
||||
char *filename;
|
||||
@ -640,21 +645,23 @@ int bdrv_parse_discard_flags(const char *mode, int *flags)
|
||||
*
|
||||
* Return 0 on success, -1 if the cache mode was invalid.
|
||||
*/
|
||||
int bdrv_parse_cache_flags(const char *mode, int *flags)
|
||||
int bdrv_parse_cache_mode(const char *mode, int *flags, bool *writethrough)
|
||||
{
|
||||
*flags &= ~BDRV_O_CACHE_MASK;
|
||||
|
||||
if (!strcmp(mode, "off") || !strcmp(mode, "none")) {
|
||||
*flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
|
||||
*writethrough = false;
|
||||
*flags |= BDRV_O_NOCACHE;
|
||||
} else if (!strcmp(mode, "directsync")) {
|
||||
*writethrough = true;
|
||||
*flags |= BDRV_O_NOCACHE;
|
||||
} else if (!strcmp(mode, "writeback")) {
|
||||
*flags |= BDRV_O_CACHE_WB;
|
||||
*writethrough = false;
|
||||
} else if (!strcmp(mode, "unsafe")) {
|
||||
*flags |= BDRV_O_CACHE_WB;
|
||||
*writethrough = false;
|
||||
*flags |= BDRV_O_NO_FLUSH;
|
||||
} else if (!strcmp(mode, "writethrough")) {
|
||||
/* this is the default */
|
||||
*writethrough = true;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
@ -673,7 +680,6 @@ static void bdrv_temp_snapshot_options(int *child_flags, QDict *child_options,
|
||||
*child_flags = (parent_flags & ~BDRV_O_SNAPSHOT) | BDRV_O_TEMPORARY;
|
||||
|
||||
/* For temporary files, unconditional cache=unsafe is fine */
|
||||
qdict_set_default_str(child_options, BDRV_OPT_CACHE_WB, "on");
|
||||
qdict_set_default_str(child_options, BDRV_OPT_CACHE_DIRECT, "off");
|
||||
qdict_set_default_str(child_options, BDRV_OPT_CACHE_NO_FLUSH, "on");
|
||||
}
|
||||
@ -698,11 +704,11 @@ static void bdrv_inherited_options(int *child_flags, QDict *child_options,
|
||||
/* 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. */
|
||||
qdict_set_default_str(child_options, BDRV_OPT_CACHE_WB, "on");
|
||||
flags |= BDRV_O_UNMAP;
|
||||
|
||||
/* Clear flags that only apply to the top layer */
|
||||
flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | BDRV_O_COPY_ON_READ);
|
||||
flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | BDRV_O_COPY_ON_READ |
|
||||
BDRV_O_NO_IO);
|
||||
|
||||
*child_flags = flags;
|
||||
}
|
||||
@ -722,7 +728,7 @@ static void bdrv_inherited_fmt_options(int *child_flags, QDict *child_options,
|
||||
child_file.inherit_options(child_flags, child_options,
|
||||
parent_flags, parent_options);
|
||||
|
||||
*child_flags &= ~BDRV_O_PROTOCOL;
|
||||
*child_flags &= ~(BDRV_O_PROTOCOL | BDRV_O_NO_IO);
|
||||
}
|
||||
|
||||
const BdrvChildRole child_format = {
|
||||
@ -738,8 +744,8 @@ static void bdrv_backing_options(int *child_flags, QDict *child_options,
|
||||
{
|
||||
int flags = parent_flags;
|
||||
|
||||
/* The cache mode is inherited unmodified for backing files */
|
||||
qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_WB);
|
||||
/* The cache mode is inherited unmodified for backing files; except WCE,
|
||||
* which is only applied on the top level (BlockBackend) */
|
||||
qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_DIRECT);
|
||||
qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_NO_FLUSH);
|
||||
|
||||
@ -758,7 +764,7 @@ static const BdrvChildRole child_backing = {
|
||||
|
||||
static int bdrv_open_flags(BlockDriverState *bs, int flags)
|
||||
{
|
||||
int open_flags = flags | BDRV_O_CACHE_WB;
|
||||
int open_flags = flags;
|
||||
|
||||
/*
|
||||
* Clear flags that are internal to the block layer before opening the
|
||||
@ -780,11 +786,6 @@ static void update_flags_from_options(int *flags, QemuOpts *opts)
|
||||
{
|
||||
*flags &= ~BDRV_O_CACHE_MASK;
|
||||
|
||||
assert(qemu_opt_find(opts, BDRV_OPT_CACHE_WB));
|
||||
if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_WB, false)) {
|
||||
*flags |= BDRV_O_CACHE_WB;
|
||||
}
|
||||
|
||||
assert(qemu_opt_find(opts, BDRV_OPT_CACHE_NO_FLUSH));
|
||||
if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_NO_FLUSH, false)) {
|
||||
*flags |= BDRV_O_NO_FLUSH;
|
||||
@ -798,10 +799,6 @@ static void update_flags_from_options(int *flags, QemuOpts *opts)
|
||||
|
||||
static void update_options_from_flags(QDict *options, int flags)
|
||||
{
|
||||
if (!qdict_haskey(options, BDRV_OPT_CACHE_WB)) {
|
||||
qdict_put(options, BDRV_OPT_CACHE_WB,
|
||||
qbool_from_bool(flags & BDRV_O_CACHE_WB));
|
||||
}
|
||||
if (!qdict_haskey(options, BDRV_OPT_CACHE_DIRECT)) {
|
||||
qdict_put(options, BDRV_OPT_CACHE_DIRECT,
|
||||
qbool_from_bool(flags & BDRV_O_NOCACHE));
|
||||
@ -863,11 +860,6 @@ static QemuOptsList bdrv_runtime_opts = {
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "Block driver to use for the node",
|
||||
},
|
||||
{
|
||||
.name = BDRV_OPT_CACHE_WB,
|
||||
.type = QEMU_OPT_BOOL,
|
||||
.help = "Enable writeback mode",
|
||||
},
|
||||
{
|
||||
.name = BDRV_OPT_CACHE_DIRECT,
|
||||
.type = QEMU_OPT_BOOL,
|
||||
@ -974,7 +966,6 @@ static int bdrv_open_common(BlockDriverState *bs, BdrvChild *file,
|
||||
|
||||
/* Apply cache mode options */
|
||||
update_flags_from_options(&bs->open_flags, opts);
|
||||
bdrv_set_enable_write_cache(bs, bs->open_flags & BDRV_O_CACHE_WB);
|
||||
|
||||
/* Open the image, either directly or using a protocol */
|
||||
open_flags = bdrv_open_flags(bs, bs->open_flags);
|
||||
@ -1004,13 +995,6 @@ static int bdrv_open_common(BlockDriverState *bs, BdrvChild *file,
|
||||
goto free_and_fail;
|
||||
}
|
||||
|
||||
if (bs->encrypted) {
|
||||
error_report("Encrypted images are deprecated");
|
||||
error_printf("Support for them will be removed in a future release.\n"
|
||||
"You can use 'qemu-img convert' to convert your image"
|
||||
" to an unencrypted one.\n");
|
||||
}
|
||||
|
||||
ret = refresh_total_sectors(bs, bs->total_sectors);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Could not refresh total sector count");
|
||||
@ -2004,17 +1988,6 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
|
||||
|
||||
update_flags_from_options(&reopen_state->flags, opts);
|
||||
|
||||
/* If a guest device is attached, it owns WCE */
|
||||
if (reopen_state->bs->blk && blk_get_attached_dev(reopen_state->bs->blk)) {
|
||||
bool old_wce = bdrv_enable_write_cache(reopen_state->bs);
|
||||
bool new_wce = (reopen_state->flags & BDRV_O_CACHE_WB);
|
||||
if (old_wce != new_wce) {
|
||||
error_setg(errp, "Cannot change cache.writeback: Device attached");
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* node-name and driver must be unchanged. Put them back into the QDict, so
|
||||
* that they are checked at the end of this function. */
|
||||
value = qemu_opt_get(opts, "node-name");
|
||||
@ -2114,8 +2087,6 @@ void bdrv_reopen_commit(BDRVReopenState *reopen_state)
|
||||
|
||||
reopen_state->bs->explicit_options = reopen_state->explicit_options;
|
||||
reopen_state->bs->open_flags = reopen_state->flags;
|
||||
reopen_state->bs->enable_write_cache = !!(reopen_state->flags &
|
||||
BDRV_O_CACHE_WB);
|
||||
reopen_state->bs->read_only = !(reopen_state->flags & BDRV_O_RDWR);
|
||||
|
||||
bdrv_refresh_limits(reopen_state->bs, NULL);
|
||||
@ -2242,29 +2213,11 @@ void bdrv_close_all(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* make a BlockDriverState anonymous by removing from graph_bdrv_state list.
|
||||
* Also, NULL terminate the device_name to prevent double remove */
|
||||
void bdrv_make_anon(BlockDriverState *bs)
|
||||
{
|
||||
if (bs->node_name[0] != '\0') {
|
||||
QTAILQ_REMOVE(&graph_bdrv_states, bs, node_list);
|
||||
}
|
||||
bs->node_name[0] = '\0';
|
||||
}
|
||||
|
||||
/* Fields that need to stay with the top-level BDS */
|
||||
static void bdrv_move_feature_fields(BlockDriverState *bs_dest,
|
||||
BlockDriverState *bs_src)
|
||||
{
|
||||
/* move some fields that need to stay attached to the device */
|
||||
|
||||
/* dev info */
|
||||
bs_dest->copy_on_read = bs_src->copy_on_read;
|
||||
|
||||
bs_dest->enable_write_cache = bs_src->enable_write_cache;
|
||||
|
||||
/* dirty bitmap */
|
||||
bs_dest->dirty_bitmaps = bs_src->dirty_bitmaps;
|
||||
}
|
||||
|
||||
static void change_parent_backing_link(BlockDriverState *from,
|
||||
@ -2381,8 +2334,9 @@ static void bdrv_delete(BlockDriverState *bs)
|
||||
bdrv_close(bs);
|
||||
|
||||
/* remove from list, if necessary */
|
||||
bdrv_make_anon(bs);
|
||||
|
||||
if (bs->node_name[0] != '\0') {
|
||||
QTAILQ_REMOVE(&graph_bdrv_states, bs, node_list);
|
||||
}
|
||||
QTAILQ_REMOVE(&all_bdrv_states, bs, bs_list);
|
||||
|
||||
g_free(bs);
|
||||
@ -2741,23 +2695,6 @@ int bdrv_is_sg(BlockDriverState *bs)
|
||||
return bs->sg;
|
||||
}
|
||||
|
||||
int bdrv_enable_write_cache(BlockDriverState *bs)
|
||||
{
|
||||
return bs->enable_write_cache;
|
||||
}
|
||||
|
||||
void bdrv_set_enable_write_cache(BlockDriverState *bs, bool wce)
|
||||
{
|
||||
bs->enable_write_cache = wce;
|
||||
|
||||
/* so a reopen() will preserve wce */
|
||||
if (wce) {
|
||||
bs->open_flags |= BDRV_O_CACHE_WB;
|
||||
} else {
|
||||
bs->open_flags &= ~BDRV_O_CACHE_WB;
|
||||
}
|
||||
}
|
||||
|
||||
int bdrv_is_encrypted(BlockDriverState *bs)
|
||||
{
|
||||
if (bs->backing && bs->backing->bs->encrypted) {
|
||||
@ -2899,7 +2836,7 @@ BlockDeviceInfoList *bdrv_named_nodes_list(Error **errp)
|
||||
|
||||
list = NULL;
|
||||
QTAILQ_FOREACH(bs, &graph_bdrv_states, node_list) {
|
||||
BlockDeviceInfo *info = bdrv_block_device_info(bs, errp);
|
||||
BlockDeviceInfo *info = bdrv_block_device_info(NULL, bs, errp);
|
||||
if (!info) {
|
||||
qapi_free_BlockDeviceInfoList(list);
|
||||
return NULL;
|
||||
@ -3608,8 +3545,8 @@ void bdrv_img_create(const char *filename, const char *fmt,
|
||||
}
|
||||
|
||||
/* backing files always opened read-only */
|
||||
back_flags =
|
||||
flags & ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING);
|
||||
back_flags = flags;
|
||||
back_flags &= ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING);
|
||||
|
||||
if (backing_fmt) {
|
||||
backing_options = qdict_new();
|
||||
|
@ -4,7 +4,7 @@ block-obj-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o
|
||||
block-obj-y += qed-check.o
|
||||
block-obj-$(CONFIG_VHDX) += vhdx.o vhdx-endian.o vhdx-log.o
|
||||
block-obj-y += quorum.o
|
||||
block-obj-y += parallels.o blkdebug.o blkverify.o
|
||||
block-obj-y += parallels.o blkdebug.o blkverify.o blkreplay.o
|
||||
block-obj-y += block-backend.o snapshot.o qapi.o
|
||||
block-obj-$(CONFIG_WIN32) += raw-win32.o win32-aio.o
|
||||
block-obj-$(CONFIG_POSIX) += raw-posix.o
|
||||
@ -23,6 +23,8 @@ block-obj-$(CONFIG_LIBSSH2) += ssh.o
|
||||
block-obj-y += accounting.o dirty-bitmap.o
|
||||
block-obj-y += write-threshold.o
|
||||
|
||||
block-obj-y += crypto.o
|
||||
|
||||
common-obj-y += stream.o
|
||||
common-obj-y += commit.o
|
||||
common-obj-y += backup.o
|
||||
|
@ -404,7 +404,6 @@ static void coroutine_fn backup_run(void *opaque)
|
||||
|
||||
job->done_bitmap = bitmap_new(end);
|
||||
|
||||
bdrv_set_enable_write_cache(target, true);
|
||||
if (target->blk) {
|
||||
blk_set_on_error(target->blk, on_target_error, on_target_error);
|
||||
blk_iostatus_enable(target->blk);
|
||||
|
160
block/blkreplay.c
Executable file
160
block/blkreplay.c
Executable file
@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Block protocol for record/replay
|
||||
*
|
||||
* Copyright (c) 2010-2016 Institute for System Programming
|
||||
* of the Russian Academy of Sciences.
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "block/block_int.h"
|
||||
#include "sysemu/replay.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
typedef struct Request {
|
||||
Coroutine *co;
|
||||
QEMUBH *bh;
|
||||
} Request;
|
||||
|
||||
/* Next request id.
|
||||
This counter is global, because requests from different
|
||||
block devices should not get overlapping ids. */
|
||||
static uint64_t request_id;
|
||||
|
||||
static int blkreplay_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
Error **errp)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
int ret;
|
||||
|
||||
/* Open the image file */
|
||||
bs->file = bdrv_open_child(NULL, options, "image",
|
||||
bs, &child_file, false, &local_err);
|
||||
if (local_err) {
|
||||
ret = -EINVAL;
|
||||
error_propagate(errp, local_err);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
fail:
|
||||
if (ret < 0) {
|
||||
bdrv_unref_child(bs, bs->file);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void blkreplay_close(BlockDriverState *bs)
|
||||
{
|
||||
}
|
||||
|
||||
static int64_t blkreplay_getlength(BlockDriverState *bs)
|
||||
{
|
||||
return bdrv_getlength(bs->file->bs);
|
||||
}
|
||||
|
||||
/* This bh is used for synchronization of return from coroutines.
|
||||
It continues yielded coroutine which then finishes its execution.
|
||||
BH is called adjusted to some replay checkpoint, therefore
|
||||
record and replay will always finish coroutines deterministically.
|
||||
*/
|
||||
static void blkreplay_bh_cb(void *opaque)
|
||||
{
|
||||
Request *req = opaque;
|
||||
qemu_coroutine_enter(req->co, NULL);
|
||||
qemu_bh_delete(req->bh);
|
||||
g_free(req);
|
||||
}
|
||||
|
||||
static void block_request_create(uint64_t reqid, BlockDriverState *bs,
|
||||
Coroutine *co)
|
||||
{
|
||||
Request *req = g_new(Request, 1);
|
||||
*req = (Request) {
|
||||
.co = co,
|
||||
.bh = aio_bh_new(bdrv_get_aio_context(bs), blkreplay_bh_cb, req),
|
||||
};
|
||||
replay_block_event(req->bh, reqid);
|
||||
}
|
||||
|
||||
static int coroutine_fn blkreplay_co_readv(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
|
||||
{
|
||||
uint64_t reqid = request_id++;
|
||||
int ret = bdrv_co_readv(bs->file->bs, sector_num, nb_sectors, qiov);
|
||||
block_request_create(reqid, bs, qemu_coroutine_self());
|
||||
qemu_coroutine_yield();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int coroutine_fn blkreplay_co_writev(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
|
||||
{
|
||||
uint64_t reqid = request_id++;
|
||||
int ret = bdrv_co_writev(bs->file->bs, sector_num, nb_sectors, qiov);
|
||||
block_request_create(reqid, bs, qemu_coroutine_self());
|
||||
qemu_coroutine_yield();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int coroutine_fn blkreplay_co_write_zeroes(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors, BdrvRequestFlags flags)
|
||||
{
|
||||
uint64_t reqid = request_id++;
|
||||
int ret = bdrv_co_write_zeroes(bs->file->bs, sector_num, nb_sectors, flags);
|
||||
block_request_create(reqid, bs, qemu_coroutine_self());
|
||||
qemu_coroutine_yield();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int coroutine_fn blkreplay_co_discard(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors)
|
||||
{
|
||||
uint64_t reqid = request_id++;
|
||||
int ret = bdrv_co_discard(bs->file->bs, sector_num, nb_sectors);
|
||||
block_request_create(reqid, bs, qemu_coroutine_self());
|
||||
qemu_coroutine_yield();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int coroutine_fn blkreplay_co_flush(BlockDriverState *bs)
|
||||
{
|
||||
uint64_t reqid = request_id++;
|
||||
int ret = bdrv_co_flush(bs->file->bs);
|
||||
block_request_create(reqid, bs, qemu_coroutine_self());
|
||||
qemu_coroutine_yield();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BlockDriver bdrv_blkreplay = {
|
||||
.format_name = "blkreplay",
|
||||
.protocol_name = "blkreplay",
|
||||
.instance_size = 0,
|
||||
|
||||
.bdrv_file_open = blkreplay_open,
|
||||
.bdrv_close = blkreplay_close,
|
||||
.bdrv_getlength = blkreplay_getlength,
|
||||
|
||||
.bdrv_co_readv = blkreplay_co_readv,
|
||||
.bdrv_co_writev = blkreplay_co_writev,
|
||||
|
||||
.bdrv_co_write_zeroes = blkreplay_co_write_zeroes,
|
||||
.bdrv_co_discard = blkreplay_co_discard,
|
||||
.bdrv_co_flush = blkreplay_co_flush,
|
||||
};
|
||||
|
||||
static void bdrv_blkreplay_init(void)
|
||||
{
|
||||
bdrv_register(&bdrv_blkreplay);
|
||||
}
|
||||
|
||||
block_init(bdrv_blkreplay_init);
|
@ -47,6 +47,8 @@ struct BlockBackend {
|
||||
* can be used to restore those options in the new BDS on insert) */
|
||||
BlockBackendRootState root_state;
|
||||
|
||||
bool enable_write_cache;
|
||||
|
||||
/* I/O stats (display with "info blockstats"). */
|
||||
BlockAcctStats stats;
|
||||
|
||||
@ -160,6 +162,8 @@ BlockBackend *blk_new_open(const char *filename, const char *reference,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
blk_set_enable_write_cache(blk, true);
|
||||
|
||||
return blk;
|
||||
}
|
||||
|
||||
@ -371,23 +375,6 @@ BlockDriverState *blk_bs(BlockBackend *blk)
|
||||
return blk->root ? blk->root->bs : NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Changes the BlockDriverState attached to @blk
|
||||
*/
|
||||
void blk_set_bs(BlockBackend *blk, BlockDriverState *bs)
|
||||
{
|
||||
bdrv_ref(bs);
|
||||
|
||||
if (blk->root) {
|
||||
blk->root->bs->blk = NULL;
|
||||
bdrv_root_unref_child(blk->root);
|
||||
}
|
||||
assert(bs->blk == NULL);
|
||||
|
||||
blk->root = bdrv_root_attach_child(bs, "root", &child_root);
|
||||
bs->blk = blk;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return @blk's DriveInfo if any, else null.
|
||||
*/
|
||||
@ -712,11 +699,17 @@ static int coroutine_fn blk_co_pwritev(BlockBackend *blk, int64_t offset,
|
||||
unsigned int bytes, QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags)
|
||||
{
|
||||
int ret = blk_check_byte_request(blk, offset, bytes);
|
||||
int ret;
|
||||
|
||||
ret = blk_check_byte_request(blk, offset, bytes);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!blk->enable_write_cache) {
|
||||
flags |= BDRV_REQ_FUA;
|
||||
}
|
||||
|
||||
return bdrv_co_do_pwritev(blk_bs(blk), offset, bytes, qiov, flags);
|
||||
}
|
||||
|
||||
@ -1223,28 +1216,12 @@ int blk_is_sg(BlockBackend *blk)
|
||||
|
||||
int blk_enable_write_cache(BlockBackend *blk)
|
||||
{
|
||||
BlockDriverState *bs = blk_bs(blk);
|
||||
|
||||
if (bs) {
|
||||
return bdrv_enable_write_cache(bs);
|
||||
} else {
|
||||
return !!(blk->root_state.open_flags & BDRV_O_CACHE_WB);
|
||||
}
|
||||
return blk->enable_write_cache;
|
||||
}
|
||||
|
||||
void blk_set_enable_write_cache(BlockBackend *blk, bool wce)
|
||||
{
|
||||
BlockDriverState *bs = blk_bs(blk);
|
||||
|
||||
if (bs) {
|
||||
bdrv_set_enable_write_cache(bs, wce);
|
||||
} else {
|
||||
if (wce) {
|
||||
blk->root_state.open_flags |= BDRV_O_CACHE_WB;
|
||||
} else {
|
||||
blk->root_state.open_flags &= ~BDRV_O_CACHE_WB;
|
||||
}
|
||||
}
|
||||
blk->enable_write_cache = wce;
|
||||
}
|
||||
|
||||
void blk_invalidate_cache(BlockBackend *blk, Error **errp)
|
||||
@ -1505,11 +1482,22 @@ int blk_discard(BlockBackend *blk, int64_t sector_num, int nb_sectors)
|
||||
int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
|
||||
int64_t pos, int size)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!blk_is_available(blk)) {
|
||||
return -ENOMEDIUM;
|
||||
}
|
||||
|
||||
return bdrv_save_vmstate(blk_bs(blk), buf, pos, size);
|
||||
ret = bdrv_save_vmstate(blk_bs(blk), buf, pos, size);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ret == size && !blk->enable_write_cache) {
|
||||
ret = bdrv_flush(blk_bs(blk));
|
||||
}
|
||||
|
||||
return ret < 0 ? ret : size;
|
||||
}
|
||||
|
||||
int blk_load_vmstate(BlockBackend *blk, uint8_t *buf, int64_t pos, int size)
|
||||
|
586
block/crypto.c
Normal file
586
block/crypto.c
Normal file
@ -0,0 +1,586 @@
|
||||
/*
|
||||
* QEMU block full disk encryption
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include "block/block_int.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "crypto/block.h"
|
||||
#include "qapi/opts-visitor.h"
|
||||
#include "qapi-visit.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
#define BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET "key-secret"
|
||||
#define BLOCK_CRYPTO_OPT_LUKS_CIPHER_ALG "cipher-alg"
|
||||
#define BLOCK_CRYPTO_OPT_LUKS_CIPHER_MODE "cipher-mode"
|
||||
#define BLOCK_CRYPTO_OPT_LUKS_IVGEN_ALG "ivgen-alg"
|
||||
#define BLOCK_CRYPTO_OPT_LUKS_IVGEN_HASH_ALG "ivgen-hash-alg"
|
||||
#define BLOCK_CRYPTO_OPT_LUKS_HASH_ALG "hash-alg"
|
||||
|
||||
typedef struct BlockCrypto BlockCrypto;
|
||||
|
||||
struct BlockCrypto {
|
||||
QCryptoBlock *block;
|
||||
};
|
||||
|
||||
|
||||
static int block_crypto_probe_generic(QCryptoBlockFormat format,
|
||||
const uint8_t *buf,
|
||||
int buf_size,
|
||||
const char *filename)
|
||||
{
|
||||
if (qcrypto_block_has_format(format, buf, buf_size)) {
|
||||
return 100;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static ssize_t block_crypto_read_func(QCryptoBlock *block,
|
||||
size_t offset,
|
||||
uint8_t *buf,
|
||||
size_t buflen,
|
||||
Error **errp,
|
||||
void *opaque)
|
||||
{
|
||||
BlockDriverState *bs = opaque;
|
||||
ssize_t ret;
|
||||
|
||||
ret = bdrv_pread(bs->file->bs, offset, buf, buflen);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Could not read encryption header");
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
struct BlockCryptoCreateData {
|
||||
const char *filename;
|
||||
QemuOpts *opts;
|
||||
BlockBackend *blk;
|
||||
uint64_t size;
|
||||
};
|
||||
|
||||
|
||||
static ssize_t block_crypto_write_func(QCryptoBlock *block,
|
||||
size_t offset,
|
||||
const uint8_t *buf,
|
||||
size_t buflen,
|
||||
Error **errp,
|
||||
void *opaque)
|
||||
{
|
||||
struct BlockCryptoCreateData *data = opaque;
|
||||
ssize_t ret;
|
||||
|
||||
ret = blk_pwrite(data->blk, offset, buf, buflen);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Could not write encryption header");
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static ssize_t block_crypto_init_func(QCryptoBlock *block,
|
||||
size_t headerlen,
|
||||
Error **errp,
|
||||
void *opaque)
|
||||
{
|
||||
struct BlockCryptoCreateData *data = opaque;
|
||||
int ret;
|
||||
|
||||
/* User provided size should reflect amount of space made
|
||||
* available to the guest, so we must take account of that
|
||||
* which will be used by the crypto header
|
||||
*/
|
||||
data->size += headerlen;
|
||||
|
||||
qemu_opt_set_number(data->opts, BLOCK_OPT_SIZE, data->size, &error_abort);
|
||||
ret = bdrv_create_file(data->filename, data->opts, errp);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
data->blk = blk_new_open(data->filename, NULL, NULL,
|
||||
BDRV_O_RDWR | BDRV_O_PROTOCOL, errp);
|
||||
if (!data->blk) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static QemuOptsList block_crypto_runtime_opts_luks = {
|
||||
.name = "crypto",
|
||||
.head = QTAILQ_HEAD_INITIALIZER(block_crypto_runtime_opts_luks.head),
|
||||
.desc = {
|
||||
{
|
||||
.name = BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET,
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "ID of the secret that provides the encryption key",
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
static QemuOptsList block_crypto_create_opts_luks = {
|
||||
.name = "crypto",
|
||||
.head = QTAILQ_HEAD_INITIALIZER(block_crypto_create_opts_luks.head),
|
||||
.desc = {
|
||||
{
|
||||
.name = BLOCK_OPT_SIZE,
|
||||
.type = QEMU_OPT_SIZE,
|
||||
.help = "Virtual disk size"
|
||||
},
|
||||
{
|
||||
.name = BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET,
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "ID of the secret that provides the encryption key",
|
||||
},
|
||||
{
|
||||
.name = BLOCK_CRYPTO_OPT_LUKS_CIPHER_ALG,
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "Name of encryption cipher algorithm",
|
||||
},
|
||||
{
|
||||
.name = BLOCK_CRYPTO_OPT_LUKS_CIPHER_MODE,
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "Name of encryption cipher mode",
|
||||
},
|
||||
{
|
||||
.name = BLOCK_CRYPTO_OPT_LUKS_IVGEN_ALG,
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "Name of IV generator algorithm",
|
||||
},
|
||||
{
|
||||
.name = BLOCK_CRYPTO_OPT_LUKS_IVGEN_HASH_ALG,
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "Name of IV generator hash algorithm",
|
||||
},
|
||||
{
|
||||
.name = BLOCK_CRYPTO_OPT_LUKS_HASH_ALG,
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "Name of encryption hash algorithm",
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
static QCryptoBlockOpenOptions *
|
||||
block_crypto_open_opts_init(QCryptoBlockFormat format,
|
||||
QemuOpts *opts,
|
||||
Error **errp)
|
||||
{
|
||||
OptsVisitor *ov;
|
||||
QCryptoBlockOpenOptions *ret = NULL;
|
||||
Error *local_err = NULL;
|
||||
|
||||
ret = g_new0(QCryptoBlockOpenOptions, 1);
|
||||
ret->format = format;
|
||||
|
||||
ov = opts_visitor_new(opts);
|
||||
|
||||
visit_start_struct(opts_get_visitor(ov),
|
||||
NULL, NULL, 0, &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (format) {
|
||||
case Q_CRYPTO_BLOCK_FORMAT_LUKS:
|
||||
visit_type_QCryptoBlockOptionsLUKS_members(
|
||||
opts_get_visitor(ov), &ret->u.luks, &local_err);
|
||||
break;
|
||||
|
||||
default:
|
||||
error_setg(&local_err, "Unsupported block format %d", format);
|
||||
break;
|
||||
}
|
||||
error_propagate(errp, local_err);
|
||||
local_err = NULL;
|
||||
|
||||
visit_end_struct(opts_get_visitor(ov), &local_err);
|
||||
|
||||
out:
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
qapi_free_QCryptoBlockOpenOptions(ret);
|
||||
ret = NULL;
|
||||
}
|
||||
opts_visitor_cleanup(ov);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static QCryptoBlockCreateOptions *
|
||||
block_crypto_create_opts_init(QCryptoBlockFormat format,
|
||||
QemuOpts *opts,
|
||||
Error **errp)
|
||||
{
|
||||
OptsVisitor *ov;
|
||||
QCryptoBlockCreateOptions *ret = NULL;
|
||||
Error *local_err = NULL;
|
||||
|
||||
ret = g_new0(QCryptoBlockCreateOptions, 1);
|
||||
ret->format = format;
|
||||
|
||||
ov = opts_visitor_new(opts);
|
||||
|
||||
visit_start_struct(opts_get_visitor(ov),
|
||||
NULL, NULL, 0, &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (format) {
|
||||
case Q_CRYPTO_BLOCK_FORMAT_LUKS:
|
||||
visit_type_QCryptoBlockCreateOptionsLUKS_members(
|
||||
opts_get_visitor(ov), &ret->u.luks, &local_err);
|
||||
break;
|
||||
|
||||
default:
|
||||
error_setg(&local_err, "Unsupported block format %d", format);
|
||||
break;
|
||||
}
|
||||
error_propagate(errp, local_err);
|
||||
local_err = NULL;
|
||||
|
||||
visit_end_struct(opts_get_visitor(ov), &local_err);
|
||||
|
||||
out:
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
qapi_free_QCryptoBlockCreateOptions(ret);
|
||||
ret = NULL;
|
||||
}
|
||||
opts_visitor_cleanup(ov);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int block_crypto_open_generic(QCryptoBlockFormat format,
|
||||
QemuOptsList *opts_spec,
|
||||
BlockDriverState *bs,
|
||||
QDict *options,
|
||||
int flags,
|
||||
Error **errp)
|
||||
{
|
||||
BlockCrypto *crypto = bs->opaque;
|
||||
QemuOpts *opts = NULL;
|
||||
Error *local_err = NULL;
|
||||
int ret = -EINVAL;
|
||||
QCryptoBlockOpenOptions *open_opts = NULL;
|
||||
unsigned int cflags = 0;
|
||||
|
||||
opts = qemu_opts_create(opts_spec, NULL, 0, &error_abort);
|
||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
open_opts = block_crypto_open_opts_init(format, opts, errp);
|
||||
if (!open_opts) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (flags & BDRV_O_NO_IO) {
|
||||
cflags |= QCRYPTO_BLOCK_OPEN_NO_IO;
|
||||
}
|
||||
crypto->block = qcrypto_block_open(open_opts,
|
||||
block_crypto_read_func,
|
||||
bs,
|
||||
cflags,
|
||||
errp);
|
||||
|
||||
if (!crypto->block) {
|
||||
ret = -EIO;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
bs->encrypted = 1;
|
||||
bs->valid_key = 1;
|
||||
|
||||
ret = 0;
|
||||
cleanup:
|
||||
qapi_free_QCryptoBlockOpenOptions(open_opts);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int block_crypto_create_generic(QCryptoBlockFormat format,
|
||||
const char *filename,
|
||||
QemuOpts *opts,
|
||||
Error **errp)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
QCryptoBlockCreateOptions *create_opts = NULL;
|
||||
QCryptoBlock *crypto = NULL;
|
||||
struct BlockCryptoCreateData data = {
|
||||
.size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
|
||||
BDRV_SECTOR_SIZE),
|
||||
.opts = opts,
|
||||
.filename = filename,
|
||||
};
|
||||
|
||||
create_opts = block_crypto_create_opts_init(format, opts, errp);
|
||||
if (!create_opts) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
crypto = qcrypto_block_create(create_opts,
|
||||
block_crypto_init_func,
|
||||
block_crypto_write_func,
|
||||
&data,
|
||||
errp);
|
||||
|
||||
if (!crypto) {
|
||||
ret = -EIO;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
cleanup:
|
||||
qcrypto_block_free(crypto);
|
||||
blk_unref(data.blk);
|
||||
qapi_free_QCryptoBlockCreateOptions(create_opts);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int block_crypto_truncate(BlockDriverState *bs, int64_t offset)
|
||||
{
|
||||
BlockCrypto *crypto = bs->opaque;
|
||||
size_t payload_offset =
|
||||
qcrypto_block_get_payload_offset(crypto->block);
|
||||
|
||||
offset += payload_offset;
|
||||
|
||||
return bdrv_truncate(bs->file->bs, offset);
|
||||
}
|
||||
|
||||
static void block_crypto_close(BlockDriverState *bs)
|
||||
{
|
||||
BlockCrypto *crypto = bs->opaque;
|
||||
qcrypto_block_free(crypto->block);
|
||||
}
|
||||
|
||||
|
||||
#define BLOCK_CRYPTO_MAX_SECTORS 32
|
||||
|
||||
static coroutine_fn int
|
||||
block_crypto_co_readv(BlockDriverState *bs, int64_t sector_num,
|
||||
int remaining_sectors, QEMUIOVector *qiov)
|
||||
{
|
||||
BlockCrypto *crypto = bs->opaque;
|
||||
int cur_nr_sectors; /* number of sectors in current iteration */
|
||||
uint64_t bytes_done = 0;
|
||||
uint8_t *cipher_data = NULL;
|
||||
QEMUIOVector hd_qiov;
|
||||
int ret = 0;
|
||||
size_t payload_offset =
|
||||
qcrypto_block_get_payload_offset(crypto->block) / 512;
|
||||
|
||||
qemu_iovec_init(&hd_qiov, qiov->niov);
|
||||
|
||||
/* Bounce buffer so we have a linear mem region for
|
||||
* entire sector. XXX optimize so we avoid bounce
|
||||
* buffer in case that qiov->niov == 1
|
||||
*/
|
||||
cipher_data =
|
||||
qemu_try_blockalign(bs->file->bs, MIN(BLOCK_CRYPTO_MAX_SECTORS * 512,
|
||||
qiov->size));
|
||||
if (cipher_data == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
while (remaining_sectors) {
|
||||
cur_nr_sectors = remaining_sectors;
|
||||
|
||||
if (cur_nr_sectors > BLOCK_CRYPTO_MAX_SECTORS) {
|
||||
cur_nr_sectors = BLOCK_CRYPTO_MAX_SECTORS;
|
||||
}
|
||||
|
||||
qemu_iovec_reset(&hd_qiov);
|
||||
qemu_iovec_add(&hd_qiov, cipher_data, cur_nr_sectors * 512);
|
||||
|
||||
ret = bdrv_co_readv(bs->file->bs,
|
||||
payload_offset + sector_num,
|
||||
cur_nr_sectors, &hd_qiov);
|
||||
if (ret < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (qcrypto_block_decrypt(crypto->block,
|
||||
sector_num,
|
||||
cipher_data, cur_nr_sectors * 512,
|
||||
NULL) < 0) {
|
||||
ret = -EIO;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
qemu_iovec_from_buf(qiov, bytes_done,
|
||||
cipher_data, cur_nr_sectors * 512);
|
||||
|
||||
remaining_sectors -= cur_nr_sectors;
|
||||
sector_num += cur_nr_sectors;
|
||||
bytes_done += cur_nr_sectors * 512;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
qemu_iovec_destroy(&hd_qiov);
|
||||
qemu_vfree(cipher_data);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static coroutine_fn int
|
||||
block_crypto_co_writev(BlockDriverState *bs, int64_t sector_num,
|
||||
int remaining_sectors, QEMUIOVector *qiov)
|
||||
{
|
||||
BlockCrypto *crypto = bs->opaque;
|
||||
int cur_nr_sectors; /* number of sectors in current iteration */
|
||||
uint64_t bytes_done = 0;
|
||||
uint8_t *cipher_data = NULL;
|
||||
QEMUIOVector hd_qiov;
|
||||
int ret = 0;
|
||||
size_t payload_offset =
|
||||
qcrypto_block_get_payload_offset(crypto->block) / 512;
|
||||
|
||||
qemu_iovec_init(&hd_qiov, qiov->niov);
|
||||
|
||||
/* Bounce buffer so we have a linear mem region for
|
||||
* entire sector. XXX optimize so we avoid bounce
|
||||
* buffer in case that qiov->niov == 1
|
||||
*/
|
||||
cipher_data =
|
||||
qemu_try_blockalign(bs->file->bs, MIN(BLOCK_CRYPTO_MAX_SECTORS * 512,
|
||||
qiov->size));
|
||||
if (cipher_data == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
while (remaining_sectors) {
|
||||
cur_nr_sectors = remaining_sectors;
|
||||
|
||||
if (cur_nr_sectors > BLOCK_CRYPTO_MAX_SECTORS) {
|
||||
cur_nr_sectors = BLOCK_CRYPTO_MAX_SECTORS;
|
||||
}
|
||||
|
||||
qemu_iovec_to_buf(qiov, bytes_done,
|
||||
cipher_data, cur_nr_sectors * 512);
|
||||
|
||||
if (qcrypto_block_encrypt(crypto->block,
|
||||
sector_num,
|
||||
cipher_data, cur_nr_sectors * 512,
|
||||
NULL) < 0) {
|
||||
ret = -EIO;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
qemu_iovec_reset(&hd_qiov);
|
||||
qemu_iovec_add(&hd_qiov, cipher_data, cur_nr_sectors * 512);
|
||||
|
||||
ret = bdrv_co_writev(bs->file->bs,
|
||||
payload_offset + sector_num,
|
||||
cur_nr_sectors, &hd_qiov);
|
||||
if (ret < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
remaining_sectors -= cur_nr_sectors;
|
||||
sector_num += cur_nr_sectors;
|
||||
bytes_done += cur_nr_sectors * 512;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
qemu_iovec_destroy(&hd_qiov);
|
||||
qemu_vfree(cipher_data);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int64_t block_crypto_getlength(BlockDriverState *bs)
|
||||
{
|
||||
BlockCrypto *crypto = bs->opaque;
|
||||
int64_t len = bdrv_getlength(bs->file->bs);
|
||||
|
||||
ssize_t offset = qcrypto_block_get_payload_offset(crypto->block);
|
||||
|
||||
len -= offset;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static int block_crypto_probe_luks(const uint8_t *buf,
|
||||
int buf_size,
|
||||
const char *filename) {
|
||||
return block_crypto_probe_generic(Q_CRYPTO_BLOCK_FORMAT_LUKS,
|
||||
buf, buf_size, filename);
|
||||
}
|
||||
|
||||
static int block_crypto_open_luks(BlockDriverState *bs,
|
||||
QDict *options,
|
||||
int flags,
|
||||
Error **errp)
|
||||
{
|
||||
return block_crypto_open_generic(Q_CRYPTO_BLOCK_FORMAT_LUKS,
|
||||
&block_crypto_runtime_opts_luks,
|
||||
bs, options, flags, errp);
|
||||
}
|
||||
|
||||
static int block_crypto_create_luks(const char *filename,
|
||||
QemuOpts *opts,
|
||||
Error **errp)
|
||||
{
|
||||
return block_crypto_create_generic(Q_CRYPTO_BLOCK_FORMAT_LUKS,
|
||||
filename, opts, errp);
|
||||
}
|
||||
|
||||
BlockDriver bdrv_crypto_luks = {
|
||||
.format_name = "luks",
|
||||
.instance_size = sizeof(BlockCrypto),
|
||||
.bdrv_probe = block_crypto_probe_luks,
|
||||
.bdrv_open = block_crypto_open_luks,
|
||||
.bdrv_close = block_crypto_close,
|
||||
.bdrv_create = block_crypto_create_luks,
|
||||
.bdrv_truncate = block_crypto_truncate,
|
||||
.create_opts = &block_crypto_create_opts_luks,
|
||||
|
||||
.bdrv_co_readv = block_crypto_co_readv,
|
||||
.bdrv_co_writev = block_crypto_co_writev,
|
||||
.bdrv_getlength = block_crypto_getlength,
|
||||
};
|
||||
|
||||
static void block_crypto_init(void)
|
||||
{
|
||||
bdrv_register(&bdrv_crypto_luks);
|
||||
}
|
||||
|
||||
block_init(block_crypto_init);
|
24
block/io.c
24
block/io.c
@ -747,9 +747,9 @@ int bdrv_pwrite_sync(BlockDriverState *bs, int64_t offset,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* No flush needed for cache modes that already do it */
|
||||
if (bs->enable_write_cache) {
|
||||
bdrv_flush(bs);
|
||||
ret = bdrv_flush(bs);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -844,6 +844,7 @@ static int coroutine_fn bdrv_aligned_preadv(BlockDriverState *bs,
|
||||
assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
|
||||
assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
|
||||
assert(!qiov || bytes == qiov->size);
|
||||
assert((bs->open_flags & BDRV_O_NO_IO) == 0);
|
||||
|
||||
/* Handle Copy on Read and associated serialisation */
|
||||
if (flags & BDRV_REQ_COPY_ON_READ) {
|
||||
@ -1130,6 +1131,7 @@ static int coroutine_fn bdrv_aligned_pwritev(BlockDriverState *bs,
|
||||
assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
|
||||
assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
|
||||
assert(!qiov || bytes == qiov->size);
|
||||
assert((bs->open_flags & BDRV_O_NO_IO) == 0);
|
||||
|
||||
waited = wait_serialising_requests(req);
|
||||
assert(!waited || !req->serialising);
|
||||
@ -1152,13 +1154,20 @@ static int coroutine_fn bdrv_aligned_pwritev(BlockDriverState *bs,
|
||||
} else if (flags & BDRV_REQ_ZERO_WRITE) {
|
||||
bdrv_debug_event(bs, BLKDBG_PWRITEV_ZERO);
|
||||
ret = bdrv_co_do_write_zeroes(bs, sector_num, nb_sectors, flags);
|
||||
} else if (drv->bdrv_co_writev_flags) {
|
||||
bdrv_debug_event(bs, BLKDBG_PWRITEV);
|
||||
ret = drv->bdrv_co_writev_flags(bs, sector_num, nb_sectors, qiov,
|
||||
flags);
|
||||
} else {
|
||||
assert(drv->supported_write_flags == 0);
|
||||
bdrv_debug_event(bs, BLKDBG_PWRITEV);
|
||||
ret = drv->bdrv_co_writev(bs, sector_num, nb_sectors, qiov);
|
||||
}
|
||||
bdrv_debug_event(bs, BLKDBG_PWRITEV_DONE);
|
||||
|
||||
if (ret == 0 && !bs->enable_write_cache) {
|
||||
if (ret == 0 && (flags & BDRV_REQ_FUA) &&
|
||||
!(drv->supported_write_flags & BDRV_REQ_FUA))
|
||||
{
|
||||
ret = bdrv_co_flush(bs);
|
||||
}
|
||||
|
||||
@ -2331,6 +2340,13 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
|
||||
}
|
||||
|
||||
tracked_request_begin(&req, bs, 0, 0, BDRV_TRACKED_FLUSH);
|
||||
|
||||
/* Write back all layers by calling one driver function */
|
||||
if (bs->drv->bdrv_co_flush) {
|
||||
ret = bs->drv->bdrv_co_flush(bs);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Write back cached data to the OS even with cache=unsafe */
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_FLUSH_TO_OS);
|
||||
if (bs->drv->bdrv_co_flush_to_os) {
|
||||
|
@ -70,7 +70,6 @@ typedef struct IscsiLun {
|
||||
bool lbprz;
|
||||
bool dpofua;
|
||||
bool has_write_same;
|
||||
bool force_next_flush;
|
||||
bool request_timed_out;
|
||||
} IscsiLun;
|
||||
|
||||
@ -84,7 +83,6 @@ typedef struct IscsiTask {
|
||||
QEMUBH *bh;
|
||||
IscsiLun *iscsilun;
|
||||
QEMUTimer retry_timer;
|
||||
bool force_next_flush;
|
||||
int err_code;
|
||||
} IscsiTask;
|
||||
|
||||
@ -282,8 +280,6 @@ iscsi_co_generic_cb(struct iscsi_context *iscsi, int status,
|
||||
}
|
||||
iTask->err_code = iscsi_translate_sense(&task->sense);
|
||||
error_report("iSCSI Failure: %s", iscsi_get_error(iscsi));
|
||||
} else {
|
||||
iTask->iscsilun->force_next_flush |= iTask->force_next_flush;
|
||||
}
|
||||
|
||||
out:
|
||||
@ -452,15 +448,15 @@ static void iscsi_allocationmap_clear(IscsiLun *iscsilun, int64_t sector_num,
|
||||
}
|
||||
}
|
||||
|
||||
static int coroutine_fn iscsi_co_writev(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors,
|
||||
QEMUIOVector *iov)
|
||||
static int coroutine_fn
|
||||
iscsi_co_writev_flags(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
|
||||
QEMUIOVector *iov, int flags)
|
||||
{
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
struct IscsiTask iTask;
|
||||
uint64_t lba;
|
||||
uint32_t num_sectors;
|
||||
int fua;
|
||||
bool fua;
|
||||
|
||||
if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
|
||||
return -EINVAL;
|
||||
@ -476,8 +472,7 @@ static int coroutine_fn iscsi_co_writev(BlockDriverState *bs,
|
||||
num_sectors = sector_qemu2lun(nb_sectors, iscsilun);
|
||||
iscsi_co_init_iscsitask(iscsilun, &iTask);
|
||||
retry:
|
||||
fua = iscsilun->dpofua && !bs->enable_write_cache;
|
||||
iTask.force_next_flush = !fua;
|
||||
fua = iscsilun->dpofua && (flags & BDRV_REQ_FUA);
|
||||
if (iscsilun->use_16_for_rw) {
|
||||
iTask.task = iscsi_write16_task(iscsilun->iscsi, iscsilun->lun, lba,
|
||||
NULL, num_sectors * iscsilun->block_size,
|
||||
@ -518,6 +513,13 @@ retry:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int coroutine_fn
|
||||
iscsi_co_writev(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
|
||||
QEMUIOVector *iov)
|
||||
{
|
||||
return iscsi_co_writev_flags(bs, sector_num, nb_sectors, iov, 0);
|
||||
}
|
||||
|
||||
|
||||
static bool iscsi_allocationmap_is_allocated(IscsiLun *iscsilun,
|
||||
int64_t sector_num, int nb_sectors)
|
||||
@ -715,11 +717,6 @@ static int coroutine_fn iscsi_co_flush(BlockDriverState *bs)
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
struct IscsiTask iTask;
|
||||
|
||||
if (!iscsilun->force_next_flush) {
|
||||
return 0;
|
||||
}
|
||||
iscsilun->force_next_flush = false;
|
||||
|
||||
iscsi_co_init_iscsitask(iscsilun, &iTask);
|
||||
retry:
|
||||
if (iscsi_synchronizecache10_task(iscsilun->iscsi, iscsilun->lun, 0, 0, 0,
|
||||
@ -1019,7 +1016,6 @@ coroutine_fn iscsi_co_write_zeroes(BlockDriverState *bs, int64_t sector_num,
|
||||
}
|
||||
|
||||
iscsi_co_init_iscsitask(iscsilun, &iTask);
|
||||
iTask.force_next_flush = true;
|
||||
retry:
|
||||
if (use_16_for_ws) {
|
||||
iTask.task = iscsi_writesame16_task(iscsilun->iscsi, iscsilun->lun, lba,
|
||||
@ -1852,6 +1848,8 @@ static BlockDriver bdrv_iscsi = {
|
||||
.bdrv_co_write_zeroes = iscsi_co_write_zeroes,
|
||||
.bdrv_co_readv = iscsi_co_readv,
|
||||
.bdrv_co_writev = iscsi_co_writev,
|
||||
.bdrv_co_writev_flags = iscsi_co_writev_flags,
|
||||
.supported_write_flags = BDRV_REQ_FUA,
|
||||
.bdrv_co_flush_to_disk = iscsi_co_flush,
|
||||
|
||||
#ifdef __linux__
|
||||
|
@ -856,7 +856,6 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target,
|
||||
|
||||
bdrv_op_block_all(s->target, s->common.blocker);
|
||||
|
||||
bdrv_set_enable_write_cache(s->target, true);
|
||||
if (s->target->blk) {
|
||||
blk_set_on_error(s->target->blk, on_target_error, on_target_error);
|
||||
blk_iostatus_enable(s->target->blk);
|
||||
|
@ -243,15 +243,15 @@ static int nbd_co_readv_1(BlockDriverState *bs, int64_t sector_num,
|
||||
|
||||
static int nbd_co_writev_1(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors, QEMUIOVector *qiov,
|
||||
int offset)
|
||||
int offset, int *flags)
|
||||
{
|
||||
NbdClientSession *client = nbd_get_client_session(bs);
|
||||
struct nbd_request request = { .type = NBD_CMD_WRITE };
|
||||
struct nbd_reply reply;
|
||||
ssize_t ret;
|
||||
|
||||
if (!bdrv_enable_write_cache(bs) &&
|
||||
(client->nbdflags & NBD_FLAG_SEND_FUA)) {
|
||||
if ((*flags & BDRV_REQ_FUA) && (client->nbdflags & NBD_FLAG_SEND_FUA)) {
|
||||
*flags &= ~BDRV_REQ_FUA;
|
||||
request.type |= NBD_CMD_FLAG_FUA;
|
||||
}
|
||||
|
||||
@ -291,12 +291,13 @@ int nbd_client_co_readv(BlockDriverState *bs, int64_t sector_num,
|
||||
}
|
||||
|
||||
int nbd_client_co_writev(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors, QEMUIOVector *qiov)
|
||||
int nb_sectors, QEMUIOVector *qiov, int *flags)
|
||||
{
|
||||
int offset = 0;
|
||||
int ret;
|
||||
while (nb_sectors > NBD_MAX_SECTORS) {
|
||||
ret = nbd_co_writev_1(bs, sector_num, NBD_MAX_SECTORS, qiov, offset);
|
||||
ret = nbd_co_writev_1(bs, sector_num, NBD_MAX_SECTORS, qiov, offset,
|
||||
flags);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
@ -304,7 +305,7 @@ int nbd_client_co_writev(BlockDriverState *bs, int64_t sector_num,
|
||||
sector_num += NBD_MAX_SECTORS;
|
||||
nb_sectors -= NBD_MAX_SECTORS;
|
||||
}
|
||||
return nbd_co_writev_1(bs, sector_num, nb_sectors, qiov, offset);
|
||||
return nbd_co_writev_1(bs, sector_num, nb_sectors, qiov, offset, flags);
|
||||
}
|
||||
|
||||
int nbd_client_co_flush(BlockDriverState *bs)
|
||||
|
@ -48,7 +48,7 @@ int nbd_client_co_discard(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors);
|
||||
int nbd_client_co_flush(BlockDriverState *bs);
|
||||
int nbd_client_co_writev(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors, QEMUIOVector *qiov);
|
||||
int nb_sectors, QEMUIOVector *qiov, int *flags);
|
||||
int nbd_client_co_readv(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors, QEMUIOVector *qiov);
|
||||
|
||||
|
27
block/nbd.c
27
block/nbd.c
@ -355,10 +355,29 @@ static int nbd_co_readv(BlockDriverState *bs, int64_t sector_num,
|
||||
return nbd_client_co_readv(bs, sector_num, nb_sectors, qiov);
|
||||
}
|
||||
|
||||
static int nbd_co_writev_flags(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors, QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = nbd_client_co_writev(bs, sector_num, nb_sectors, qiov, &flags);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* The flag wasn't sent to the server, so we need to emulate it with an
|
||||
* explicit flush */
|
||||
if (flags & BDRV_REQ_FUA) {
|
||||
ret = nbd_client_co_flush(bs);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int nbd_co_writev(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors, QEMUIOVector *qiov)
|
||||
{
|
||||
return nbd_client_co_writev(bs, sector_num, nb_sectors, qiov);
|
||||
return nbd_co_writev_flags(bs, sector_num, nb_sectors, qiov, 0);
|
||||
}
|
||||
|
||||
static int nbd_co_flush(BlockDriverState *bs)
|
||||
@ -458,6 +477,8 @@ static BlockDriver bdrv_nbd = {
|
||||
.bdrv_file_open = nbd_open,
|
||||
.bdrv_co_readv = nbd_co_readv,
|
||||
.bdrv_co_writev = nbd_co_writev,
|
||||
.bdrv_co_writev_flags = nbd_co_writev_flags,
|
||||
.supported_write_flags = BDRV_REQ_FUA,
|
||||
.bdrv_close = nbd_close,
|
||||
.bdrv_co_flush_to_os = nbd_co_flush,
|
||||
.bdrv_co_discard = nbd_co_discard,
|
||||
@ -476,6 +497,8 @@ static BlockDriver bdrv_nbd_tcp = {
|
||||
.bdrv_file_open = nbd_open,
|
||||
.bdrv_co_readv = nbd_co_readv,
|
||||
.bdrv_co_writev = nbd_co_writev,
|
||||
.bdrv_co_writev_flags = nbd_co_writev_flags,
|
||||
.supported_write_flags = BDRV_REQ_FUA,
|
||||
.bdrv_close = nbd_close,
|
||||
.bdrv_co_flush_to_os = nbd_co_flush,
|
||||
.bdrv_co_discard = nbd_co_discard,
|
||||
@ -494,6 +517,8 @@ static BlockDriver bdrv_nbd_unix = {
|
||||
.bdrv_file_open = nbd_open,
|
||||
.bdrv_co_readv = nbd_co_readv,
|
||||
.bdrv_co_writev = nbd_co_writev,
|
||||
.bdrv_co_writev_flags = nbd_co_writev_flags,
|
||||
.supported_write_flags = BDRV_REQ_FUA,
|
||||
.bdrv_close = nbd_close,
|
||||
.bdrv_co_flush_to_os = nbd_co_flush,
|
||||
.bdrv_co_discard = nbd_co_discard,
|
||||
|
42
block/null.c
42
block/null.c
@ -15,10 +15,12 @@
|
||||
#include "block/block_int.h"
|
||||
|
||||
#define NULL_OPT_LATENCY "latency-ns"
|
||||
#define NULL_OPT_ZEROES "read-zeroes"
|
||||
|
||||
typedef struct {
|
||||
int64_t length;
|
||||
int64_t latency_ns;
|
||||
bool read_zeroes;
|
||||
} BDRVNullState;
|
||||
|
||||
static QemuOptsList runtime_opts = {
|
||||
@ -41,6 +43,11 @@ static QemuOptsList runtime_opts = {
|
||||
.help = "nanoseconds (approximated) to wait "
|
||||
"before completing request",
|
||||
},
|
||||
{
|
||||
.name = NULL_OPT_ZEROES,
|
||||
.type = QEMU_OPT_BOOL,
|
||||
.help = "return zeroes when read",
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
@ -62,6 +69,7 @@ static int null_file_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
error_setg(errp, "latency-ns is invalid");
|
||||
ret = -EINVAL;
|
||||
}
|
||||
s->read_zeroes = qemu_opt_get_bool(opts, NULL_OPT_ZEROES, false);
|
||||
qemu_opts_del(opts);
|
||||
return ret;
|
||||
}
|
||||
@ -91,6 +99,12 @@ static coroutine_fn int null_co_readv(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors,
|
||||
QEMUIOVector *qiov)
|
||||
{
|
||||
BDRVNullState *s = bs->opaque;
|
||||
|
||||
if (s->read_zeroes) {
|
||||
qemu_iovec_memset(qiov, 0, 0, nb_sectors * BDRV_SECTOR_SIZE);
|
||||
}
|
||||
|
||||
return null_co_common(bs);
|
||||
}
|
||||
|
||||
@ -160,6 +174,12 @@ static BlockAIOCB *null_aio_readv(BlockDriverState *bs,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque)
|
||||
{
|
||||
BDRVNullState *s = bs->opaque;
|
||||
|
||||
if (s->read_zeroes) {
|
||||
qemu_iovec_memset(qiov, 0, 0, nb_sectors * BDRV_SECTOR_SIZE);
|
||||
}
|
||||
|
||||
return null_aio_common(bs, cb, opaque);
|
||||
}
|
||||
|
||||
@ -185,6 +205,24 @@ static int null_reopen_prepare(BDRVReopenState *reopen_state,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int64_t coroutine_fn null_co_get_block_status(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
int nb_sectors, int *pnum,
|
||||
BlockDriverState **file)
|
||||
{
|
||||
BDRVNullState *s = bs->opaque;
|
||||
off_t start = sector_num * BDRV_SECTOR_SIZE;
|
||||
|
||||
*pnum = nb_sectors;
|
||||
*file = bs;
|
||||
|
||||
if (s->read_zeroes) {
|
||||
return BDRV_BLOCK_OFFSET_VALID | start | BDRV_BLOCK_ZERO;
|
||||
} else {
|
||||
return BDRV_BLOCK_OFFSET_VALID | start;
|
||||
}
|
||||
}
|
||||
|
||||
static BlockDriver bdrv_null_co = {
|
||||
.format_name = "null-co",
|
||||
.protocol_name = "null-co",
|
||||
@ -198,6 +236,8 @@ static BlockDriver bdrv_null_co = {
|
||||
.bdrv_co_writev = null_co_writev,
|
||||
.bdrv_co_flush_to_disk = null_co_flush,
|
||||
.bdrv_reopen_prepare = null_reopen_prepare,
|
||||
|
||||
.bdrv_co_get_block_status = null_co_get_block_status,
|
||||
};
|
||||
|
||||
static BlockDriver bdrv_null_aio = {
|
||||
@ -213,6 +253,8 @@ static BlockDriver bdrv_null_aio = {
|
||||
.bdrv_aio_writev = null_aio_writev,
|
||||
.bdrv_aio_flush = null_aio_flush,
|
||||
.bdrv_reopen_prepare = null_reopen_prepare,
|
||||
|
||||
.bdrv_co_get_block_status = null_co_get_block_status,
|
||||
};
|
||||
|
||||
static void bdrv_null_init(void)
|
||||
|
@ -480,8 +480,7 @@ static int parallels_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
}
|
||||
|
||||
file = blk_new_open(filename, NULL, NULL,
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_PROTOCOL,
|
||||
&local_err);
|
||||
BDRV_O_RDWR | BDRV_O_PROTOCOL, &local_err);
|
||||
if (file == NULL) {
|
||||
error_propagate(errp, local_err);
|
||||
return -EIO;
|
||||
|
75
block/qapi.c
75
block/qapi.c
@ -34,7 +34,8 @@
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "qemu/cutils.h"
|
||||
|
||||
BlockDeviceInfo *bdrv_block_device_info(BlockDriverState *bs, Error **errp)
|
||||
BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
|
||||
BlockDriverState *bs, Error **errp)
|
||||
{
|
||||
ImageInfo **p_image_info;
|
||||
BlockDriverState *bs0;
|
||||
@ -48,7 +49,7 @@ BlockDeviceInfo *bdrv_block_device_info(BlockDriverState *bs, Error **errp)
|
||||
|
||||
info->cache = g_new(BlockdevCacheInfo, 1);
|
||||
*info->cache = (BlockdevCacheInfo) {
|
||||
.writeback = bdrv_enable_write_cache(bs),
|
||||
.writeback = blk ? blk_enable_write_cache(blk) : true,
|
||||
.direct = !!(bs->open_flags & BDRV_O_NOCACHE),
|
||||
.no_flush = !!(bs->open_flags & BDRV_O_NO_FLUSH),
|
||||
};
|
||||
@ -343,7 +344,7 @@ static void bdrv_query_info(BlockBackend *blk, BlockInfo **p_info,
|
||||
|
||||
if (bs && bs->drv) {
|
||||
info->has_inserted = true;
|
||||
info->inserted = bdrv_block_device_info(bs, errp);
|
||||
info->inserted = bdrv_block_device_info(blk, bs, errp);
|
||||
if (info->inserted == NULL) {
|
||||
goto err;
|
||||
}
|
||||
@ -360,50 +361,47 @@ static BlockStats *bdrv_query_stats(BlockBackend *blk,
|
||||
const BlockDriverState *bs,
|
||||
bool query_backing);
|
||||
|
||||
static void bdrv_query_blk_stats(BlockStats *s, BlockBackend *blk)
|
||||
static void bdrv_query_blk_stats(BlockDeviceStats *ds, BlockBackend *blk)
|
||||
{
|
||||
BlockAcctStats *stats = blk_get_stats(blk);
|
||||
BlockAcctTimedStats *ts = NULL;
|
||||
|
||||
s->has_device = true;
|
||||
s->device = g_strdup(blk_name(blk));
|
||||
ds->rd_bytes = stats->nr_bytes[BLOCK_ACCT_READ];
|
||||
ds->wr_bytes = stats->nr_bytes[BLOCK_ACCT_WRITE];
|
||||
ds->rd_operations = stats->nr_ops[BLOCK_ACCT_READ];
|
||||
ds->wr_operations = stats->nr_ops[BLOCK_ACCT_WRITE];
|
||||
|
||||
s->stats->rd_bytes = stats->nr_bytes[BLOCK_ACCT_READ];
|
||||
s->stats->wr_bytes = stats->nr_bytes[BLOCK_ACCT_WRITE];
|
||||
s->stats->rd_operations = stats->nr_ops[BLOCK_ACCT_READ];
|
||||
s->stats->wr_operations = stats->nr_ops[BLOCK_ACCT_WRITE];
|
||||
ds->failed_rd_operations = stats->failed_ops[BLOCK_ACCT_READ];
|
||||
ds->failed_wr_operations = stats->failed_ops[BLOCK_ACCT_WRITE];
|
||||
ds->failed_flush_operations = stats->failed_ops[BLOCK_ACCT_FLUSH];
|
||||
|
||||
s->stats->failed_rd_operations = stats->failed_ops[BLOCK_ACCT_READ];
|
||||
s->stats->failed_wr_operations = stats->failed_ops[BLOCK_ACCT_WRITE];
|
||||
s->stats->failed_flush_operations = stats->failed_ops[BLOCK_ACCT_FLUSH];
|
||||
|
||||
s->stats->invalid_rd_operations = stats->invalid_ops[BLOCK_ACCT_READ];
|
||||
s->stats->invalid_wr_operations = stats->invalid_ops[BLOCK_ACCT_WRITE];
|
||||
s->stats->invalid_flush_operations =
|
||||
ds->invalid_rd_operations = stats->invalid_ops[BLOCK_ACCT_READ];
|
||||
ds->invalid_wr_operations = stats->invalid_ops[BLOCK_ACCT_WRITE];
|
||||
ds->invalid_flush_operations =
|
||||
stats->invalid_ops[BLOCK_ACCT_FLUSH];
|
||||
|
||||
s->stats->rd_merged = stats->merged[BLOCK_ACCT_READ];
|
||||
s->stats->wr_merged = stats->merged[BLOCK_ACCT_WRITE];
|
||||
s->stats->flush_operations = stats->nr_ops[BLOCK_ACCT_FLUSH];
|
||||
s->stats->wr_total_time_ns = stats->total_time_ns[BLOCK_ACCT_WRITE];
|
||||
s->stats->rd_total_time_ns = stats->total_time_ns[BLOCK_ACCT_READ];
|
||||
s->stats->flush_total_time_ns = stats->total_time_ns[BLOCK_ACCT_FLUSH];
|
||||
ds->rd_merged = stats->merged[BLOCK_ACCT_READ];
|
||||
ds->wr_merged = stats->merged[BLOCK_ACCT_WRITE];
|
||||
ds->flush_operations = stats->nr_ops[BLOCK_ACCT_FLUSH];
|
||||
ds->wr_total_time_ns = stats->total_time_ns[BLOCK_ACCT_WRITE];
|
||||
ds->rd_total_time_ns = stats->total_time_ns[BLOCK_ACCT_READ];
|
||||
ds->flush_total_time_ns = stats->total_time_ns[BLOCK_ACCT_FLUSH];
|
||||
|
||||
s->stats->has_idle_time_ns = stats->last_access_time_ns > 0;
|
||||
if (s->stats->has_idle_time_ns) {
|
||||
s->stats->idle_time_ns = block_acct_idle_time_ns(stats);
|
||||
ds->has_idle_time_ns = stats->last_access_time_ns > 0;
|
||||
if (ds->has_idle_time_ns) {
|
||||
ds->idle_time_ns = block_acct_idle_time_ns(stats);
|
||||
}
|
||||
|
||||
s->stats->account_invalid = stats->account_invalid;
|
||||
s->stats->account_failed = stats->account_failed;
|
||||
ds->account_invalid = stats->account_invalid;
|
||||
ds->account_failed = stats->account_failed;
|
||||
|
||||
while ((ts = block_acct_interval_next(stats, ts))) {
|
||||
BlockDeviceTimedStatsList *timed_stats =
|
||||
g_malloc0(sizeof(*timed_stats));
|
||||
BlockDeviceTimedStats *dev_stats = g_malloc0(sizeof(*dev_stats));
|
||||
timed_stats->next = s->stats->timed_stats;
|
||||
timed_stats->next = ds->timed_stats;
|
||||
timed_stats->value = dev_stats;
|
||||
s->stats->timed_stats = timed_stats;
|
||||
ds->timed_stats = timed_stats;
|
||||
|
||||
TimedAverage *rd = &ts->latency[BLOCK_ACCT_READ];
|
||||
TimedAverage *wr = &ts->latency[BLOCK_ACCT_WRITE];
|
||||
@ -462,7 +460,9 @@ static BlockStats *bdrv_query_stats(BlockBackend *blk,
|
||||
s->stats = g_malloc0(sizeof(*s->stats));
|
||||
|
||||
if (blk) {
|
||||
bdrv_query_blk_stats(s, blk);
|
||||
s->has_device = true;
|
||||
s->device = g_strdup(blk_name(blk));
|
||||
bdrv_query_blk_stats(s->stats, blk);
|
||||
}
|
||||
if (bs) {
|
||||
bdrv_query_bds_stats(s, bs, query_backing);
|
||||
@ -652,9 +652,8 @@ static void dump_qlist(fprintf_function func_fprintf, void *f, int indentation,
|
||||
for (entry = qlist_first(list); entry; entry = qlist_next(entry), i++) {
|
||||
QType type = qobject_type(entry->value);
|
||||
bool composite = (type == QTYPE_QDICT || type == QTYPE_QLIST);
|
||||
const char *format = composite ? "%*s[%i]:\n" : "%*s[%i]: ";
|
||||
|
||||
func_fprintf(f, format, indentation * 4, "", i);
|
||||
func_fprintf(f, "%*s[%i]:%c", indentation * 4, "", i,
|
||||
composite ? '\n' : ' ');
|
||||
dump_qobject(func_fprintf, f, indentation + 1, entry->value);
|
||||
if (!composite) {
|
||||
func_fprintf(f, "\n");
|
||||
@ -670,8 +669,7 @@ static void dump_qdict(fprintf_function func_fprintf, void *f, int indentation,
|
||||
for (entry = qdict_first(dict); entry; entry = qdict_next(dict, entry)) {
|
||||
QType type = qobject_type(entry->value);
|
||||
bool composite = (type == QTYPE_QDICT || type == QTYPE_QLIST);
|
||||
const char *format = composite ? "%*s%s:\n" : "%*s%s: ";
|
||||
char key[strlen(entry->key) + 1];
|
||||
char *key = g_malloc(strlen(entry->key) + 1);
|
||||
int i;
|
||||
|
||||
/* replace dashes with spaces in key (variable) names */
|
||||
@ -679,12 +677,13 @@ static void dump_qdict(fprintf_function func_fprintf, void *f, int indentation,
|
||||
key[i] = entry->key[i] == '-' ? ' ' : entry->key[i];
|
||||
}
|
||||
key[i] = 0;
|
||||
|
||||
func_fprintf(f, format, indentation * 4, "", key);
|
||||
func_fprintf(f, "%*s%s:%c", indentation * 4, "", key,
|
||||
composite ? '\n' : ' ');
|
||||
dump_qobject(func_fprintf, f, indentation + 1, entry->value);
|
||||
if (!composite) {
|
||||
func_fprintf(f, "\n");
|
||||
}
|
||||
g_free(key);
|
||||
}
|
||||
}
|
||||
|
||||
|
12
block/qcow.c
12
block/qcow.c
@ -24,6 +24,7 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "block/block_int.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "qemu/module.h"
|
||||
@ -158,6 +159,14 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
s->crypt_method_header = header.crypt_method;
|
||||
if (s->crypt_method_header) {
|
||||
if (bdrv_uses_whitelist() &&
|
||||
s->crypt_method_header == QCOW_CRYPT_AES) {
|
||||
error_report("qcow built-in AES encryption is deprecated");
|
||||
error_printf("Support for it will be removed in a future release.\n"
|
||||
"You can use 'qemu-img convert' to switch to an\n"
|
||||
"unencrypted qcow image, or a LUKS raw image.\n");
|
||||
}
|
||||
|
||||
bs->encrypted = 1;
|
||||
}
|
||||
s->cluster_bits = header.cluster_bits;
|
||||
@ -795,8 +804,7 @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
}
|
||||
|
||||
qcow_blk = blk_new_open(filename, NULL, NULL,
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_PROTOCOL,
|
||||
&local_err);
|
||||
BDRV_O_RDWR | BDRV_O_PROTOCOL, &local_err);
|
||||
if (qcow_blk == NULL) {
|
||||
error_propagate(errp, local_err);
|
||||
ret = -EIO;
|
||||
|
@ -965,6 +965,14 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
s->crypt_method_header = header.crypt_method;
|
||||
if (s->crypt_method_header) {
|
||||
if (bdrv_uses_whitelist() &&
|
||||
s->crypt_method_header == QCOW_CRYPT_AES) {
|
||||
error_report("qcow2 built-in AES encryption is deprecated");
|
||||
error_printf("Support for it will be removed in a future release.\n"
|
||||
"You can use 'qemu-img convert' to switch to an\n"
|
||||
"unencrypted qcow2 image, or a LUKS raw image.\n");
|
||||
}
|
||||
|
||||
bs->encrypted = 1;
|
||||
}
|
||||
|
||||
@ -2160,8 +2168,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
||||
}
|
||||
|
||||
blk = blk_new_open(filename, NULL, NULL,
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_PROTOCOL,
|
||||
&local_err);
|
||||
BDRV_O_RDWR | BDRV_O_PROTOCOL, &local_err);
|
||||
if (blk == NULL) {
|
||||
error_propagate(errp, local_err);
|
||||
return -EIO;
|
||||
@ -2225,8 +2232,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
||||
options = qdict_new();
|
||||
qdict_put(options, "driver", qstring_from_str("qcow2"));
|
||||
blk = blk_new_open(filename, NULL, options,
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH,
|
||||
&local_err);
|
||||
BDRV_O_RDWR | BDRV_O_NO_FLUSH, &local_err);
|
||||
if (blk == NULL) {
|
||||
error_propagate(errp, local_err);
|
||||
ret = -EIO;
|
||||
@ -2287,8 +2293,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
||||
options = qdict_new();
|
||||
qdict_put(options, "driver", qstring_from_str("qcow2"));
|
||||
blk = blk_new_open(filename, NULL, options,
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_BACKING,
|
||||
&local_err);
|
||||
BDRV_O_RDWR | BDRV_O_NO_BACKING, &local_err);
|
||||
if (blk == NULL) {
|
||||
error_propagate(errp, local_err);
|
||||
ret = -EIO;
|
||||
|
@ -576,8 +576,7 @@ static int qed_create(const char *filename, uint32_t cluster_size,
|
||||
}
|
||||
|
||||
blk = blk_new_open(filename, NULL, NULL,
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_PROTOCOL,
|
||||
&local_err);
|
||||
BDRV_O_RDWR | BDRV_O_PROTOCOL, &local_err);
|
||||
if (blk == NULL) {
|
||||
error_propagate(errp, local_err);
|
||||
return -EIO;
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include <IOKit/storage/IOMedia.h>
|
||||
#include <IOKit/storage/IOCDMedia.h>
|
||||
//#include <IOKit/storage/IOCDTypes.h>
|
||||
#include <IOKit/storage/IODVDMedia.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#endif
|
||||
|
||||
@ -1966,33 +1967,47 @@ BlockDriver bdrv_file = {
|
||||
/* host device */
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
static kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator );
|
||||
static kern_return_t GetBSDPath(io_iterator_t mediaIterator, char *bsdPath,
|
||||
CFIndex maxPathSize, int flags);
|
||||
kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator )
|
||||
static char *FindEjectableOpticalMedia(io_iterator_t *mediaIterator)
|
||||
{
|
||||
kern_return_t kernResult;
|
||||
kern_return_t kernResult = KERN_FAILURE;
|
||||
mach_port_t masterPort;
|
||||
CFMutableDictionaryRef classesToMatch;
|
||||
const char *matching_array[] = {kIODVDMediaClass, kIOCDMediaClass};
|
||||
char *mediaType = NULL;
|
||||
|
||||
kernResult = IOMasterPort( MACH_PORT_NULL, &masterPort );
|
||||
if ( KERN_SUCCESS != kernResult ) {
|
||||
printf( "IOMasterPort returned %d\n", kernResult );
|
||||
}
|
||||
|
||||
classesToMatch = IOServiceMatching( kIOCDMediaClass );
|
||||
if ( classesToMatch == NULL ) {
|
||||
printf( "IOServiceMatching returned a NULL dictionary.\n" );
|
||||
} else {
|
||||
CFDictionarySetValue( classesToMatch, CFSTR( kIOMediaEjectableKey ), kCFBooleanTrue );
|
||||
int index;
|
||||
for (index = 0; index < ARRAY_SIZE(matching_array); index++) {
|
||||
classesToMatch = IOServiceMatching(matching_array[index]);
|
||||
if (classesToMatch == NULL) {
|
||||
error_report("IOServiceMatching returned NULL for %s",
|
||||
matching_array[index]);
|
||||
continue;
|
||||
}
|
||||
kernResult = IOServiceGetMatchingServices( masterPort, classesToMatch, mediaIterator );
|
||||
if ( KERN_SUCCESS != kernResult )
|
||||
{
|
||||
printf( "IOServiceGetMatchingServices returned %d\n", kernResult );
|
||||
CFDictionarySetValue(classesToMatch, CFSTR(kIOMediaEjectableKey),
|
||||
kCFBooleanTrue);
|
||||
kernResult = IOServiceGetMatchingServices(masterPort, classesToMatch,
|
||||
mediaIterator);
|
||||
if (kernResult != KERN_SUCCESS) {
|
||||
error_report("Note: IOServiceGetMatchingServices returned %d",
|
||||
kernResult);
|
||||
continue;
|
||||
}
|
||||
|
||||
return kernResult;
|
||||
/* If a match was found, leave the loop */
|
||||
if (*mediaIterator != 0) {
|
||||
DPRINTF("Matching using %s\n", matching_array[index]);
|
||||
mediaType = g_strdup(matching_array[index]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return mediaType;
|
||||
}
|
||||
|
||||
kern_return_t GetBSDPath(io_iterator_t mediaIterator, char *bsdPath,
|
||||
@ -2024,7 +2039,46 @@ kern_return_t GetBSDPath(io_iterator_t mediaIterator, char *bsdPath,
|
||||
return kernResult;
|
||||
}
|
||||
|
||||
#endif
|
||||
/* Sets up a real cdrom for use in QEMU */
|
||||
static bool setup_cdrom(char *bsd_path, Error **errp)
|
||||
{
|
||||
int index, num_of_test_partitions = 2, fd;
|
||||
char test_partition[MAXPATHLEN];
|
||||
bool partition_found = false;
|
||||
|
||||
/* look for a working partition */
|
||||
for (index = 0; index < num_of_test_partitions; index++) {
|
||||
snprintf(test_partition, sizeof(test_partition), "%ss%d", bsd_path,
|
||||
index);
|
||||
fd = qemu_open(test_partition, O_RDONLY | O_BINARY | O_LARGEFILE);
|
||||
if (fd >= 0) {
|
||||
partition_found = true;
|
||||
qemu_close(fd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* if a working partition on the device was not found */
|
||||
if (partition_found == false) {
|
||||
error_setg(errp, "Failed to find a working partition on disc");
|
||||
} else {
|
||||
DPRINTF("Using %s as optical disc\n", test_partition);
|
||||
pstrcpy(bsd_path, MAXPATHLEN, test_partition);
|
||||
}
|
||||
return partition_found;
|
||||
}
|
||||
|
||||
/* Prints directions on mounting and unmounting a device */
|
||||
static void print_unmounting_directions(const char *file_name)
|
||||
{
|
||||
error_report("If device %s is mounted on the desktop, unmount"
|
||||
" it first before using it in QEMU", file_name);
|
||||
error_report("Command to unmount device: diskutil unmountDisk %s",
|
||||
file_name);
|
||||
error_report("Command to mount device: diskutil mountDisk %s", file_name);
|
||||
}
|
||||
|
||||
#endif /* defined(__APPLE__) && defined(__MACH__) */
|
||||
|
||||
static int hdev_probe_device(const char *filename)
|
||||
{
|
||||
@ -2115,33 +2169,57 @@ static int hdev_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
const char *filename = qdict_get_str(options, "filename");
|
||||
char bsd_path[MAXPATHLEN] = "";
|
||||
bool error_occurred = false;
|
||||
|
||||
if (strstart(filename, "/dev/cdrom", NULL)) {
|
||||
kern_return_t kernResult;
|
||||
io_iterator_t mediaIterator;
|
||||
char bsdPath[ MAXPATHLEN ];
|
||||
int fd;
|
||||
/* If using a real cdrom */
|
||||
if (strcmp(filename, "/dev/cdrom") == 0) {
|
||||
char *mediaType = NULL;
|
||||
kern_return_t ret_val;
|
||||
io_iterator_t mediaIterator = 0;
|
||||
|
||||
kernResult = FindEjectableCDMedia( &mediaIterator );
|
||||
kernResult = GetBSDPath(mediaIterator, bsdPath, sizeof(bsdPath),
|
||||
flags);
|
||||
if ( bsdPath[ 0 ] != '\0' ) {
|
||||
strcat(bsdPath,"s0");
|
||||
/* some CDs don't have a partition 0 */
|
||||
fd = qemu_open(bsdPath, O_RDONLY | O_BINARY | O_LARGEFILE);
|
||||
if (fd < 0) {
|
||||
bsdPath[strlen(bsdPath)-1] = '1';
|
||||
} else {
|
||||
qemu_close(fd);
|
||||
}
|
||||
filename = bsdPath;
|
||||
qdict_put(options, "filename", qstring_from_str(filename));
|
||||
mediaType = FindEjectableOpticalMedia(&mediaIterator);
|
||||
if (mediaType == NULL) {
|
||||
error_setg(errp, "Please make sure your CD/DVD is in the optical"
|
||||
" drive");
|
||||
error_occurred = true;
|
||||
goto hdev_open_Mac_error;
|
||||
}
|
||||
|
||||
if ( mediaIterator )
|
||||
IOObjectRelease( mediaIterator );
|
||||
ret_val = GetBSDPath(mediaIterator, bsd_path, sizeof(bsd_path), flags);
|
||||
if (ret_val != KERN_SUCCESS) {
|
||||
error_setg(errp, "Could not get BSD path for optical drive");
|
||||
error_occurred = true;
|
||||
goto hdev_open_Mac_error;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If a real optical drive was not found */
|
||||
if (bsd_path[0] == '\0') {
|
||||
error_setg(errp, "Failed to obtain bsd path for optical drive");
|
||||
error_occurred = true;
|
||||
goto hdev_open_Mac_error;
|
||||
}
|
||||
|
||||
/* If using a cdrom disc and finding a partition on the disc failed */
|
||||
if (strncmp(mediaType, kIOCDMediaClass, 9) == 0 &&
|
||||
setup_cdrom(bsd_path, errp) == false) {
|
||||
print_unmounting_directions(bsd_path);
|
||||
error_occurred = true;
|
||||
goto hdev_open_Mac_error;
|
||||
}
|
||||
|
||||
qdict_put(options, "filename", qstring_from_str(bsd_path));
|
||||
|
||||
hdev_open_Mac_error:
|
||||
g_free(mediaType);
|
||||
if (mediaIterator) {
|
||||
IOObjectRelease(mediaIterator);
|
||||
}
|
||||
if (error_occurred) {
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
#endif /* defined(__APPLE__) && defined(__MACH__) */
|
||||
|
||||
s->type = FTYPE_FILE;
|
||||
|
||||
@ -2150,6 +2228,15 @@ static int hdev_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
if (*bsd_path) {
|
||||
filename = bsd_path;
|
||||
}
|
||||
/* if a physical device experienced an error while being opened */
|
||||
if (strncmp(filename, "/dev/", 5) == 0) {
|
||||
print_unmounting_directions(filename);
|
||||
}
|
||||
#endif /* defined(__APPLE__) && defined(__MACH__) */
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -57,8 +57,9 @@ static int coroutine_fn raw_co_readv(BlockDriverState *bs, int64_t sector_num,
|
||||
return bdrv_co_readv(bs->file->bs, sector_num, nb_sectors, qiov);
|
||||
}
|
||||
|
||||
static int coroutine_fn raw_co_writev(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors, QEMUIOVector *qiov)
|
||||
static int coroutine_fn
|
||||
raw_co_writev_flags(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
void *buf = NULL;
|
||||
BlockDriver *drv;
|
||||
@ -104,7 +105,8 @@ static int coroutine_fn raw_co_writev(BlockDriverState *bs, int64_t sector_num,
|
||||
}
|
||||
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
|
||||
ret = bdrv_co_writev(bs->file->bs, sector_num, nb_sectors, qiov);
|
||||
ret = bdrv_co_do_pwritev(bs->file->bs, sector_num * BDRV_SECTOR_SIZE,
|
||||
nb_sectors * BDRV_SECTOR_SIZE, qiov, flags);
|
||||
|
||||
fail:
|
||||
if (qiov == &local_qiov) {
|
||||
@ -114,6 +116,13 @@ fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int coroutine_fn
|
||||
raw_co_writev(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
|
||||
QEMUIOVector *qiov)
|
||||
{
|
||||
return raw_co_writev_flags(bs, sector_num, nb_sectors, qiov, 0);
|
||||
}
|
||||
|
||||
static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
int nb_sectors, int *pnum,
|
||||
@ -248,6 +257,8 @@ BlockDriver bdrv_raw = {
|
||||
.bdrv_create = &raw_create,
|
||||
.bdrv_co_readv = &raw_co_readv,
|
||||
.bdrv_co_writev = &raw_co_writev,
|
||||
.bdrv_co_writev_flags = &raw_co_writev_flags,
|
||||
.supported_write_flags = BDRV_REQ_FUA,
|
||||
.bdrv_co_write_zeroes = &raw_co_write_zeroes,
|
||||
.bdrv_co_discard = &raw_co_discard,
|
||||
.bdrv_co_get_block_status = &raw_co_get_block_status,
|
||||
|
@ -1648,8 +1648,7 @@ static int sd_prealloc(const char *filename, Error **errp)
|
||||
int ret;
|
||||
|
||||
blk = blk_new_open(filename, NULL, NULL,
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_PROTOCOL,
|
||||
errp);
|
||||
BDRV_O_RDWR | BDRV_O_PROTOCOL, errp);
|
||||
if (blk == NULL) {
|
||||
ret = -EIO;
|
||||
goto out_with_err_set;
|
||||
@ -1845,7 +1844,7 @@ static int sd_create(const char *filename, QemuOpts *opts,
|
||||
}
|
||||
|
||||
blk = blk_new_open(backing_file, NULL, NULL,
|
||||
BDRV_O_PROTOCOL | BDRV_O_CACHE_WB, errp);
|
||||
BDRV_O_PROTOCOL, errp);
|
||||
if (blk == NULL) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
|
@ -770,8 +770,7 @@ static int vdi_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
}
|
||||
|
||||
blk = blk_new_open(filename, NULL, NULL,
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_PROTOCOL,
|
||||
&local_err);
|
||||
BDRV_O_RDWR | BDRV_O_PROTOCOL, &local_err);
|
||||
if (blk == NULL) {
|
||||
error_propagate(errp, local_err);
|
||||
ret = -EIO;
|
||||
|
@ -1840,8 +1840,7 @@ static int vhdx_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
}
|
||||
|
||||
blk = blk_new_open(filename, NULL, NULL,
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_PROTOCOL,
|
||||
&local_err);
|
||||
BDRV_O_RDWR | BDRV_O_PROTOCOL, &local_err);
|
||||
if (blk == NULL) {
|
||||
error_propagate(errp, local_err);
|
||||
ret = -EIO;
|
||||
|
@ -1663,8 +1663,7 @@ static int vmdk_create_extent(const char *filename, int64_t filesize,
|
||||
}
|
||||
|
||||
blk = blk_new_open(filename, NULL, NULL,
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_PROTOCOL,
|
||||
&local_err);
|
||||
BDRV_O_RDWR | BDRV_O_PROTOCOL, &local_err);
|
||||
if (blk == NULL) {
|
||||
error_propagate(errp, local_err);
|
||||
ret = -EIO;
|
||||
@ -1948,7 +1947,7 @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
}
|
||||
|
||||
blk = blk_new_open(full_backing, NULL, NULL,
|
||||
BDRV_O_NO_BACKING | BDRV_O_CACHE_WB, errp);
|
||||
BDRV_O_NO_BACKING, errp);
|
||||
g_free(full_backing);
|
||||
if (blk == NULL) {
|
||||
ret = -EIO;
|
||||
@ -2020,8 +2019,7 @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
}
|
||||
|
||||
new_blk = blk_new_open(filename, NULL, NULL,
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_PROTOCOL,
|
||||
&local_err);
|
||||
BDRV_O_RDWR | BDRV_O_PROTOCOL, &local_err);
|
||||
if (new_blk == NULL) {
|
||||
error_propagate(errp, local_err);
|
||||
ret = -EIO;
|
||||
|
@ -890,8 +890,7 @@ static int vpc_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
}
|
||||
|
||||
blk = blk_new_open(filename, NULL, NULL,
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_PROTOCOL,
|
||||
&local_err);
|
||||
BDRV_O_RDWR | BDRV_O_PROTOCOL, &local_err);
|
||||
if (blk == NULL) {
|
||||
error_propagate(errp, local_err);
|
||||
ret = -EIO;
|
||||
|
@ -2957,8 +2957,7 @@ static int enable_write_target(BDRVVVFATState *s, Error **errp)
|
||||
options = qdict_new();
|
||||
qdict_put(options, "driver", qstring_from_str("qcow"));
|
||||
ret = bdrv_open(&s->qcow, s->qcow_filename, NULL, options,
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH,
|
||||
errp);
|
||||
BDRV_O_RDWR | BDRV_O_NO_FLUSH, errp);
|
||||
if (ret < 0) {
|
||||
goto err;
|
||||
}
|
||||
|
22
blockdev.c
22
blockdev.c
@ -469,6 +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;
|
||||
BlockBackend *blk;
|
||||
BlockDriverState *bs;
|
||||
ThrottleConfig cfg;
|
||||
@ -507,6 +508,8 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
|
||||
account_invalid = qemu_opt_get_bool(opts, "stats-account-invalid", true);
|
||||
account_failed = qemu_opt_get_bool(opts, "stats-account-failed", true);
|
||||
|
||||
writethrough = !qemu_opt_get_bool(opts, BDRV_OPT_CACHE_WB, true);
|
||||
|
||||
qdict_extract_subqdict(bs_opts, &interval_dict, "stats-intervals.");
|
||||
qdict_array_split(interval_dict, &interval_list);
|
||||
|
||||
@ -592,9 +595,9 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
|
||||
/* bdrv_open() defaults to the values in bdrv_flags (for compatibility
|
||||
* with other callers) rather than what we want as the real defaults.
|
||||
* Apply the defaults here instead. */
|
||||
qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_WB, "on");
|
||||
qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_DIRECT, "off");
|
||||
qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_NO_FLUSH, "off");
|
||||
assert((bdrv_flags & BDRV_O_CACHE_MASK) == 0);
|
||||
|
||||
if (runstate_check(RUN_STATE_INMIGRATE)) {
|
||||
bdrv_flags |= BDRV_O_INACTIVE;
|
||||
@ -630,6 +633,7 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
|
||||
}
|
||||
}
|
||||
|
||||
blk_set_enable_write_cache(blk, !writethrough);
|
||||
blk_set_on_error(blk, on_read_error, on_write_error);
|
||||
|
||||
if (!monitor_add_blk(blk, qemu_opts_id(opts), errp)) {
|
||||
@ -686,7 +690,6 @@ static BlockDriverState *bds_tree_init(QDict *bs_opts, Error **errp)
|
||||
/* bdrv_open() defaults to the values in bdrv_flags (for compatibility
|
||||
* with other callers) rather than what we want as the real defaults.
|
||||
* Apply the defaults here instead. */
|
||||
qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_WB, "on");
|
||||
qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_DIRECT, "off");
|
||||
qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_NO_FLUSH, "off");
|
||||
|
||||
@ -894,8 +897,9 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
|
||||
value = qemu_opt_get(all_opts, "cache");
|
||||
if (value) {
|
||||
int flags = 0;
|
||||
bool writethrough;
|
||||
|
||||
if (bdrv_parse_cache_flags(value, &flags) != 0) {
|
||||
if (bdrv_parse_cache_mode(value, &flags, &writethrough) != 0) {
|
||||
error_report("invalid cache option");
|
||||
return NULL;
|
||||
}
|
||||
@ -903,7 +907,7 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
|
||||
/* Specific options take precedence */
|
||||
if (!qemu_opt_get(all_opts, BDRV_OPT_CACHE_WB)) {
|
||||
qemu_opt_set_bool(all_opts, BDRV_OPT_CACHE_WB,
|
||||
!!(flags & BDRV_O_CACHE_WB), &error_abort);
|
||||
!writethrough, &error_abort);
|
||||
}
|
||||
if (!qemu_opt_get(all_opts, BDRV_OPT_CACHE_DIRECT)) {
|
||||
qemu_opt_set_bool(all_opts, BDRV_OPT_CACHE_DIRECT,
|
||||
@ -1743,6 +1747,7 @@ static void external_snapshot_prepare(BlkActionState *common,
|
||||
}
|
||||
|
||||
flags = state->old_bs->open_flags;
|
||||
flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | BDRV_O_COPY_ON_READ);
|
||||
|
||||
/* create new image w/backing file */
|
||||
mode = s->has_mode ? s->mode : NEW_IMAGE_MODE_ABSOLUTE_PATHS;
|
||||
@ -1813,8 +1818,10 @@ static void external_snapshot_commit(BlkActionState *common)
|
||||
/* We don't need (or want) to use the transactional
|
||||
* bdrv_reopen_multiple() across all the entries at once, because we
|
||||
* don't want to abort all of them if one of them fails the reopen */
|
||||
if (!state->old_bs->copy_on_read) {
|
||||
bdrv_reopen(state->old_bs, state->old_bs->open_flags & ~BDRV_O_RDWR,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void external_snapshot_abort(BlkActionState *common)
|
||||
@ -2869,9 +2876,6 @@ void hmp_drive_del(Monitor *mon, const QDict *qdict)
|
||||
|
||||
/* Make the BlockBackend and the attached BlockDriverState anonymous */
|
||||
monitor_remove_blk(blk);
|
||||
if (blk_bs(blk)) {
|
||||
bdrv_make_anon(blk_bs(blk));
|
||||
}
|
||||
|
||||
/* If this BlockBackend has a device attached to it, its refcount will be
|
||||
* decremented when the device is removed; otherwise we have to do so here.
|
||||
@ -4115,6 +4119,10 @@ QemuOptsList qemu_common_drive_opts = {
|
||||
.name = "aio",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "host AIO implementation (threads, native)",
|
||||
},{
|
||||
.name = BDRV_OPT_CACHE_WB,
|
||||
.type = QEMU_OPT_BOOL,
|
||||
.help = "Enable writeback mode",
|
||||
},{
|
||||
.name = "format",
|
||||
.type = QEMU_OPT_STRING,
|
||||
|
@ -175,3 +175,23 @@ Sometimes the block layer uses asynchronous callbacks for its internal purposes
|
||||
(like reading or writing VM snapshots or disk image cluster tables). In this
|
||||
case bottom halves are not marked as "replayable" and do not saved
|
||||
into the log.
|
||||
|
||||
Block devices
|
||||
-------------
|
||||
|
||||
Block devices record/replay module intercepts calls of
|
||||
bdrv coroutine functions at the top of block drivers stack.
|
||||
To record and replay block operations the drive must be configured
|
||||
as following:
|
||||
-drive file=disk.qcow,if=none,id=img-direct
|
||||
-drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay
|
||||
-device ide-hd,drive=img-blkreplay
|
||||
|
||||
blkreplay driver should be inserted between disk image and virtual driver
|
||||
controller. Therefore all disk requests may be recorded and replayed.
|
||||
|
||||
All block completion operations are added to the queue in the coroutines.
|
||||
Queue is flushed at checkpoints and information about processed requests
|
||||
is recorded to the log. In replay phase the queue is matched with
|
||||
events read from the log. Therefore block devices requests are processed
|
||||
deterministically.
|
||||
|
@ -889,12 +889,14 @@ static int blk_connect(struct XenDevice *xendev)
|
||||
struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
|
||||
int pers, index, qflags;
|
||||
bool readonly = true;
|
||||
bool writethrough = true;
|
||||
|
||||
/* read-only ? */
|
||||
if (blkdev->directiosafe) {
|
||||
qflags = BDRV_O_NOCACHE | BDRV_O_NATIVE_AIO;
|
||||
} else {
|
||||
qflags = BDRV_O_CACHE_WB;
|
||||
qflags = 0;
|
||||
writethrough = false;
|
||||
}
|
||||
if (strcmp(blkdev->mode, "w") == 0) {
|
||||
qflags |= BDRV_O_RDWR;
|
||||
@ -926,6 +928,7 @@ static int blk_connect(struct XenDevice *xendev)
|
||||
error_free(local_err);
|
||||
return -1;
|
||||
}
|
||||
blk_set_enable_write_cache(blkdev->blk, !writethrough);
|
||||
} else {
|
||||
/* setup via qemu cmdline -> already setup for us */
|
||||
xen_be_printf(&blkdev->xendev, 2, "get configured bdrv (cmdline setup)\n");
|
||||
|
@ -64,6 +64,7 @@ typedef enum {
|
||||
*/
|
||||
BDRV_REQ_MAY_UNMAP = 0x4,
|
||||
BDRV_REQ_NO_SERIALISING = 0x8,
|
||||
BDRV_REQ_FUA = 0x10,
|
||||
} BdrvRequestFlags;
|
||||
|
||||
typedef struct BlockSizes {
|
||||
@ -81,7 +82,6 @@ typedef struct HDGeometry {
|
||||
#define BDRV_O_SNAPSHOT 0x0008 /* open the file read only and save writes in a snapshot */
|
||||
#define BDRV_O_TEMPORARY 0x0010 /* delete the file after use */
|
||||
#define BDRV_O_NOCACHE 0x0020 /* do not use the host page cache */
|
||||
#define BDRV_O_CACHE_WB 0x0040 /* use write-back caching */
|
||||
#define BDRV_O_NATIVE_AIO 0x0080 /* use native AIO instead of the thread pool */
|
||||
#define BDRV_O_NO_BACKING 0x0100 /* don't open the backing file */
|
||||
#define BDRV_O_NO_FLUSH 0x0200 /* disable flushing on this disk */
|
||||
@ -93,8 +93,9 @@ typedef struct HDGeometry {
|
||||
#define BDRV_O_PROTOCOL 0x8000 /* if no block driver is explicitly given:
|
||||
select an appropriate protocol driver,
|
||||
ignoring the format layer */
|
||||
#define BDRV_O_NO_IO 0x10000 /* don't initialize for I/O */
|
||||
|
||||
#define BDRV_O_CACHE_MASK (BDRV_O_NOCACHE | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH)
|
||||
#define BDRV_O_CACHE_MASK (BDRV_O_NOCACHE | BDRV_O_NO_FLUSH)
|
||||
|
||||
|
||||
/* Option names of options parsed by the block layer */
|
||||
@ -192,6 +193,7 @@ void bdrv_io_limits_update_group(BlockDriverState *bs, const char *group);
|
||||
|
||||
void bdrv_init(void);
|
||||
void bdrv_init_with_whitelist(void);
|
||||
bool bdrv_uses_whitelist(void);
|
||||
BlockDriver *bdrv_find_protocol(const char *filename,
|
||||
bool allow_protocol_prefix,
|
||||
Error **errp);
|
||||
@ -201,12 +203,11 @@ int bdrv_create(BlockDriver *drv, const char* filename,
|
||||
int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp);
|
||||
BlockDriverState *bdrv_new_root(void);
|
||||
BlockDriverState *bdrv_new(void);
|
||||
void bdrv_make_anon(BlockDriverState *bs);
|
||||
void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top);
|
||||
void bdrv_replace_in_backing_chain(BlockDriverState *old,
|
||||
BlockDriverState *new);
|
||||
|
||||
int bdrv_parse_cache_flags(const char *mode, int *flags);
|
||||
int bdrv_parse_cache_mode(const char *mode, int *flags, bool *writethrough);
|
||||
int bdrv_parse_discard_flags(const char *mode, int *flags);
|
||||
BdrvChild *bdrv_open_child(const char *filename,
|
||||
QDict *options, const char *bdref_key,
|
||||
@ -394,8 +395,6 @@ int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base,
|
||||
|
||||
int bdrv_is_read_only(BlockDriverState *bs);
|
||||
int bdrv_is_sg(BlockDriverState *bs);
|
||||
int bdrv_enable_write_cache(BlockDriverState *bs);
|
||||
void bdrv_set_enable_write_cache(BlockDriverState *bs, bool wce);
|
||||
bool bdrv_is_inserted(BlockDriverState *bs);
|
||||
int bdrv_media_changed(BlockDriverState *bs);
|
||||
void bdrv_lock_medium(BlockDriverState *bs, bool locked);
|
||||
|
@ -155,6 +155,11 @@ struct BlockDriver {
|
||||
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
|
||||
int coroutine_fn (*bdrv_co_writev)(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
|
||||
int coroutine_fn (*bdrv_co_writev_flags)(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov, int flags);
|
||||
|
||||
int supported_write_flags;
|
||||
|
||||
/*
|
||||
* Efficiently zero a region of the disk image. Typically an image format
|
||||
* would use a compact metadata representation to implement this. This
|
||||
@ -175,6 +180,13 @@ struct BlockDriver {
|
||||
void (*bdrv_invalidate_cache)(BlockDriverState *bs, Error **errp);
|
||||
int (*bdrv_inactivate)(BlockDriverState *bs);
|
||||
|
||||
/*
|
||||
* Flushes all data for all layers by calling bdrv_co_flush for underlying
|
||||
* layers, if needed. This function is needed for deterministic
|
||||
* synchronization of the flush finishing callback.
|
||||
*/
|
||||
int coroutine_fn (*bdrv_co_flush)(BlockDriverState *bs);
|
||||
|
||||
/*
|
||||
* Flushes all data that was already written to the OS all the way down to
|
||||
* the disk (for example raw-posix calls fsync()).
|
||||
@ -435,9 +447,6 @@ struct BlockDriverState {
|
||||
/* Alignment requirement for offset/length of I/O requests */
|
||||
unsigned int request_alignment;
|
||||
|
||||
/* do we need to tell the quest if we have a volatile write cache? */
|
||||
int enable_write_cache;
|
||||
|
||||
/* the following member gives a name to every node on the bs graph. */
|
||||
char node_name[32];
|
||||
/* element of the list of named nodes building the graph */
|
||||
@ -704,8 +713,6 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
|
||||
const BdrvChildRole *child_role);
|
||||
void bdrv_root_unref_child(BdrvChild *child);
|
||||
|
||||
void blk_set_bs(BlockBackend *blk, BlockDriverState *bs);
|
||||
|
||||
void blk_dev_change_media_cb(BlockBackend *blk, bool load);
|
||||
bool blk_dev_has_removable_media(BlockBackend *blk);
|
||||
bool blk_dev_has_tray(BlockBackend *blk);
|
||||
|
@ -29,7 +29,8 @@
|
||||
#include "block/block.h"
|
||||
#include "block/snapshot.h"
|
||||
|
||||
BlockDeviceInfo *bdrv_block_device_info(BlockDriverState *bs, Error **errp);
|
||||
BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
|
||||
BlockDriverState *bs, Error **errp);
|
||||
int bdrv_query_snapshot_info_list(BlockDriverState *bs,
|
||||
SnapshotInfoList **p_list,
|
||||
Error **errp);
|
||||
|
@ -113,6 +113,8 @@ void replay_bh_schedule_event(QEMUBH *bh);
|
||||
void replay_input_event(QemuConsole *src, InputEvent *evt);
|
||||
/*! Adds input sync event to the queue */
|
||||
void replay_input_sync_event(void);
|
||||
/*! Adds block layer event to the queue */
|
||||
void replay_block_event(QEMUBH *bh, uint64_t id);
|
||||
|
||||
/* Character device */
|
||||
|
||||
|
@ -242,11 +242,12 @@
|
||||
# @drv: the name of the block format used to open the backing device. As of
|
||||
# 0.14.0 this can be: 'blkdebug', 'bochs', 'cloop', 'cow', 'dmg',
|
||||
# 'file', 'file', 'ftp', 'ftps', 'host_cdrom', 'host_device',
|
||||
# 'http', 'https', 'nbd', 'parallels', 'qcow',
|
||||
# 'http', 'https', 'luks', 'nbd', 'parallels', 'qcow',
|
||||
# 'qcow2', 'raw', 'tftp', 'vdi', 'vmdk', 'vpc', 'vvfat'
|
||||
# 2.2: 'archipelago' added, 'cow' dropped
|
||||
# 2.3: 'host_floppy' deprecated
|
||||
# 2.5: 'host_floppy' dropped
|
||||
# 2.6: 'luks' added
|
||||
#
|
||||
# @backing_file: #optional the name of the backing file (for copy-on-write)
|
||||
#
|
||||
@ -1614,7 +1615,6 @@
|
||||
#
|
||||
# Includes cache-related options for block devices
|
||||
#
|
||||
# @writeback: #optional enables writeback mode for any caches (default: true)
|
||||
# @direct: #optional enables use of O_DIRECT (bypass the host page cache;
|
||||
# default: false)
|
||||
# @no-flush: #optional ignore any flush requests for the device (default:
|
||||
@ -1623,8 +1623,7 @@
|
||||
# Since: 1.7
|
||||
##
|
||||
{ 'struct': 'BlockdevCacheOptions',
|
||||
'data': { '*writeback': 'bool',
|
||||
'*direct': 'bool',
|
||||
'data': { '*direct': 'bool',
|
||||
'*no-flush': 'bool' } }
|
||||
|
||||
##
|
||||
@ -1639,7 +1638,7 @@
|
||||
{ 'enum': 'BlockdevDriver',
|
||||
'data': [ 'archipelago', 'blkdebug', 'blkverify', 'bochs', 'cloop',
|
||||
'dmg', 'file', 'ftp', 'ftps', 'host_cdrom', 'host_device',
|
||||
'http', 'https', 'null-aio', 'null-co', 'parallels',
|
||||
'http', 'https', 'luks', 'null-aio', 'null-co', 'parallels',
|
||||
'qcow', 'qcow2', 'qed', 'quorum', 'raw', 'tftp', 'vdi', 'vhdx',
|
||||
'vmdk', 'vpc', 'vvfat' ] }
|
||||
|
||||
@ -1705,6 +1704,22 @@
|
||||
{ 'struct': 'BlockdevOptionsGenericFormat',
|
||||
'data': { 'file': 'BlockdevRef' } }
|
||||
|
||||
##
|
||||
# @BlockdevOptionsLUKS
|
||||
#
|
||||
# Driver specific block device options for LUKS.
|
||||
#
|
||||
# @key-secret: #optional the ID of a QCryptoSecret object providing
|
||||
# the decryption key (since 2.6). Mandatory except when
|
||||
# doing a metadata-only probe of the image.
|
||||
#
|
||||
# Since: 2.6
|
||||
##
|
||||
{ 'struct': 'BlockdevOptionsLUKS',
|
||||
'base': 'BlockdevOptionsGenericFormat',
|
||||
'data': { '*key-secret': 'str' } }
|
||||
|
||||
|
||||
##
|
||||
# @BlockdevOptionsGenericCOWFormat
|
||||
#
|
||||
@ -2085,6 +2100,7 @@
|
||||
'http': 'BlockdevOptionsFile',
|
||||
'https': 'BlockdevOptionsFile',
|
||||
# TODO iscsi: Wait for structured options
|
||||
'luks': 'BlockdevOptionsLUKS',
|
||||
# TODO nbd: Should take InetSocketAddress for 'host'?
|
||||
# TODO nfs: Wait for structured options
|
||||
'null-aio': 'BlockdevOptionsNull',
|
||||
|
110
qemu-img.c
110
qemu-img.c
@ -59,8 +59,7 @@ typedef enum OutputFormat {
|
||||
OFORMAT_HUMAN,
|
||||
} OutputFormat;
|
||||
|
||||
/* Default to cache=writeback as data integrity is not important for qemu-tcg. */
|
||||
#define BDRV_O_FLAGS BDRV_O_CACHE_WB
|
||||
/* Default to cache=writeback as data integrity is not important for qemu-img */
|
||||
#define BDRV_DEFAULT_CACHE "writeback"
|
||||
|
||||
static void format_print(void *opaque, const char *name)
|
||||
@ -225,13 +224,14 @@ static int print_block_option_help(const char *filename, const char *fmt)
|
||||
|
||||
|
||||
static int img_open_password(BlockBackend *blk, const char *filename,
|
||||
bool require_io, bool quiet)
|
||||
int flags, bool quiet)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
char password[256];
|
||||
|
||||
bs = blk_bs(blk);
|
||||
if (bdrv_is_encrypted(bs) && require_io) {
|
||||
if (bdrv_is_encrypted(bs) && bdrv_key_required(bs) &&
|
||||
!(flags & BDRV_O_NO_IO)) {
|
||||
qprintf(quiet, "Disk image '%s' is encrypted.\n", filename);
|
||||
if (qemu_read_password(password, sizeof(password)) < 0) {
|
||||
error_report("No password given");
|
||||
@ -247,8 +247,8 @@ static int img_open_password(BlockBackend *blk, const char *filename,
|
||||
|
||||
|
||||
static BlockBackend *img_open_opts(const char *optstr,
|
||||
QemuOpts *opts, int flags,
|
||||
bool require_io, bool quiet)
|
||||
QemuOpts *opts, int flags, bool writethrough,
|
||||
bool quiet)
|
||||
{
|
||||
QDict *options;
|
||||
Error *local_err = NULL;
|
||||
@ -259,8 +259,9 @@ static BlockBackend *img_open_opts(const char *optstr,
|
||||
error_reportf_err(local_err, "Could not open '%s'", optstr);
|
||||
return NULL;
|
||||
}
|
||||
blk_set_enable_write_cache(blk, !writethrough);
|
||||
|
||||
if (img_open_password(blk, optstr, require_io, quiet) < 0) {
|
||||
if (img_open_password(blk, optstr, flags, quiet) < 0) {
|
||||
blk_unref(blk);
|
||||
return NULL;
|
||||
}
|
||||
@ -269,7 +270,7 @@ static BlockBackend *img_open_opts(const char *optstr,
|
||||
|
||||
static BlockBackend *img_open_file(const char *filename,
|
||||
const char *fmt, int flags,
|
||||
bool require_io, bool quiet)
|
||||
bool writethrough, bool quiet)
|
||||
{
|
||||
BlockBackend *blk;
|
||||
Error *local_err = NULL;
|
||||
@ -285,8 +286,9 @@ static BlockBackend *img_open_file(const char *filename,
|
||||
error_reportf_err(local_err, "Could not open '%s': ", filename);
|
||||
return NULL;
|
||||
}
|
||||
blk_set_enable_write_cache(blk, !writethrough);
|
||||
|
||||
if (img_open_password(blk, filename, require_io, quiet) < 0) {
|
||||
if (img_open_password(blk, filename, flags, quiet) < 0) {
|
||||
blk_unref(blk);
|
||||
return NULL;
|
||||
}
|
||||
@ -296,8 +298,8 @@ static BlockBackend *img_open_file(const char *filename,
|
||||
|
||||
static BlockBackend *img_open(bool image_opts,
|
||||
const char *filename,
|
||||
const char *fmt, int flags,
|
||||
bool require_io, bool quiet)
|
||||
const char *fmt, int flags, bool writethrough,
|
||||
bool quiet)
|
||||
{
|
||||
BlockBackend *blk;
|
||||
if (image_opts) {
|
||||
@ -311,9 +313,9 @@ static BlockBackend *img_open(bool image_opts,
|
||||
if (!opts) {
|
||||
return NULL;
|
||||
}
|
||||
blk = img_open_opts(filename, opts, flags, true, quiet);
|
||||
blk = img_open_opts(filename, opts, flags, writethrough, quiet);
|
||||
} else {
|
||||
blk = img_open_file(filename, fmt, flags, true, quiet);
|
||||
blk = img_open_file(filename, fmt, flags, writethrough, quiet);
|
||||
}
|
||||
return blk;
|
||||
}
|
||||
@ -461,7 +463,7 @@ static int img_create(int argc, char **argv)
|
||||
}
|
||||
|
||||
bdrv_img_create(filename, fmt, base_filename, base_fmt,
|
||||
options, img_size, BDRV_O_FLAGS, &local_err, quiet);
|
||||
options, img_size, 0, &local_err, quiet);
|
||||
if (local_err) {
|
||||
error_reportf_err(local_err, "%s: ", filename);
|
||||
goto fail;
|
||||
@ -591,7 +593,8 @@ static int img_check(int argc, char **argv)
|
||||
BlockBackend *blk;
|
||||
BlockDriverState *bs;
|
||||
int fix = 0;
|
||||
int flags = BDRV_O_FLAGS | BDRV_O_CHECK;
|
||||
int flags = BDRV_O_CHECK;
|
||||
bool writethrough;
|
||||
ImageCheck *check;
|
||||
bool quiet = false;
|
||||
Error *local_err = NULL;
|
||||
@ -600,6 +603,7 @@ static int img_check(int argc, char **argv)
|
||||
fmt = NULL;
|
||||
output = NULL;
|
||||
cache = BDRV_DEFAULT_CACHE;
|
||||
|
||||
for(;;) {
|
||||
int option_index = 0;
|
||||
static const struct option long_options[] = {
|
||||
@ -679,13 +683,13 @@ static int img_check(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = bdrv_parse_cache_flags(cache, &flags);
|
||||
ret = bdrv_parse_cache_mode(cache, &flags, &writethrough);
|
||||
if (ret < 0) {
|
||||
error_report("Invalid source cache option: %s", cache);
|
||||
return 1;
|
||||
}
|
||||
|
||||
blk = img_open(image_opts, filename, fmt, flags, true, quiet);
|
||||
blk = img_open(image_opts, filename, fmt, flags, writethrough, quiet);
|
||||
if (!blk) {
|
||||
return 1;
|
||||
}
|
||||
@ -795,6 +799,7 @@ static int img_commit(int argc, char **argv)
|
||||
BlockBackend *blk;
|
||||
BlockDriverState *bs, *base_bs;
|
||||
bool progress = false, quiet = false, drop = false;
|
||||
bool writethrough;
|
||||
Error *local_err = NULL;
|
||||
CommonBlockJobCBInfo cbi;
|
||||
bool image_opts = false;
|
||||
@ -871,13 +876,13 @@ static int img_commit(int argc, char **argv)
|
||||
}
|
||||
|
||||
flags = BDRV_O_RDWR | BDRV_O_UNMAP;
|
||||
ret = bdrv_parse_cache_flags(cache, &flags);
|
||||
ret = bdrv_parse_cache_mode(cache, &flags, &writethrough);
|
||||
if (ret < 0) {
|
||||
error_report("Invalid cache option: %s", cache);
|
||||
return 1;
|
||||
}
|
||||
|
||||
blk = img_open(image_opts, filename, fmt, flags, true, quiet);
|
||||
blk = img_open(image_opts, filename, fmt, flags, writethrough, quiet);
|
||||
if (!blk) {
|
||||
return 1;
|
||||
}
|
||||
@ -1121,6 +1126,7 @@ static int img_compare(int argc, char **argv)
|
||||
int ret = 0; /* return value - 0 Ident, 1 Different, >1 Error */
|
||||
bool progress = false, quiet = false, strict = false;
|
||||
int flags;
|
||||
bool writethrough;
|
||||
int64_t total_sectors;
|
||||
int64_t sector_num = 0;
|
||||
int64_t nb_sectors;
|
||||
@ -1203,21 +1209,21 @@ static int img_compare(int argc, char **argv)
|
||||
/* Initialize before goto out */
|
||||
qemu_progress_init(progress, 2.0);
|
||||
|
||||
flags = BDRV_O_FLAGS;
|
||||
ret = bdrv_parse_cache_flags(cache, &flags);
|
||||
flags = 0;
|
||||
ret = bdrv_parse_cache_mode(cache, &flags, &writethrough);
|
||||
if (ret < 0) {
|
||||
error_report("Invalid source cache option: %s", cache);
|
||||
ret = 2;
|
||||
goto out3;
|
||||
}
|
||||
|
||||
blk1 = img_open(image_opts, filename1, fmt1, flags, true, quiet);
|
||||
blk1 = img_open(image_opts, filename1, fmt1, flags, writethrough, quiet);
|
||||
if (!blk1) {
|
||||
ret = 2;
|
||||
goto out3;
|
||||
}
|
||||
|
||||
blk2 = img_open(image_opts, filename2, fmt2, flags, true, quiet);
|
||||
blk2 = img_open(image_opts, filename2, fmt2, flags, writethrough, quiet);
|
||||
if (!blk2) {
|
||||
ret = 2;
|
||||
goto out2;
|
||||
@ -1508,10 +1514,6 @@ static int convert_read(ImgConvertState *s, int64_t sector_num, int nb_sectors,
|
||||
int n;
|
||||
int ret;
|
||||
|
||||
if (s->status == BLK_ZERO || s->status == BLK_BACKING_FILE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(nb_sectors <= s->buf_sectors);
|
||||
while (nb_sectors > 0) {
|
||||
BlockBackend *blk;
|
||||
@ -1649,7 +1651,8 @@ static int convert_do_copy(ImgConvertState *s)
|
||||
ret = n;
|
||||
goto fail;
|
||||
}
|
||||
if (s->status == BLK_DATA) {
|
||||
if (s->status == BLK_DATA || (!s->min_sparse && s->status == BLK_ZERO))
|
||||
{
|
||||
s->allocated_sectors += n;
|
||||
}
|
||||
sector_num += n;
|
||||
@ -1669,18 +1672,25 @@ static int convert_do_copy(ImgConvertState *s)
|
||||
ret = n;
|
||||
goto fail;
|
||||
}
|
||||
if (s->status == BLK_DATA) {
|
||||
if (s->status == BLK_DATA || (!s->min_sparse && s->status == BLK_ZERO))
|
||||
{
|
||||
allocated_done += n;
|
||||
qemu_progress_print(100.0 * allocated_done / s->allocated_sectors,
|
||||
0);
|
||||
}
|
||||
|
||||
if (s->status == BLK_DATA) {
|
||||
ret = convert_read(s, sector_num, n, buf);
|
||||
if (ret < 0) {
|
||||
error_report("error while reading sector %" PRId64
|
||||
": %s", sector_num, strerror(-ret));
|
||||
goto fail;
|
||||
}
|
||||
} else if (!s->min_sparse && s->status == BLK_ZERO) {
|
||||
n = MIN(n, s->buf_sectors);
|
||||
memset(buf, 0, n * BDRV_SECTOR_SIZE);
|
||||
s->status = BLK_DATA;
|
||||
}
|
||||
|
||||
ret = convert_write(s, sector_num, n, buf);
|
||||
if (ret < 0) {
|
||||
@ -1711,6 +1721,7 @@ static int img_convert(int argc, char **argv)
|
||||
int c, bs_n, bs_i, compress, cluster_sectors, skip_create;
|
||||
int64_t ret = 0;
|
||||
int progress = 0, flags, src_flags;
|
||||
bool writethrough, src_writethrough;
|
||||
const char *fmt, *out_fmt, *cache, *src_cache, *out_baseimg, *out_filename;
|
||||
BlockDriver *drv, *proto_drv;
|
||||
BlockBackend **blk = NULL, *out_blk = NULL;
|
||||
@ -1883,8 +1894,8 @@ static int img_convert(int argc, char **argv)
|
||||
goto out;
|
||||
}
|
||||
|
||||
src_flags = BDRV_O_FLAGS;
|
||||
ret = bdrv_parse_cache_flags(src_cache, &src_flags);
|
||||
src_flags = 0;
|
||||
ret = bdrv_parse_cache_mode(src_cache, &src_flags, &src_writethrough);
|
||||
if (ret < 0) {
|
||||
error_report("Invalid source cache option: %s", src_cache);
|
||||
goto out;
|
||||
@ -1899,7 +1910,7 @@ static int img_convert(int argc, char **argv)
|
||||
total_sectors = 0;
|
||||
for (bs_i = 0; bs_i < bs_n; bs_i++) {
|
||||
blk[bs_i] = img_open(image_opts, argv[optind + bs_i],
|
||||
fmt, src_flags, true, quiet);
|
||||
fmt, src_flags, src_writethrough, quiet);
|
||||
if (!blk[bs_i]) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
@ -2033,7 +2044,7 @@ static int img_convert(int argc, char **argv)
|
||||
}
|
||||
|
||||
flags = min_sparse ? (BDRV_O_RDWR | BDRV_O_UNMAP) : BDRV_O_RDWR;
|
||||
ret = bdrv_parse_cache_flags(cache, &flags);
|
||||
ret = bdrv_parse_cache_mode(cache, &flags, &writethrough);
|
||||
if (ret < 0) {
|
||||
error_report("Invalid cache option: %s", cache);
|
||||
goto out;
|
||||
@ -2044,7 +2055,7 @@ static int img_convert(int argc, char **argv)
|
||||
* the bdrv_create() call which takes different params.
|
||||
* Not critical right now, so fix can wait...
|
||||
*/
|
||||
out_blk = img_open_file(out_filename, out_fmt, flags, true, quiet);
|
||||
out_blk = img_open_file(out_filename, out_fmt, flags, writethrough, quiet);
|
||||
if (!out_blk) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
@ -2236,8 +2247,7 @@ static ImageInfoList *collect_image_info_list(bool image_opts,
|
||||
g_hash_table_insert(filenames, (gpointer)filename, NULL);
|
||||
|
||||
blk = img_open(image_opts, filename, fmt,
|
||||
BDRV_O_FLAGS | BDRV_O_NO_BACKING,
|
||||
false, false);
|
||||
BDRV_O_NO_BACKING | BDRV_O_NO_IO, false, false);
|
||||
if (!blk) {
|
||||
goto err;
|
||||
}
|
||||
@ -2567,7 +2577,7 @@ static int img_map(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
blk = img_open(image_opts, filename, fmt, BDRV_O_FLAGS, true, false);
|
||||
blk = img_open(image_opts, filename, fmt, 0, false, false);
|
||||
if (!blk) {
|
||||
return 1;
|
||||
}
|
||||
@ -2631,7 +2641,7 @@ static int img_snapshot(int argc, char **argv)
|
||||
Error *err = NULL;
|
||||
bool image_opts = false;
|
||||
|
||||
bdrv_oflags = BDRV_O_FLAGS | BDRV_O_RDWR;
|
||||
bdrv_oflags = BDRV_O_RDWR;
|
||||
/* Parse commandline parameters */
|
||||
for(;;) {
|
||||
static const struct option long_options[] = {
|
||||
@ -2712,7 +2722,7 @@ static int img_snapshot(int argc, char **argv)
|
||||
}
|
||||
|
||||
/* Open the image */
|
||||
blk = img_open(image_opts, filename, NULL, bdrv_oflags, true, quiet);
|
||||
blk = img_open(image_opts, filename, NULL, bdrv_oflags, false, quiet);
|
||||
if (!blk) {
|
||||
return 1;
|
||||
}
|
||||
@ -2774,6 +2784,7 @@ static int img_rebase(int argc, char **argv)
|
||||
char *filename;
|
||||
const char *fmt, *cache, *src_cache, *out_basefmt, *out_baseimg;
|
||||
int c, flags, src_flags, ret;
|
||||
bool writethrough, src_writethrough;
|
||||
int unsafe = 0;
|
||||
int progress = 0;
|
||||
bool quiet = false;
|
||||
@ -2864,26 +2875,30 @@ static int img_rebase(int argc, char **argv)
|
||||
qemu_progress_print(0, 100);
|
||||
|
||||
flags = BDRV_O_RDWR | (unsafe ? BDRV_O_NO_BACKING : 0);
|
||||
ret = bdrv_parse_cache_flags(cache, &flags);
|
||||
ret = bdrv_parse_cache_mode(cache, &flags, &writethrough);
|
||||
if (ret < 0) {
|
||||
error_report("Invalid cache option: %s", cache);
|
||||
goto out;
|
||||
}
|
||||
|
||||
src_flags = BDRV_O_FLAGS;
|
||||
ret = bdrv_parse_cache_flags(src_cache, &src_flags);
|
||||
src_flags = 0;
|
||||
ret = bdrv_parse_cache_mode(src_cache, &src_flags, &src_writethrough);
|
||||
if (ret < 0) {
|
||||
error_report("Invalid source cache option: %s", src_cache);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* The source files are opened read-only, don't care about WCE */
|
||||
assert((src_flags & BDRV_O_RDWR) == 0);
|
||||
(void) src_writethrough;
|
||||
|
||||
/*
|
||||
* Open the images.
|
||||
*
|
||||
* Ignore the old backing file for unsafe rebase in case we want to correct
|
||||
* the reference to a renamed or moved backing file.
|
||||
*/
|
||||
blk = img_open(image_opts, filename, fmt, flags, true, quiet);
|
||||
blk = img_open(image_opts, filename, fmt, flags, writethrough, quiet);
|
||||
if (!blk) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
@ -3221,7 +3236,7 @@ static int img_resize(int argc, char **argv)
|
||||
qemu_opts_del(param);
|
||||
|
||||
blk = img_open(image_opts, filename, fmt,
|
||||
BDRV_O_FLAGS | BDRV_O_RDWR, true, quiet);
|
||||
BDRV_O_RDWR, false, quiet);
|
||||
if (!blk) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
@ -3277,6 +3292,7 @@ static int img_amend(int argc, char **argv)
|
||||
QemuOpts *opts = NULL;
|
||||
const char *fmt = NULL, *filename, *cache;
|
||||
int flags;
|
||||
bool writethrough;
|
||||
bool quiet = false, progress = false;
|
||||
BlockBackend *blk = NULL;
|
||||
BlockDriverState *bs = NULL;
|
||||
@ -3373,14 +3389,14 @@ static int img_amend(int argc, char **argv)
|
||||
goto out;
|
||||
}
|
||||
|
||||
flags = BDRV_O_FLAGS | BDRV_O_RDWR;
|
||||
ret = bdrv_parse_cache_flags(cache, &flags);
|
||||
flags = BDRV_O_RDWR;
|
||||
ret = bdrv_parse_cache_mode(cache, &flags, &writethrough);
|
||||
if (ret < 0) {
|
||||
error_report("Invalid cache option: %s", cache);
|
||||
goto out;
|
||||
}
|
||||
|
||||
blk = img_open(image_opts, filename, fmt, flags, true, quiet);
|
||||
blk = img_open(image_opts, filename, fmt, flags, writethrough, quiet);
|
||||
if (!blk) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
|
@ -2106,6 +2106,7 @@ static int reopen_f(BlockBackend *blk, int argc, char **argv)
|
||||
QDict *opts;
|
||||
int c;
|
||||
int flags = bs->open_flags;
|
||||
bool writethrough = !blk_enable_write_cache(blk);
|
||||
|
||||
BlockReopenQueue *brq;
|
||||
Error *local_err = NULL;
|
||||
@ -2113,7 +2114,7 @@ static int reopen_f(BlockBackend *blk, int argc, char **argv)
|
||||
while ((c = getopt(argc, argv, "c:o:r")) != -1) {
|
||||
switch (c) {
|
||||
case 'c':
|
||||
if (bdrv_parse_cache_flags(optarg, &flags) < 0) {
|
||||
if (bdrv_parse_cache_mode(optarg, &flags, &writethrough) < 0) {
|
||||
error_report("Invalid cache option: %s", optarg);
|
||||
return 0;
|
||||
}
|
||||
@ -2138,6 +2139,14 @@ static int reopen_f(BlockBackend *blk, int argc, char **argv)
|
||||
return qemuio_command_usage(&reopen_cmd);
|
||||
}
|
||||
|
||||
if (writethrough != blk_enable_write_cache(blk) &&
|
||||
blk_get_attached_dev(blk))
|
||||
{
|
||||
error_report("Cannot change cache.writeback: Device attached");
|
||||
qemu_opts_reset(&reopen_opts);
|
||||
return 0;
|
||||
}
|
||||
|
||||
qopts = qemu_opts_find(&reopen_opts, NULL);
|
||||
opts = qopts ? qemu_opts_to_qdict(qopts, NULL) : NULL;
|
||||
qemu_opts_reset(&reopen_opts);
|
||||
@ -2146,6 +2155,8 @@ static int reopen_f(BlockBackend *blk, int argc, char **argv)
|
||||
bdrv_reopen_multiple(brq, &local_err);
|
||||
if (local_err) {
|
||||
error_report_err(local_err);
|
||||
} else {
|
||||
blk_set_enable_write_cache(blk, !writethrough);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
23
qemu-io.c
23
qemu-io.c
@ -51,7 +51,7 @@ static const cmdinfo_t close_cmd = {
|
||||
.oneline = "close the current open file",
|
||||
};
|
||||
|
||||
static int openfile(char *name, int flags, QDict *opts)
|
||||
static int openfile(char *name, int flags, bool writethrough, QDict *opts)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
BlockDriverState *bs;
|
||||
@ -70,7 +70,7 @@ static int openfile(char *name, int flags, QDict *opts)
|
||||
}
|
||||
|
||||
bs = blk_bs(qemuio_blk);
|
||||
if (bdrv_is_encrypted(bs)) {
|
||||
if (bdrv_is_encrypted(bs) && bdrv_key_required(bs)) {
|
||||
char password[256];
|
||||
printf("Disk image '%s' is encrypted.\n", name);
|
||||
if (qemu_read_password(password, sizeof(password)) < 0) {
|
||||
@ -83,6 +83,7 @@ static int openfile(char *name, int flags, QDict *opts)
|
||||
}
|
||||
}
|
||||
|
||||
blk_set_enable_write_cache(qemuio_blk, !writethrough);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -137,6 +138,7 @@ static int open_f(BlockBackend *blk, int argc, char **argv)
|
||||
{
|
||||
int flags = 0;
|
||||
int readonly = 0;
|
||||
bool writethrough = true;
|
||||
int c;
|
||||
QemuOpts *qopts;
|
||||
QDict *opts;
|
||||
@ -147,7 +149,8 @@ static int open_f(BlockBackend *blk, int argc, char **argv)
|
||||
flags |= BDRV_O_SNAPSHOT;
|
||||
break;
|
||||
case 'n':
|
||||
flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
|
||||
flags |= BDRV_O_NOCACHE;
|
||||
writethrough = false;
|
||||
break;
|
||||
case 'r':
|
||||
readonly = 1;
|
||||
@ -185,9 +188,9 @@ static int open_f(BlockBackend *blk, int argc, char **argv)
|
||||
qemu_opts_reset(&empty_opts);
|
||||
|
||||
if (optind == argc - 1) {
|
||||
return openfile(argv[optind], flags, opts);
|
||||
return openfile(argv[optind], flags, writethrough, opts);
|
||||
} else if (optind == argc) {
|
||||
return openfile(NULL, flags, opts);
|
||||
return openfile(NULL, flags, writethrough, opts);
|
||||
} else {
|
||||
QDECREF(opts);
|
||||
return qemuio_command_usage(&open_cmd);
|
||||
@ -428,6 +431,7 @@ int main(int argc, char **argv)
|
||||
int c;
|
||||
int opt_index = 0;
|
||||
int flags = BDRV_O_UNMAP;
|
||||
bool writethrough = true;
|
||||
Error *local_error = NULL;
|
||||
QDict *opts = NULL;
|
||||
const char *format = NULL;
|
||||
@ -449,7 +453,8 @@ int main(int argc, char **argv)
|
||||
flags |= BDRV_O_SNAPSHOT;
|
||||
break;
|
||||
case 'n':
|
||||
flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
|
||||
flags |= BDRV_O_NOCACHE;
|
||||
writethrough = false;
|
||||
break;
|
||||
case 'd':
|
||||
if (bdrv_parse_discard_flags(optarg, &flags) < 0) {
|
||||
@ -473,7 +478,7 @@ int main(int argc, char **argv)
|
||||
flags |= BDRV_O_NATIVE_AIO;
|
||||
break;
|
||||
case 't':
|
||||
if (bdrv_parse_cache_flags(optarg, &flags) < 0) {
|
||||
if (bdrv_parse_cache_mode(optarg, &flags, &writethrough) < 0) {
|
||||
error_report("Invalid cache option: %s", optarg);
|
||||
exit(1);
|
||||
}
|
||||
@ -555,13 +560,13 @@ int main(int argc, char **argv)
|
||||
exit(1);
|
||||
}
|
||||
opts = qemu_opts_to_qdict(qopts, NULL);
|
||||
openfile(NULL, flags, opts);
|
||||
openfile(NULL, flags, writethrough, opts);
|
||||
} else {
|
||||
if (format) {
|
||||
opts = qdict_new();
|
||||
qdict_put(opts, "driver", qstring_from_str(format));
|
||||
}
|
||||
openfile(argv[optind], flags, opts);
|
||||
openfile(argv[optind], flags, writethrough, opts);
|
||||
}
|
||||
}
|
||||
command_loop();
|
||||
|
@ -509,6 +509,7 @@ int main(int argc, char **argv)
|
||||
const char *export_name = NULL;
|
||||
const char *tlscredsid = NULL;
|
||||
bool imageOpts = false;
|
||||
bool writethrough = true;
|
||||
|
||||
/* The client thread uses SIGTERM to interrupt the server. A signal
|
||||
* handler ensures that "qemu-nbd -v -c" exits with a nice status code.
|
||||
@ -535,7 +536,7 @@ int main(int argc, char **argv)
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
seen_cache = true;
|
||||
if (bdrv_parse_cache_flags(optarg, &flags) == -1) {
|
||||
if (bdrv_parse_cache_mode(optarg, &flags, &writethrough) == -1) {
|
||||
error_report("Invalid cache mode `%s'", optarg);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@ -849,6 +850,8 @@ int main(int argc, char **argv)
|
||||
}
|
||||
bs = blk_bs(blk);
|
||||
|
||||
blk_set_enable_write_cache(blk, !writethrough);
|
||||
|
||||
if (sn_opts) {
|
||||
ret = bdrv_snapshot_load_tmp(bs,
|
||||
qemu_opt_get(sn_opts, SNAPSHOT_OPT_ID),
|
||||
|
@ -51,6 +51,9 @@ static void replay_run_event(Event *event)
|
||||
case REPLAY_ASYNC_EVENT_CHAR_READ:
|
||||
replay_event_char_read_run(event->opaque);
|
||||
break;
|
||||
case REPLAY_ASYNC_EVENT_BLOCK:
|
||||
aio_bh_call(event->opaque);
|
||||
break;
|
||||
default:
|
||||
error_report("Replay: invalid async event ID (%d) in the queue",
|
||||
event->event_kind);
|
||||
@ -135,7 +138,7 @@ void replay_add_event(ReplayAsyncEventKind event_kind,
|
||||
|
||||
void replay_bh_schedule_event(QEMUBH *bh)
|
||||
{
|
||||
if (replay_mode != REPLAY_MODE_NONE) {
|
||||
if (replay_mode != REPLAY_MODE_NONE && events_enabled) {
|
||||
uint64_t id = replay_get_current_step();
|
||||
replay_add_event(REPLAY_ASYNC_EVENT_BH, bh, NULL, id);
|
||||
} else {
|
||||
@ -153,6 +156,15 @@ void replay_add_input_sync_event(void)
|
||||
replay_add_event(REPLAY_ASYNC_EVENT_INPUT_SYNC, NULL, NULL, 0);
|
||||
}
|
||||
|
||||
void replay_block_event(QEMUBH *bh, uint64_t id)
|
||||
{
|
||||
if (replay_mode != REPLAY_MODE_NONE && events_enabled) {
|
||||
replay_add_event(REPLAY_ASYNC_EVENT_BLOCK, bh, NULL, id);
|
||||
} else {
|
||||
qemu_bh_schedule(bh);
|
||||
}
|
||||
}
|
||||
|
||||
static void replay_save_event(Event *event, int checkpoint)
|
||||
{
|
||||
if (replay_mode != REPLAY_MODE_PLAY) {
|
||||
@ -174,8 +186,11 @@ static void replay_save_event(Event *event, int checkpoint)
|
||||
case REPLAY_ASYNC_EVENT_CHAR_READ:
|
||||
replay_event_char_read_save(event->opaque);
|
||||
break;
|
||||
case REPLAY_ASYNC_EVENT_BLOCK:
|
||||
replay_put_qword(event->id);
|
||||
break;
|
||||
default:
|
||||
error_report("Unknown ID %d of replay event", read_event_kind);
|
||||
error_report("Unknown ID %" PRId64 " of replay event", event->id);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
@ -232,6 +247,11 @@ static Event *replay_read_event(int checkpoint)
|
||||
event->event_kind = read_event_kind;
|
||||
event->opaque = replay_event_char_read_load();
|
||||
return event;
|
||||
case REPLAY_ASYNC_EVENT_BLOCK:
|
||||
if (read_id == -1) {
|
||||
read_id = replay_get_qword();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
error_report("Unknown ID %d of replay event", read_event_kind);
|
||||
exit(1);
|
||||
|
@ -49,6 +49,7 @@ enum ReplayAsyncEventKind {
|
||||
REPLAY_ASYNC_EVENT_INPUT,
|
||||
REPLAY_ASYNC_EVENT_INPUT_SYNC,
|
||||
REPLAY_ASYNC_EVENT_CHAR_READ,
|
||||
REPLAY_ASYNC_EVENT_BLOCK,
|
||||
REPLAY_ASYNC_COUNT
|
||||
};
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
/* Current version of the replay mechanism.
|
||||
Increase it when file format changes. */
|
||||
#define REPLAY_VERSION 0xe02003
|
||||
#define REPLAY_VERSION 0xe02004
|
||||
/* Size of replay log header */
|
||||
#define HEADER_SIZE (sizeof(uint32_t) + sizeof(uint64_t))
|
||||
|
||||
|
@ -63,3 +63,7 @@ void replay_char_read_all_save_buf(uint8_t *buf, int offset)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
||||
void replay_block_event(QEMUBH *bh, uint64_t id)
|
||||
{
|
||||
}
|
||||
|
@ -187,12 +187,6 @@ qemu-img create -f qcow2 -o encryption=off TEST_DIR/t.qcow2 64M
|
||||
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
|
||||
|
||||
qemu-img create -f qcow2 -o encryption=on TEST_DIR/t.qcow2 64M
|
||||
qemu-img: Encrypted images are deprecated
|
||||
Support for them will be removed in a future release.
|
||||
You can use 'qemu-img convert' to convert your image to an unencrypted one.
|
||||
qemu-img: Encrypted images are deprecated
|
||||
Support for them will be removed in a future release.
|
||||
You can use 'qemu-img convert' to convert your image to an unencrypted one.
|
||||
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=on cluster_size=65536 lazy_refcounts=off refcount_bits=16
|
||||
|
||||
== Check lazy_refcounts option (only with v3) ==
|
||||
|
@ -218,7 +218,7 @@ run_qemu -drive driver=null-co,cache=invalid_value
|
||||
|
||||
for cache in writeback writethrough unsafe invalid_value; do
|
||||
echo -e "info block\ninfo block file\ninfo block backing\ninfo block backing-file" | \
|
||||
run_qemu -drive file="$TEST_IMG",cache=$cache,backing.file.filename="$TEST_IMG.base",backing.cache.no-flush=on,backing.cache.writeback=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=$device_id -nodefaults
|
||||
run_qemu -drive file="$TEST_IMG",cache=$cache,backing.file.filename="$TEST_IMG.base",backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=$device_id -nodefaults
|
||||
done
|
||||
|
||||
echo
|
||||
|
@ -239,7 +239,7 @@ QEMU X.Y.Z monitor - type 'help' for more information
|
||||
Testing: -drive driver=null-co,cache=invalid_value
|
||||
QEMU_PROG: -drive driver=null-co,cache=invalid_value: invalid cache option
|
||||
|
||||
Testing: -drive file=TEST_DIR/t.qcow2,cache=writeback,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.cache.writeback=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults
|
||||
Testing: -drive file=TEST_DIR/t.qcow2,cache=writeback,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults
|
||||
QEMU X.Y.Z monitor - type 'help' for more information
|
||||
(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K
|
||||
drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
|
||||
@ -259,7 +259,7 @@ backing-file: TEST_DIR/t.qcow2.base (file, read-only)
|
||||
Cache mode: writeback, ignore flushes
|
||||
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
||||
|
||||
Testing: -drive file=TEST_DIR/t.qcow2,cache=writethrough,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.cache.writeback=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults
|
||||
Testing: -drive file=TEST_DIR/t.qcow2,cache=writethrough,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults
|
||||
QEMU X.Y.Z monitor - type 'help' for more information
|
||||
(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K
|
||||
drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
|
||||
@ -279,7 +279,7 @@ backing-file: TEST_DIR/t.qcow2.base (file, read-only)
|
||||
Cache mode: writeback, ignore flushes
|
||||
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
||||
|
||||
Testing: -drive file=TEST_DIR/t.qcow2,cache=unsafe,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.cache.writeback=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults
|
||||
Testing: -drive file=TEST_DIR/t.qcow2,cache=unsafe,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults
|
||||
QEMU X.Y.Z monitor - type 'help' for more information
|
||||
(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K
|
||||
drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
|
||||
@ -299,8 +299,8 @@ backing-file: TEST_DIR/t.qcow2.base (file, read-only)
|
||||
Cache mode: writeback, ignore flushes
|
||||
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
||||
|
||||
Testing: -drive file=TEST_DIR/t.qcow2,cache=invalid_value,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.cache.writeback=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults
|
||||
QEMU_PROG: -drive file=TEST_DIR/t.qcow2,cache=invalid_value,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.cache.writeback=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0: invalid cache option
|
||||
Testing: -drive file=TEST_DIR/t.qcow2,cache=invalid_value,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults
|
||||
QEMU_PROG: -drive file=TEST_DIR/t.qcow2,cache=invalid_value,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0: invalid cache option
|
||||
|
||||
|
||||
=== Specifying the protocol layer ===
|
||||
|
@ -45,7 +45,8 @@ function do_run_qemu()
|
||||
|
||||
function run_qemu()
|
||||
{
|
||||
do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp | _filter_qemu \
|
||||
do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \
|
||||
| _filter_qemu | _filter_imgfmt \
|
||||
| sed -e 's/\("actual-size":\s*\)[0-9]\+/\1SIZE/g'
|
||||
}
|
||||
|
||||
|
@ -38,19 +38,14 @@ QMP_VERSION
|
||||
|
||||
=== Encrypted image ===
|
||||
|
||||
qemu-img: Encrypted images are deprecated
|
||||
Support for them will be removed in a future release.
|
||||
You can use 'qemu-img convert' to convert your image to an unencrypted one.
|
||||
qemu-img: Encrypted images are deprecated
|
||||
Support for them will be removed in a future release.
|
||||
You can use 'qemu-img convert' to convert your image to an unencrypted one.
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on
|
||||
Testing: -S
|
||||
QMP_VERSION
|
||||
{"return": {}}
|
||||
Encrypted images are deprecated
|
||||
Support for them will be removed in a future release.
|
||||
You can use 'qemu-img convert' to convert your image to an unencrypted one.
|
||||
IMGFMT built-in AES encryption is deprecated
|
||||
Support for it will be removed in a future release.
|
||||
You can use 'qemu-img convert' to switch to an
|
||||
unencrypted IMGFMT image, or a LUKS raw image.
|
||||
{"error": {"class": "GenericError", "desc": "blockdev-add doesn't support encrypted devices"}}
|
||||
{"return": {}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"}
|
||||
@ -58,9 +53,10 @@ You can use 'qemu-img convert' to convert your image to an unencrypted one.
|
||||
Testing:
|
||||
QMP_VERSION
|
||||
{"return": {}}
|
||||
Encrypted images are deprecated
|
||||
Support for them will be removed in a future release.
|
||||
You can use 'qemu-img convert' to convert your image to an unencrypted one.
|
||||
IMGFMT built-in AES encryption is deprecated
|
||||
Support for it will be removed in a future release.
|
||||
You can use 'qemu-img convert' to switch to an
|
||||
unencrypted IMGFMT image, or a LUKS raw image.
|
||||
{"error": {"class": "GenericError", "desc": "Guest must be stopped for opening of encrypted image"}}
|
||||
{"return": {}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"}
|
||||
@ -68,12 +64,6 @@ You can use 'qemu-img convert' to convert your image to an unencrypted one.
|
||||
|
||||
=== Missing driver ===
|
||||
|
||||
qemu-img: Encrypted images are deprecated
|
||||
Support for them will be removed in a future release.
|
||||
You can use 'qemu-img convert' to convert your image to an unencrypted one.
|
||||
qemu-img: Encrypted images are deprecated
|
||||
Support for them will be removed in a future release.
|
||||
You can use 'qemu-img convert' to convert your image to an unencrypted one.
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on
|
||||
Testing: -S
|
||||
QMP_VERSION
|
||||
|
@ -112,16 +112,14 @@ read 3145728/3145728 bytes at offset 0
|
||||
3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 63963136/63963136 bytes at offset 3145728
|
||||
61 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
[{ "start": 0, "length": 6291456, "depth": 0, "zero": false, "data": true, "offset": 327680},
|
||||
{ "start": 6291456, "length": 60817408, "depth": 0, "zero": true, "data": false}]
|
||||
[{ "start": 0, "length": 67108864, "depth": 0, "zero": false, "data": true, "offset": 327680}]
|
||||
|
||||
convert -c -S 0:
|
||||
read 3145728/3145728 bytes at offset 0
|
||||
3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 63963136/63963136 bytes at offset 3145728
|
||||
61 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
[{ "start": 0, "length": 6291456, "depth": 0, "zero": false, "data": true},
|
||||
{ "start": 6291456, "length": 60817408, "depth": 0, "zero": true, "data": false}]
|
||||
[{ "start": 0, "length": 67108864, "depth": 0, "zero": false, "data": true}]
|
||||
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
|
||||
wrote 33554432/33554432 bytes at offset 0
|
||||
32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
|
@ -1,43 +1,25 @@
|
||||
QA output created by 134
|
||||
qemu-img: Encrypted images are deprecated
|
||||
Support for them will be removed in a future release.
|
||||
You can use 'qemu-img convert' to convert your image to an unencrypted one.
|
||||
qemu-img: Encrypted images are deprecated
|
||||
Support for them will be removed in a future release.
|
||||
You can use 'qemu-img convert' to convert your image to an unencrypted one.
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on
|
||||
|
||||
== reading whole image ==
|
||||
Encrypted images are deprecated
|
||||
Support for them will be removed in a future release.
|
||||
You can use 'qemu-img convert' to convert your image to an unencrypted one.
|
||||
Disk image 'TEST_DIR/t.qcow2' 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)
|
||||
|
||||
== rewriting whole image ==
|
||||
Encrypted images are deprecated
|
||||
Support for them will be removed in a future release.
|
||||
You can use 'qemu-img convert' to convert your image to an unencrypted one.
|
||||
Disk image 'TEST_DIR/t.qcow2' 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 ==
|
||||
Encrypted images are deprecated
|
||||
Support for them will be removed in a future release.
|
||||
You can use 'qemu-img convert' to convert your image to an unencrypted one.
|
||||
Disk image 'TEST_DIR/t.qcow2' 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)
|
||||
|
||||
== verify pattern failure with wrong password ==
|
||||
Encrypted images are deprecated
|
||||
Support for them will be removed in a future release.
|
||||
You can use 'qemu-img convert' to convert your image to an unencrypted one.
|
||||
Disk image 'TEST_DIR/t.qcow2' is encrypted.
|
||||
password:
|
||||
Pattern verification failed at offset 0, 134217728 bytes
|
||||
|
@ -96,36 +96,36 @@ function check_cache_all()
|
||||
# bs->backing
|
||||
|
||||
echo -e "cache.direct=on on none0"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$files","$ids",cache.direct=on | grep "Cache"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$files","$ids",cache.direct=on | grep -e "Cache" -e "[Cc]annot|[Cc]ould not|[Cc]an't"
|
||||
echo -e "\ncache.direct=on on file"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$files","$ids",file.cache.direct=on | grep "Cache"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$files","$ids",file.cache.direct=on | grep -e "Cache" -e "[Cc]annot|[Cc]ould not|[Cc]an't"
|
||||
echo -e "\ncache.direct=on on backing"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.cache.direct=on | grep "Cache"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.cache.direct=on | grep -e "Cache" -e "[Cc]annot|[Cc]ould not|[Cc]an't"
|
||||
echo -e "\ncache.direct=on on backing-file"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.file.cache.direct=on | grep "Cache"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.file.cache.direct=on | grep -e "Cache" -e "[Cc]annot|[Cc]ould not|[Cc]an't"
|
||||
|
||||
# cache.writeback is supposed to be inherited by bs->backing; bs->file
|
||||
# always gets cache.writeback=on
|
||||
|
||||
echo -e "\n\ncache.writeback=off on none0"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$files","$ids",cache.writeback=off | grep "Cache"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$files","$ids",cache.writeback=off | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't"
|
||||
echo -e "\ncache.writeback=off on file"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$files","$ids",file.cache.writeback=off | grep "Cache"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$files","$ids",file.cache.writeback=off | grep -e "doesn't" -e "does not"
|
||||
echo -e "\ncache.writeback=off on backing"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.cache.writeback=off | grep "Cache"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.cache.writeback=off | grep -e "doesn't" -e "does not"
|
||||
echo -e "\ncache.writeback=off on backing-file"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.file.cache.writeback=off | grep "Cache"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.file.cache.writeback=off | grep -e "doesn't" -e "does not"
|
||||
|
||||
# cache.no-flush is supposed to be inherited by both bs->file and bs->backing
|
||||
|
||||
echo -e "\n\ncache.no-flush=on on none0"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$files","$ids",cache.no-flush=on | grep "Cache"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$files","$ids",cache.no-flush=on | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't"
|
||||
echo -e "\ncache.no-flush=on on file"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$files","$ids",file.cache.no-flush=on | grep "Cache"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$files","$ids",file.cache.no-flush=on | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't"
|
||||
echo -e "\ncache.no-flush=on on backing"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.cache.no-flush=on | grep "Cache"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.cache.no-flush=on | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't"
|
||||
echo -e "\ncache.no-flush=on on backing-file"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.file.cache.no-flush=on | grep "Cache"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.file.cache.no-flush=on | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't"
|
||||
}
|
||||
|
||||
echo
|
||||
@ -134,7 +134,8 @@ echo
|
||||
|
||||
# First check the inherited cache mode after opening the image.
|
||||
|
||||
hmp_cmds="info block image
|
||||
hmp_cmds="info block none0
|
||||
info block image
|
||||
info block file
|
||||
info block backing
|
||||
info block backing-file"
|
||||
@ -164,6 +165,7 @@ echo
|
||||
# new cache mode is specified in the flags, not as an option.
|
||||
|
||||
hmp_cmds='qemu-io none0 "reopen -c none"
|
||||
info block none0
|
||||
info block image
|
||||
info block file
|
||||
info block backing
|
||||
@ -179,6 +181,7 @@ echo
|
||||
# new cache mode is specified as an option, not in the flags.
|
||||
|
||||
hmp_cmds='qemu-io none0 "reopen -o cache.direct=on"
|
||||
info block none0
|
||||
info block image
|
||||
info block file
|
||||
info block backing
|
||||
@ -213,12 +216,13 @@ echo
|
||||
# BDS initialised with the json: pseudo-protocol, but still have it inherit
|
||||
# options from its parent node.
|
||||
|
||||
hmp_cmds="qemu-io none0 \"reopen -o cache.writeback=off,cache.direct=on,cache.no-flush=on\"
|
||||
hmp_cmds="qemu-io none0 \"reopen -o cache.direct=on,cache.no-flush=on\"
|
||||
info block none0
|
||||
info block image
|
||||
info block blkdebug
|
||||
info block file"
|
||||
|
||||
echo "$hmp_cmds" | run_qemu -drive if=none,file="blkdebug::json:{\"filename\":\"$TEST_IMG\",,\"cache\":{\"writeback\":false,,\"direct\":false}}",node-name=image,file.node-name=blkdebug,file.image.node-name=file | grep "Cache"
|
||||
echo "$hmp_cmds" | run_qemu -drive if=none,file="blkdebug::json:{\"filename\":\"$TEST_IMG\",,\"cache\":{\"direct\":false}}",node-name=image,file.node-name=blkdebug,file.image.node-name=file | grep "Cache"
|
||||
|
||||
echo
|
||||
echo "=== Check that referenced BDSes don't inherit ==="
|
||||
@ -234,35 +238,35 @@ function check_cache_all_separate()
|
||||
# Check cache.direct
|
||||
|
||||
echo -e "cache.direct=on on blk"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img",cache.direct=on | grep "Cache"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img",cache.direct=on | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't"
|
||||
echo -e "\ncache.direct=on on file"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file",cache.direct=on -drive "$drv_img" | grep "Cache"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file",cache.direct=on -drive "$drv_img" | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't"
|
||||
echo -e "\ncache.direct=on on backing"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk",cache.direct=on -drive "$drv_file" -drive "$drv_img" | grep "Cache"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk",cache.direct=on -drive "$drv_file" -drive "$drv_img" | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't"
|
||||
echo -e "\ncache.direct=on on backing-file"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile",cache.direct=on -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img" | grep "Cache"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile",cache.direct=on -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img" | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't"
|
||||
|
||||
# Check cache.writeback
|
||||
|
||||
echo -e "\n\ncache.writeback=off on blk"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img",cache.writeback=off | grep "Cache"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img",cache.writeback=off | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't"
|
||||
echo -e "\ncache.writeback=off on file"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file",cache.writeback=off -drive "$drv_img" | grep "Cache"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file",cache.writeback=off -drive "$drv_img" | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't"
|
||||
echo -e "\ncache.writeback=off on backing"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk",cache.writeback=off -drive "$drv_file" -drive "$drv_img" | grep "Cache"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk",cache.writeback=off -drive "$drv_file" -drive "$drv_img" | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't"
|
||||
echo -e "\ncache.writeback=off on backing-file"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile",cache.writeback=off -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img" | grep "Cache"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile",cache.writeback=off -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img" | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't"
|
||||
|
||||
# Check cache.no-flush
|
||||
|
||||
echo -e "\n\ncache.no-flush=on on blk"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img",cache.no-flush=on | grep "Cache"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img",cache.no-flush=on | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't"
|
||||
echo -e "\ncache.no-flush=on on file"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file",cache.no-flush=on -drive "$drv_img" | grep "Cache"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file",cache.no-flush=on -drive "$drv_img" | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't"
|
||||
echo -e "\ncache.no-flush=on on backing"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk",cache.no-flush=on -drive "$drv_file" -drive "$drv_img" | grep "Cache"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk",cache.no-flush=on -drive "$drv_file" -drive "$drv_img" | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't"
|
||||
echo -e "\ncache.no-flush=on on backing-file"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile",cache.no-flush=on -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img" | grep "Cache"
|
||||
echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile",cache.no-flush=on -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img" | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't"
|
||||
}
|
||||
|
||||
echo
|
||||
@ -321,6 +325,7 @@ echo "--- Basic reopen ---"
|
||||
echo
|
||||
|
||||
hmp_cmds='qemu-io none0 "reopen -o backing.cache.direct=on"
|
||||
info block none0
|
||||
info block image
|
||||
info block file
|
||||
info block backing
|
||||
@ -338,8 +343,8 @@ echo
|
||||
# TODO Implement node-name support for 'qemu-io' HMP command for -c
|
||||
# Can use only -o to access child node options for now
|
||||
|
||||
hmp_cmds="qemu-io none0 \"reopen -o file.cache.writeback=off,file.cache.direct=off,file.cache.no-flush=off\"
|
||||
qemu-io none0 \"reopen -o backing.file.cache.writeback=on,backing.file.cache.direct=off,backing.file.cache.no-flush=on\"
|
||||
hmp_cmds="qemu-io none0 \"reopen -o file.cache.direct=off,file.cache.no-flush=off\"
|
||||
qemu-io none0 \"reopen -o backing.file.cache.direct=off,backing.file.cache.no-flush=on\"
|
||||
qemu-io none0 \"reopen -c none\"
|
||||
info block image
|
||||
info block file
|
||||
|
@ -39,14 +39,17 @@ cache.direct=on on none0
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
|
||||
cache.direct=on on file
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
|
||||
cache.direct=on on backing
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback, direct
|
||||
@ -56,32 +59,25 @@ cache.direct=on on backing-file
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback, direct
|
||||
|
||||
|
||||
cache.writeback=off on none0
|
||||
Cache mode: writethrough
|
||||
Cache mode: writeback
|
||||
Cache mode: writethrough
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
|
||||
cache.writeback=off on file
|
||||
Cache mode: writeback
|
||||
Cache mode: writethrough
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,backing.file.filename=TEST_DIR/t.qcow2.base,node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,file.cache.writeback=off: Block protocol 'file' doesn't support the option 'cache.writeback'
|
||||
|
||||
cache.writeback=off on backing
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writethrough
|
||||
Cache mode: writeback
|
||||
QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,backing.file.filename=TEST_DIR/t.qcow2.base,node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,backing.cache.writeback=off: Could not open backing file: Block format 'qcow2' does not support the option 'cache.writeback'
|
||||
|
||||
cache.writeback=off on backing-file
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writethrough
|
||||
QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,backing.file.filename=TEST_DIR/t.qcow2.base,node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,backing.file.cache.writeback=off: Could not open backing file: Block protocol 'file' doesn't support the option 'cache.writeback'
|
||||
|
||||
|
||||
cache.no-flush=on on none0
|
||||
@ -89,14 +85,17 @@ cache.no-flush=on on none0
|
||||
Cache mode: writeback, ignore flushes
|
||||
Cache mode: writeback, ignore flushes
|
||||
Cache mode: writeback, ignore flushes
|
||||
Cache mode: writeback, ignore flushes
|
||||
|
||||
cache.no-flush=on on file
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback, ignore flushes
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
|
||||
cache.no-flush=on on backing
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback, ignore flushes
|
||||
@ -106,6 +105,7 @@ cache.no-flush=on on backing-file
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback, ignore flushes
|
||||
|
||||
--- Cache modes after reopen (live snapshot) ---
|
||||
@ -140,32 +140,20 @@ cache.direct=on on backing-file
|
||||
|
||||
|
||||
cache.writeback=off on none0
|
||||
Cache mode: writethrough
|
||||
Cache mode: writethrough
|
||||
Cache mode: writeback
|
||||
Cache mode: writethrough
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
|
||||
cache.writeback=off on file
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writethrough
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,backing.file.filename=TEST_DIR/t.qcow2.base,node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,file.cache.writeback=off: Block protocol 'file' doesn't support the option 'cache.writeback'
|
||||
|
||||
cache.writeback=off on backing
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writethrough
|
||||
Cache mode: writeback
|
||||
QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,backing.file.filename=TEST_DIR/t.qcow2.base,node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,backing.cache.writeback=off: Could not open backing file: Block format 'qcow2' does not support the option 'cache.writeback'
|
||||
|
||||
cache.writeback=off on backing-file
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writethrough
|
||||
QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,backing.file.filename=TEST_DIR/t.qcow2.base,node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,backing.file.cache.writeback=off: Could not open backing file: Block protocol 'file' doesn't support the option 'cache.writeback'
|
||||
|
||||
|
||||
cache.no-flush=on on none0
|
||||
@ -203,24 +191,28 @@ cache.direct=on on none0
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
|
||||
cache.direct=on on file
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
|
||||
cache.direct=on on backing
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
|
||||
cache.direct=on on backing-file
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
|
||||
|
||||
cache.writeback=off on none0
|
||||
@ -228,24 +220,16 @@ cache.writeback=off on none0
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
|
||||
cache.writeback=off on file
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writethrough, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,backing.file.filename=TEST_DIR/t.qcow2.base,node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,file.cache.writeback=off: Block protocol 'file' doesn't support the option 'cache.writeback'
|
||||
|
||||
cache.writeback=off on backing
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writethrough, direct
|
||||
Cache mode: writeback, direct
|
||||
QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,backing.file.filename=TEST_DIR/t.qcow2.base,node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,backing.cache.writeback=off: Could not open backing file: Block format 'qcow2' does not support the option 'cache.writeback'
|
||||
|
||||
cache.writeback=off on backing-file
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writethrough, direct
|
||||
QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,backing.file.filename=TEST_DIR/t.qcow2.base,node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,backing.file.cache.writeback=off: Could not open backing file: Block protocol 'file' doesn't support the option 'cache.writeback'
|
||||
|
||||
|
||||
cache.no-flush=on on none0
|
||||
@ -253,14 +237,17 @@ cache.no-flush=on on none0
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
|
||||
cache.no-flush=on on file
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct, ignore flushes
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
|
||||
cache.no-flush=on on backing
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct, ignore flushes
|
||||
@ -270,6 +257,7 @@ cache.no-flush=on on backing-file
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct, ignore flushes
|
||||
|
||||
--- Change cache modes with reopen (qemu-io command, options) ---
|
||||
@ -279,49 +267,45 @@ cache.direct=on on none0
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
|
||||
cache.direct=on on file
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
|
||||
cache.direct=on on backing
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
|
||||
cache.direct=on on backing-file
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
|
||||
|
||||
cache.writeback=off on none0
|
||||
Cache mode: writethrough, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writethrough, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
|
||||
cache.writeback=off on file
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writethrough, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,backing.file.filename=TEST_DIR/t.qcow2.base,node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,file.cache.writeback=off: Block protocol 'file' doesn't support the option 'cache.writeback'
|
||||
|
||||
cache.writeback=off on backing
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writethrough, direct
|
||||
Cache mode: writeback, direct
|
||||
QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,backing.file.filename=TEST_DIR/t.qcow2.base,node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,backing.cache.writeback=off: Could not open backing file: Block format 'qcow2' does not support the option 'cache.writeback'
|
||||
|
||||
cache.writeback=off on backing-file
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writethrough, direct
|
||||
QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,backing.file.filename=TEST_DIR/t.qcow2.base,node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,backing.file.cache.writeback=off: Could not open backing file: Block protocol 'file' doesn't support the option 'cache.writeback'
|
||||
|
||||
|
||||
cache.no-flush=on on none0
|
||||
@ -329,14 +313,17 @@ cache.no-flush=on on none0
|
||||
Cache mode: writeback, direct, ignore flushes
|
||||
Cache mode: writeback, direct, ignore flushes
|
||||
Cache mode: writeback, direct, ignore flushes
|
||||
Cache mode: writeback, direct, ignore flushes
|
||||
|
||||
cache.no-flush=on on file
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct, ignore flushes
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
|
||||
cache.no-flush=on on backing
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct, ignore flushes
|
||||
@ -346,6 +333,7 @@ cache.no-flush=on on backing-file
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct, ignore flushes
|
||||
|
||||
--- Change cache modes after snapshot ---
|
||||
@ -381,31 +369,19 @@ cache.direct=on on backing-file
|
||||
|
||||
cache.writeback=off on none0
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writethrough
|
||||
Cache mode: writeback
|
||||
Cache mode: writethrough
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
|
||||
cache.writeback=off on file
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback
|
||||
Cache mode: writethrough
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,backing.file.filename=TEST_DIR/t.qcow2.base,node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,file.cache.writeback=off: Block protocol 'file' doesn't support the option 'cache.writeback'
|
||||
|
||||
cache.writeback=off on backing
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writethrough
|
||||
Cache mode: writeback
|
||||
QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,backing.file.filename=TEST_DIR/t.qcow2.base,node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,backing.cache.writeback=off: Could not open backing file: Block format 'qcow2' does not support the option 'cache.writeback'
|
||||
|
||||
cache.writeback=off on backing-file
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writethrough
|
||||
QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,backing.file.filename=TEST_DIR/t.qcow2.base,node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,backing.file.cache.writeback=off: Could not open backing file: Block protocol 'file' doesn't support the option 'cache.writeback'
|
||||
|
||||
|
||||
cache.no-flush=on on none0
|
||||
@ -438,9 +414,10 @@ cache.no-flush=on on backing-file
|
||||
|
||||
--- Change cache mode in parent, child has explicit option in JSON ---
|
||||
|
||||
Cache mode: writethrough, direct, ignore flushes
|
||||
Cache mode: writeback, direct, ignore flushes
|
||||
Cache mode: writethrough, ignore flushes
|
||||
Cache mode: writeback, direct, ignore flushes
|
||||
Cache mode: writeback, direct, ignore flushes
|
||||
Cache mode: writeback, ignore flushes
|
||||
|
||||
=== Check that referenced BDSes don't inherit ===
|
||||
|
||||
@ -473,28 +450,28 @@ cache.direct=on on backing-file
|
||||
|
||||
|
||||
cache.writeback=off on blk
|
||||
Cache mode: writethrough
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
|
||||
cache.writeback=off on file
|
||||
Cache mode: writeback
|
||||
Cache mode: writethrough
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
|
||||
cache.writeback=off on backing
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writethrough
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
|
||||
cache.writeback=off on backing-file
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writethrough
|
||||
Cache mode: writeback
|
||||
|
||||
|
||||
cache.no-flush=on on blk
|
||||
@ -554,7 +531,7 @@ cache.direct=on on backing-file
|
||||
|
||||
cache.writeback=off on blk
|
||||
Cache mode: writethrough
|
||||
Cache mode: writethrough
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
@ -562,7 +539,7 @@ cache.writeback=off on blk
|
||||
cache.writeback=off on file
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writethrough
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
|
||||
@ -570,7 +547,7 @@ cache.writeback=off on backing
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writethrough
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
|
||||
cache.writeback=off on backing-file
|
||||
@ -578,7 +555,7 @@ cache.writeback=off on backing-file
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writethrough
|
||||
Cache mode: writeback
|
||||
|
||||
|
||||
cache.no-flush=on on blk
|
||||
@ -644,21 +621,21 @@ cache.writeback=off on blk
|
||||
|
||||
cache.writeback=off on file
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writethrough
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
|
||||
cache.writeback=off on backing
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback
|
||||
Cache mode: writethrough
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
|
||||
cache.writeback=off on backing-file
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writethrough
|
||||
Cache mode: writeback
|
||||
|
||||
|
||||
cache.no-flush=on on blk
|
||||
@ -695,20 +672,24 @@ cache.direct=on on none0
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
|
||||
cache.direct=on on file
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
|
||||
cache.direct=on on backing
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
|
||||
cache.direct=on on backing-file
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback, direct
|
||||
@ -718,47 +699,43 @@ cache.direct=on on backing-file
|
||||
cache.writeback=off on none0
|
||||
Cache mode: writethrough
|
||||
Cache mode: writeback
|
||||
Cache mode: writethrough, direct
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
|
||||
cache.writeback=off on file
|
||||
Cache mode: writeback
|
||||
Cache mode: writethrough
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,backing.file.filename=TEST_DIR/t.qcow2.base,node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,file.cache.writeback=off: Block protocol 'file' doesn't support the option 'cache.writeback'
|
||||
|
||||
cache.writeback=off on backing
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writethrough, direct
|
||||
Cache mode: writeback, direct
|
||||
QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,backing.file.filename=TEST_DIR/t.qcow2.base,node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,backing.cache.writeback=off: Could not open backing file: Block format 'qcow2' does not support the option 'cache.writeback'
|
||||
|
||||
cache.writeback=off on backing-file
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writethrough, direct
|
||||
QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,backing.file.filename=TEST_DIR/t.qcow2.base,node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,backing.file.cache.writeback=off: Could not open backing file: Block protocol 'file' doesn't support the option 'cache.writeback'
|
||||
|
||||
|
||||
cache.no-flush=on on none0
|
||||
Cache mode: writeback, ignore flushes
|
||||
Cache mode: writeback, ignore flushes
|
||||
Cache mode: writeback, ignore flushes
|
||||
Cache mode: writeback, direct, ignore flushes
|
||||
Cache mode: writeback, direct, ignore flushes
|
||||
|
||||
cache.no-flush=on on file
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback, ignore flushes
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, direct
|
||||
|
||||
cache.no-flush=on on backing
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback, direct, ignore flushes
|
||||
Cache mode: writeback, direct, ignore flushes
|
||||
|
||||
cache.no-flush=on on backing-file
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback, direct
|
||||
@ -767,7 +744,7 @@ cache.no-flush=on on backing-file
|
||||
--- Change cache mode after reopening child ---
|
||||
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writethrough
|
||||
Cache mode: writeback
|
||||
Cache mode: writeback, direct
|
||||
Cache mode: writeback, ignore flushes
|
||||
*** done
|
||||
|
519
tests/qemu-iotests/149
Executable file
519
tests/qemu-iotests/149
Executable file
@ -0,0 +1,519 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
# Copyright (C) 2016 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: Daniel P. Berrange <berrange@redhat.com>
|
||||
#
|
||||
# Exercise the QEMU 'luks' block driver to validate interoperability
|
||||
# with the Linux dm-crypt + cryptsetup implementation
|
||||
|
||||
import subprocess
|
||||
import os
|
||||
import os.path
|
||||
|
||||
import base64
|
||||
|
||||
import iotests
|
||||
|
||||
|
||||
class LUKSConfig(object):
|
||||
"""Represent configuration parameters for a single LUKS
|
||||
setup to be tested"""
|
||||
|
||||
def __init__(self, name, cipher, keylen, mode, ivgen,
|
||||
ivgen_hash, hash, password=None, passwords=None):
|
||||
|
||||
self.name = name
|
||||
self.cipher = cipher
|
||||
self.keylen = keylen
|
||||
self.mode = mode
|
||||
self.ivgen = ivgen
|
||||
self.ivgen_hash = ivgen_hash
|
||||
self.hash = hash
|
||||
|
||||
if passwords is not None:
|
||||
self.passwords = passwords
|
||||
else:
|
||||
self.passwords = {}
|
||||
|
||||
if password is None:
|
||||
self.passwords["0"] = "123456"
|
||||
else:
|
||||
self.passwords["0"] = password
|
||||
|
||||
def __repr__(self):
|
||||
return self.name
|
||||
|
||||
def image_name(self):
|
||||
return "luks-%s.img" % self.name
|
||||
|
||||
def image_path(self):
|
||||
return os.path.join(iotests.test_dir, self.image_name())
|
||||
|
||||
def device_name(self):
|
||||
return "qiotest-145-%s" % self.name
|
||||
|
||||
def device_path(self):
|
||||
return "/dev/mapper/" + self.device_name()
|
||||
|
||||
def first_password(self):
|
||||
for i in range(8):
|
||||
slot = str(i)
|
||||
if slot in self.passwords:
|
||||
return (self.passwords[slot], slot)
|
||||
raise Exception("No password found")
|
||||
|
||||
def first_password_base64(self):
|
||||
(pw, slot) = self.first_password()
|
||||
return base64.b64encode(pw)
|
||||
|
||||
def active_slots(self):
|
||||
slots = []
|
||||
for i in range(8):
|
||||
slot = str(i)
|
||||
if slot in self.passwords:
|
||||
slots.append(slot)
|
||||
return slots
|
||||
|
||||
def verify_passwordless_sudo():
|
||||
"""Check whether sudo is configured to allow
|
||||
password-less access to commands"""
|
||||
|
||||
args = ["sudo", "-n", "/bin/true"]
|
||||
|
||||
proc = subprocess.Popen(args,
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT)
|
||||
|
||||
msg = proc.communicate()[0]
|
||||
|
||||
if proc.returncode != 0:
|
||||
iotests.notrun('requires password-less sudo access: %s' % msg)
|
||||
|
||||
|
||||
def cryptsetup(args, password=None):
|
||||
"""Run the cryptsetup command in batch mode"""
|
||||
|
||||
fullargs = ["sudo", "cryptsetup", "-q", "-v"]
|
||||
fullargs.extend(args)
|
||||
|
||||
iotests.log(" ".join(fullargs), filters=[iotests.filter_test_dir])
|
||||
proc = subprocess.Popen(fullargs,
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT)
|
||||
|
||||
msg = proc.communicate(password)[0]
|
||||
|
||||
if proc.returncode != 0:
|
||||
raise Exception(msg)
|
||||
|
||||
|
||||
def cryptsetup_add_password(config, slot):
|
||||
"""Add another password to a LUKS key slot"""
|
||||
|
||||
(password, mainslot) = config.first_password()
|
||||
|
||||
pwfile = os.path.join(iotests.test_dir, "passwd.txt")
|
||||
with open(pwfile, "w") as fh:
|
||||
fh.write(config.passwords[slot])
|
||||
|
||||
try:
|
||||
args = ["luksAddKey", config.image_path(),
|
||||
"--key-slot", slot,
|
||||
"--key-file", "-",
|
||||
pwfile]
|
||||
|
||||
cryptsetup(args, password)
|
||||
finally:
|
||||
os.unlink(pwfile)
|
||||
|
||||
|
||||
def cryptsetup_format(config):
|
||||
"""Format a new LUKS volume with cryptsetup, adding the
|
||||
first key slot only"""
|
||||
|
||||
(password, slot) = config.first_password()
|
||||
|
||||
args = ["luksFormat"]
|
||||
cipher = config.cipher + "-" + config.mode + "-" + config.ivgen
|
||||
if config.ivgen_hash is not None:
|
||||
cipher = cipher + ":" + config.ivgen_hash
|
||||
args.extend(["--cipher", cipher])
|
||||
if config.mode == "xts":
|
||||
args.extend(["--key-size", str(config.keylen * 2)])
|
||||
else:
|
||||
args.extend(["--key-size", str(config.keylen)])
|
||||
if config.hash is not None:
|
||||
args.extend(["--hash", config.hash])
|
||||
args.extend(["--key-slot", slot])
|
||||
args.extend(["--key-file", "-"])
|
||||
args.append(config.image_path())
|
||||
|
||||
cryptsetup(args, password)
|
||||
|
||||
|
||||
def chown(config):
|
||||
"""Set the ownership of a open LUKS device to this user"""
|
||||
|
||||
path = config.device_path()
|
||||
|
||||
args = ["sudo", "chown", "%d:%d" % (os.getuid(), os.getgid()), path]
|
||||
iotests.log(" ".join(args), filters=[iotests.filter_chown])
|
||||
proc = subprocess.Popen(args,
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT)
|
||||
|
||||
msg = proc.communicate()[0]
|
||||
|
||||
if proc.returncode != 0:
|
||||
raise Exception("Cannot change owner on %s" % path)
|
||||
|
||||
|
||||
def cryptsetup_open(config):
|
||||
"""Open an image as a LUKS device"""
|
||||
|
||||
(password, slot) = config.first_password()
|
||||
|
||||
args = ["luksOpen", config.image_path(), config.device_name()]
|
||||
|
||||
cryptsetup(args, password)
|
||||
|
||||
|
||||
def cryptsetup_close(config):
|
||||
"""Close an active LUKS device """
|
||||
|
||||
args = ["luksClose", config.device_name()]
|
||||
cryptsetup(args)
|
||||
|
||||
|
||||
def delete_image(config):
|
||||
"""Delete a disk image"""
|
||||
|
||||
try:
|
||||
os.unlink(config.image_path())
|
||||
iotests.log("unlink %s" % config.image_path(),
|
||||
filters=[iotests.filter_test_dir])
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
|
||||
def create_image(config, size_mb):
|
||||
"""Create a bare disk image with requested size"""
|
||||
|
||||
delete_image(config)
|
||||
iotests.log("truncate %s --size %dMB" % (config.image_path(), size_mb),
|
||||
filters=[iotests.filter_test_dir])
|
||||
with open(config.image_path(), "w") as fn:
|
||||
fn.truncate(size_mb * 1024 * 1024)
|
||||
|
||||
|
||||
def qemu_img_create(config, size_mb):
|
||||
"""Create and format a disk image with LUKS using qemu-img"""
|
||||
|
||||
opts = [
|
||||
"key-secret=sec0",
|
||||
"cipher-alg=%s-%d" % (config.cipher, config.keylen),
|
||||
"cipher-mode=%s" % config.mode,
|
||||
"ivgen-alg=%s" % config.ivgen,
|
||||
"hash-alg=%s" % config.hash,
|
||||
]
|
||||
if config.ivgen_hash is not None:
|
||||
opts.append("ivgen-hash-alg=%s" % config.ivgen_hash)
|
||||
|
||||
args = ["create", "-f", "luks",
|
||||
"--object",
|
||||
("secret,id=sec0,data=%s,format=base64" %
|
||||
config.first_password_base64()),
|
||||
"-o", ",".join(opts),
|
||||
config.image_path(),
|
||||
"%dM" % size_mb]
|
||||
|
||||
iotests.log("qemu-img " + " ".join(args), filters=[iotests.filter_test_dir])
|
||||
iotests.log(iotests.qemu_img_pipe(*args), filters=[iotests.filter_test_dir])
|
||||
|
||||
def qemu_io_image_args(config, dev=False):
|
||||
"""Get the args for access an image or device with qemu-io"""
|
||||
|
||||
if dev:
|
||||
return [
|
||||
"--image-opts",
|
||||
"driver=file,filename=%s" % config.device_path()]
|
||||
else:
|
||||
return [
|
||||
"--object",
|
||||
("secret,id=sec0,data=%s,format=base64" %
|
||||
config.first_password_base64()),
|
||||
"--image-opts",
|
||||
("driver=luks,key-secret=sec0,file.filename=%s" %
|
||||
config.image_path())]
|
||||
|
||||
def qemu_io_write_pattern(config, pattern, offset_mb, size_mb, dev=False):
|
||||
"""Write a pattern of data to a LUKS image or device"""
|
||||
|
||||
args = ["-c", "write -P 0x%x %dM %dM" % (pattern, offset_mb, size_mb)]
|
||||
args.extend(qemu_io_image_args(config, dev))
|
||||
iotests.log("qemu-io " + " ".join(args), filters=[iotests.filter_test_dir])
|
||||
iotests.log(iotests.qemu_io(*args), filters=[iotests.filter_test_dir,
|
||||
iotests.filter_qemu_io])
|
||||
|
||||
|
||||
def qemu_io_read_pattern(config, pattern, offset_mb, size_mb, dev=False):
|
||||
"""Read a pattern of data to a LUKS image or device"""
|
||||
|
||||
args = ["-c", "read -P 0x%x %dM %dM" % (pattern, offset_mb, size_mb)]
|
||||
args.extend(qemu_io_image_args(config, dev))
|
||||
iotests.log("qemu-io " + " ".join(args), filters=[iotests.filter_test_dir])
|
||||
iotests.log(iotests.qemu_io(*args), filters=[iotests.filter_test_dir,
|
||||
iotests.filter_qemu_io])
|
||||
|
||||
|
||||
def test_once(config, qemu_img=False):
|
||||
"""Run the test with a desired LUKS configuration. Can either
|
||||
use qemu-img for creating the initial volume, or cryptsetup,
|
||||
in order to test interoperability in both directions"""
|
||||
|
||||
iotests.log("# ================= %s %s =================" % (
|
||||
"qemu-img" if qemu_img else "dm-crypt", config))
|
||||
|
||||
oneKB = 1024
|
||||
oneMB = oneKB * 1024
|
||||
oneGB = oneMB * 1024
|
||||
oneTB = oneGB * 1024
|
||||
|
||||
# 4 TB, so that we pass the 32-bit sector number boundary.
|
||||
# Important for testing correctness of some IV generators
|
||||
# The files are sparse, so not actually using this much space
|
||||
image_size = 4 * oneTB
|
||||
if qemu_img:
|
||||
iotests.log("# Create image")
|
||||
qemu_img_create(config, image_size / oneMB)
|
||||
else:
|
||||
iotests.log("# Create image")
|
||||
create_image(config, image_size / oneMB)
|
||||
|
||||
lowOffsetMB = 100
|
||||
highOffsetMB = 3 * oneTB / oneMB
|
||||
|
||||
try:
|
||||
if not qemu_img:
|
||||
iotests.log("# Format image")
|
||||
cryptsetup_format(config)
|
||||
|
||||
for slot in config.active_slots()[1:]:
|
||||
iotests.log("# Add password slot %s" % slot)
|
||||
cryptsetup_add_password(config, slot)
|
||||
|
||||
# First we'll open the image using cryptsetup and write a
|
||||
# known pattern of data that we'll then verify with QEMU
|
||||
|
||||
iotests.log("# Open dev")
|
||||
cryptsetup_open(config)
|
||||
|
||||
try:
|
||||
iotests.log("# Set dev owner")
|
||||
chown(config)
|
||||
|
||||
iotests.log("# Write test pattern 0xa7")
|
||||
qemu_io_write_pattern(config, 0xa7, lowOffsetMB, 10, dev=True)
|
||||
iotests.log("# Write test pattern 0x13")
|
||||
qemu_io_write_pattern(config, 0x13, highOffsetMB, 10, dev=True)
|
||||
finally:
|
||||
iotests.log("# Close dev")
|
||||
cryptsetup_close(config)
|
||||
|
||||
# Ok, now we're using QEMU to verify the pattern just
|
||||
# written via dm-crypt
|
||||
|
||||
iotests.log("# Read test pattern 0xa7")
|
||||
qemu_io_read_pattern(config, 0xa7, lowOffsetMB, 10, dev=False)
|
||||
iotests.log("# Read test pattern 0x13")
|
||||
qemu_io_read_pattern(config, 0x13, highOffsetMB, 10, dev=False)
|
||||
|
||||
|
||||
# Write a new pattern to the image, which we'll later
|
||||
# verify with dm-crypt
|
||||
iotests.log("# Write test pattern 0x91")
|
||||
qemu_io_write_pattern(config, 0x91, lowOffsetMB, 10, dev=False)
|
||||
iotests.log("# Write test pattern 0x5e")
|
||||
qemu_io_write_pattern(config, 0x5e, highOffsetMB, 10, dev=False)
|
||||
|
||||
|
||||
# Now we're opening the image with dm-crypt once more
|
||||
# and verifying what QEMU wrote, completing the circle
|
||||
iotests.log("# Open dev")
|
||||
cryptsetup_open(config)
|
||||
|
||||
try:
|
||||
iotests.log("# Set dev owner")
|
||||
chown(config)
|
||||
|
||||
iotests.log("# Read test pattern 0x91")
|
||||
qemu_io_read_pattern(config, 0x91, lowOffsetMB, 10, dev=True)
|
||||
iotests.log("# Read test pattern 0x5e")
|
||||
qemu_io_read_pattern(config, 0x5e, highOffsetMB, 10, dev=True)
|
||||
finally:
|
||||
iotests.log("# Close dev")
|
||||
cryptsetup_close(config)
|
||||
finally:
|
||||
iotests.log("# Delete image")
|
||||
delete_image(config)
|
||||
print
|
||||
|
||||
|
||||
# Obviously we only work with the luks image format
|
||||
iotests.verify_image_format(supported_fmts=['luks'])
|
||||
iotests.verify_platform()
|
||||
|
||||
# We need sudo in order to run cryptsetup to create
|
||||
# dm-crypt devices. This is safe to use on any
|
||||
# machine, since all dm-crypt devices are backed
|
||||
# by newly created plain files, and have a dm-crypt
|
||||
# name prefix of 'qiotest' to avoid clashing with
|
||||
# user LUKS volumes
|
||||
verify_passwordless_sudo()
|
||||
|
||||
|
||||
# If we look at all permutations of cipher, key size,
|
||||
# mode, ivgen, hash, there are ~1000 possible configs.
|
||||
#
|
||||
# We certainly don't want/need to test every permutation
|
||||
# to get good validation of interoperability between QEMU
|
||||
# and dm-crypt/cryptsetup.
|
||||
#
|
||||
# The configs below are a representative set that aim to
|
||||
# exercise each axis of configurability.
|
||||
#
|
||||
configs = [
|
||||
# A common LUKS default
|
||||
LUKSConfig("aes-256-xts-plain64-sha1",
|
||||
"aes", 256, "xts", "plain64", None, "sha1"),
|
||||
|
||||
|
||||
# LUKS default but diff ciphers
|
||||
LUKSConfig("twofish-256-xts-plain64-sha1",
|
||||
"twofish", 256, "xts", "plain64", None, "sha1"),
|
||||
LUKSConfig("serpent-256-xts-plain64-sha1",
|
||||
"serpent", 256, "xts", "plain64", None, "sha1"),
|
||||
# Should really be xts, but kernel doesn't support xts+cast5
|
||||
# nor does it do essiv+cast5
|
||||
LUKSConfig("cast5-128-cbc-plain64-sha1",
|
||||
"cast5", 128, "cbc", "plain64", None, "sha1"),
|
||||
LUKSConfig("cast6-256-xts-plain64-sha1",
|
||||
"cast6", 256, "xts", "plain64", None, "sha1"),
|
||||
|
||||
|
||||
# LUKS default but diff modes / ivgens
|
||||
LUKSConfig("aes-256-cbc-plain-sha1",
|
||||
"aes", 256, "cbc", "plain", None, "sha1"),
|
||||
LUKSConfig("aes-256-cbc-plain64-sha1",
|
||||
"aes", 256, "cbc", "plain64", None, "sha1"),
|
||||
LUKSConfig("aes-256-cbc-essiv-sha256-sha1",
|
||||
"aes", 256, "cbc", "essiv", "sha256", "sha1"),
|
||||
LUKSConfig("aes-256-xts-essiv-sha256-sha1",
|
||||
"aes", 256, "xts", "essiv", "sha256", "sha1"),
|
||||
|
||||
|
||||
# LUKS default but smaller key sizes
|
||||
LUKSConfig("aes-128-xts-plain64-sha256-sha1",
|
||||
"aes", 128, "xts", "plain64", None, "sha1"),
|
||||
LUKSConfig("aes-192-xts-plain64-sha256-sha1",
|
||||
"aes", 192, "xts", "plain64", None, "sha1"),
|
||||
|
||||
LUKSConfig("twofish-128-xts-plain64-sha1",
|
||||
"twofish", 128, "xts", "plain64", None, "sha1"),
|
||||
LUKSConfig("twofish-192-xts-plain64-sha1",
|
||||
"twofish", 192, "xts", "plain64", None, "sha1"),
|
||||
|
||||
LUKSConfig("serpent-128-xts-plain64-sha1",
|
||||
"serpent", 128, "xts", "plain64", None, "sha1"),
|
||||
LUKSConfig("serpent-192-xts-plain64-sha1",
|
||||
"serpent", 192, "xts", "plain64", None, "sha1"),
|
||||
|
||||
LUKSConfig("cast6-128-xts-plain64-sha1",
|
||||
"cast6", 128, "xts", "plain", None, "sha1"),
|
||||
LUKSConfig("cast6-192-xts-plain64-sha1",
|
||||
"cast6", 192, "xts", "plain64", None, "sha1"),
|
||||
|
||||
|
||||
# LUKS default but diff hash
|
||||
LUKSConfig("aes-256-xts-plain64-sha256",
|
||||
"aes", 256, "xts", "plain64", None, "sha256"),
|
||||
LUKSConfig("aes-256-xts-plain64-sha512",
|
||||
"aes", 256, "xts", "plain64", None, "sha512"),
|
||||
LUKSConfig("aes-256-xts-plain64-ripemd160",
|
||||
"aes", 256, "xts", "plain64", None, "ripemd160"),
|
||||
|
||||
# Password in slot 3
|
||||
LUKSConfig("aes-256-xts-plain-sha1-pwslot3",
|
||||
"aes", 256, "xts", "plain", None, "sha1",
|
||||
passwords={
|
||||
"3": "slot3",
|
||||
}),
|
||||
|
||||
# Passwords in every slot
|
||||
LUKSConfig("aes-256-xts-plain-sha1-pwallslots",
|
||||
"aes", 256, "xts", "plain", None, "sha1",
|
||||
passwords={
|
||||
"0": "slot1",
|
||||
"1": "slot1",
|
||||
"2": "slot2",
|
||||
"3": "slot3",
|
||||
"4": "slot4",
|
||||
"5": "slot5",
|
||||
"6": "slot6",
|
||||
"7": "slot7",
|
||||
}),
|
||||
]
|
||||
|
||||
blacklist = [
|
||||
# We don't have a cast-6 cipher impl for QEMU yet
|
||||
"cast6-256-xts-plain64-sha1",
|
||||
"cast6-128-xts-plain64-sha1",
|
||||
"cast6-192-xts-plain64-sha1",
|
||||
|
||||
# GCrypt doesn't support Twofish with 192 bit key
|
||||
"twofish-192-xts-plain64-sha1",
|
||||
|
||||
# We don't have sha512 hash wired up yet
|
||||
"aes-256-xts-plain64-sha512",
|
||||
|
||||
# We don't have ripemd160 hash wired up yet
|
||||
"aes-256-xts-plain64-ripemd160",
|
||||
]
|
||||
|
||||
whitelist = []
|
||||
if "LUKS_CONFIG" in os.environ:
|
||||
whitelist = os.environ["LUKS_CONFIG"].split(",")
|
||||
|
||||
for config in configs:
|
||||
if config.name in blacklist:
|
||||
iotests.log("Skipping %s in blacklist" % config.name)
|
||||
continue
|
||||
|
||||
if len(whitelist) > 0 and config.name not in whitelist:
|
||||
iotests.log("Skipping %s not in whitelist" % config.name)
|
||||
continue
|
||||
|
||||
test_once(config, qemu_img=False)
|
||||
|
||||
# XXX we should support setting passwords in a non-0
|
||||
# key slot with 'qemu-img create' in future
|
||||
(pw, slot) = config.first_password()
|
||||
if slot == "0":
|
||||
test_once(config, qemu_img=True)
|
1880
tests/qemu-iotests/149.out
Normal file
1880
tests/qemu-iotests/149.out
Normal file
File diff suppressed because it is too large
Load Diff
105
tests/qemu-iotests/150
Executable file
105
tests/qemu-iotests/150
Executable file
@ -0,0 +1,105 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Test that qemu-img convert -S 0 fully allocates the target image
|
||||
#
|
||||
# Copyright (C) 2016 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=mreitz@redhat.com
|
||||
|
||||
seq="$(basename $0)"
|
||||
echo "QA output created by $seq"
|
||||
|
||||
here="$PWD"
|
||||
tmp=/tmp/$$
|
||||
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 generic
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
|
||||
|
||||
on_disk_size()
|
||||
{
|
||||
du "$@" | sed -e 's/\t\+.*//'
|
||||
}
|
||||
|
||||
|
||||
img_size=1048576
|
||||
|
||||
|
||||
echo
|
||||
echo '=== Comparing empty image against sparse conversion ==='
|
||||
echo
|
||||
|
||||
_make_test_img $img_size
|
||||
|
||||
empty_size=$(on_disk_size "$TEST_IMG")
|
||||
|
||||
|
||||
$QEMU_IMG_PROG convert -O "$IMGFMT" -S 512 \
|
||||
"json:{ 'driver': 'null-co', 'size': $img_size, 'read-zeroes': true }" \
|
||||
"$TEST_IMG"
|
||||
|
||||
sparse_convert_size=$(on_disk_size "$TEST_IMG")
|
||||
|
||||
|
||||
if [ "$empty_size" -eq "$sparse_convert_size" ]; then
|
||||
echo 'Equal image size'
|
||||
else
|
||||
echo 'Different image size'
|
||||
fi
|
||||
|
||||
|
||||
echo
|
||||
echo '=== Comparing full image against non-sparse conversion ==='
|
||||
echo
|
||||
|
||||
_make_test_img $img_size
|
||||
$QEMU_IO -c "write 0 $img_size" "$TEST_IMG" | _filter_qemu_io
|
||||
|
||||
full_size=$(on_disk_size "$TEST_IMG")
|
||||
|
||||
|
||||
$QEMU_IMG convert -O "$IMGFMT" -S 0 \
|
||||
"json:{ 'driver': 'null-co', 'size': $img_size, 'read-zeroes': true }" \
|
||||
"$TEST_IMG"
|
||||
|
||||
non_sparse_convert_size=$(on_disk_size "$TEST_IMG")
|
||||
|
||||
|
||||
if [ "$full_size" -eq "$non_sparse_convert_size" ]; then
|
||||
echo 'Equal image size'
|
||||
else
|
||||
echo 'Different image size'
|
||||
fi
|
||||
|
||||
|
||||
# success, all done
|
||||
echo "*** done"
|
||||
rm -f $seq.full
|
||||
status=0
|
14
tests/qemu-iotests/150.out
Normal file
14
tests/qemu-iotests/150.out
Normal file
@ -0,0 +1,14 @@
|
||||
QA output created by 150
|
||||
|
||||
=== Comparing empty image against sparse conversion ===
|
||||
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
|
||||
Equal image size
|
||||
|
||||
=== Comparing full image against non-sparse conversion ===
|
||||
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
|
||||
wrote 1048576/1048576 bytes at offset 0
|
||||
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
Equal image size
|
||||
*** done
|
@ -155,6 +155,7 @@ check options
|
||||
-ssh test ssh
|
||||
-nfs test nfs
|
||||
-archipelago test archipelago
|
||||
-luks test luks
|
||||
-xdiff graphical mode diff
|
||||
-nocache use O_DIRECT on backing file
|
||||
-misalign misalign memory allocations
|
||||
|
@ -150,3 +150,5 @@
|
||||
145 auto quick
|
||||
146 auto quick
|
||||
148 rw auto quick
|
||||
149 rw auto sudo
|
||||
150 rw auto quick
|
||||
|
@ -29,7 +29,9 @@ import qtest
|
||||
import struct
|
||||
|
||||
__all__ = ['imgfmt', 'imgproto', 'test_dir' 'qemu_img', 'qemu_io',
|
||||
'VM', 'QMPTestCase', 'notrun', 'main']
|
||||
'VM', 'QMPTestCase', 'notrun', 'main', 'verify_image_format',
|
||||
'verify_platform', 'filter_test_dir', 'filter_win32',
|
||||
'filter_qemu_io', 'filter_chown', 'log']
|
||||
|
||||
# This will not work if arguments contain spaces but is necessary if we
|
||||
# want to support the override options that ./check supports.
|
||||
@ -71,7 +73,9 @@ def qemu_img_verbose(*args):
|
||||
|
||||
def qemu_img_pipe(*args):
|
||||
'''Run qemu-img and return its output'''
|
||||
subp = subprocess.Popen(qemu_img_args + list(args), stdout=subprocess.PIPE)
|
||||
subp = subprocess.Popen(qemu_img_args + list(args),
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT)
|
||||
exitcode = subp.wait()
|
||||
if exitcode < 0:
|
||||
sys.stderr.write('qemu-img received signal %i: %s\n' % (-exitcode, ' '.join(qemu_img_args + list(args))))
|
||||
@ -80,7 +84,8 @@ def qemu_img_pipe(*args):
|
||||
def qemu_io(*args):
|
||||
'''Run qemu-io and return the stdout data'''
|
||||
args = qemu_io_args + list(args)
|
||||
subp = subprocess.Popen(args, stdout=subprocess.PIPE)
|
||||
subp = subprocess.Popen(args, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT)
|
||||
exitcode = subp.wait()
|
||||
if exitcode < 0:
|
||||
sys.stderr.write('qemu-io received signal %i: %s\n' % (-exitcode, ' '.join(args)))
|
||||
@ -101,6 +106,28 @@ def create_image(name, size):
|
||||
i = i + 512
|
||||
file.close()
|
||||
|
||||
test_dir_re = re.compile(r"%s" % test_dir)
|
||||
def filter_test_dir(msg):
|
||||
return test_dir_re.sub("TEST_DIR", msg)
|
||||
|
||||
win32_re = re.compile(r"\r")
|
||||
def filter_win32(msg):
|
||||
return win32_re.sub("", msg)
|
||||
|
||||
qemu_io_re = re.compile(r"[0-9]* ops; [0-9\/:. sec]* \([0-9\/.inf]* [EPTGMKiBbytes]*\/sec and [0-9\/.inf]* ops\/sec\)")
|
||||
def filter_qemu_io(msg):
|
||||
msg = filter_win32(msg)
|
||||
return qemu_io_re.sub("X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)", msg)
|
||||
|
||||
chown_re = re.compile(r"chown [0-9]+:[0-9]+")
|
||||
def filter_chown(msg):
|
||||
return chown_re.sub("chown UID:GID", msg)
|
||||
|
||||
def log(msg, filters=[]):
|
||||
for flt in filters:
|
||||
msg = flt(msg)
|
||||
print msg
|
||||
|
||||
# Test if 'match' is a recursive subset of 'event'
|
||||
def event_match(event, match=None):
|
||||
if match is None:
|
||||
@ -391,16 +418,21 @@ def notrun(reason):
|
||||
print '%s not run: %s' % (seq, reason)
|
||||
sys.exit(0)
|
||||
|
||||
def verify_image_format(supported_fmts=[]):
|
||||
if supported_fmts and (imgfmt not in supported_fmts):
|
||||
notrun('not suitable for this image format: %s' % imgfmt)
|
||||
|
||||
def verify_platform(supported_oses=['linux']):
|
||||
if True not in [sys.platform.startswith(x) for x in supported_oses]:
|
||||
notrun('not suitable for this OS: %s' % sys.platform)
|
||||
|
||||
def main(supported_fmts=[], supported_oses=['linux']):
|
||||
'''Run tests'''
|
||||
|
||||
debug = '-d' in sys.argv
|
||||
verbosity = 1
|
||||
if supported_fmts and (imgfmt not in supported_fmts):
|
||||
notrun('not suitable for this image format: %s' % imgfmt)
|
||||
|
||||
if True not in [sys.platform.startswith(x) for x in supported_oses]:
|
||||
notrun('not suitable for this OS: %s' % sys.platform)
|
||||
verify_image_format(supported_fmts)
|
||||
verify_platform(supported_oses)
|
||||
|
||||
# We need to filter out the time taken from the output so that qemu-iotest
|
||||
# can reliably diff the results against master output.
|
||||
|
Loading…
Reference in New Issue
Block a user