Block layer patches

-----BEGIN PGP SIGNATURE-----
 
 iQEcBAABAgAGBQJZZPdkAAoJEPQH2wBh1c9A+9oIAInvmlySO/o/pXFI/CoHbZkU
 YxRDm2JNCpscmcTaS7T2KvFyypUTG3EW7olzK5Qb/aMHM78EEQHeciHbJ7Lpd5id
 sLnxg0mSMoTVaAG7s7aXRFc58gMfZPD1ngbaIkbpaAkDzGFTgKyWwemi/Ic/We1z
 2ULK6YSVbinwP2b2T6v3N4TABxKKnvBtPo4CdQy87BV1mJF+Mv7F9TyVIsaH0B2I
 DIvLOitmbeahh0rwrj2ffWc2TAUlje8h0AN7/4YW/dA6HWT4tcB6ykzmN0Jo7Oe+
 /2JUd/VjDpYyP4XTpiu4+TTWOKXs14vvefZeSNy7rLF/oRcB4L0CTXzTJFv3Epk=
 =o7Us
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/maxreitz/tags/pull-block-2017-07-11' into staging

Block layer patches

# gpg: Signature made Tue 11 Jul 2017 17:05:56 BST
# gpg:                using RSA key 0xF407DB0061D5CF40
# gpg: Good signature from "Max Reitz <mreitz@redhat.com>"
# Primary key fingerprint: 91BE B60A 30DB 3E88 57D1  1829 F407 DB00 61D5 CF40

* remotes/maxreitz/tags/pull-block-2017-07-11: (85 commits)
  iotests: Add preallocated growth test for qcow2
  iotests: Add preallocated resize test for raw
  block/qcow2: falloc/full preallocating growth
  block/qcow2: Rename "fail_block" to just "fail"
  block/qcow2: Add qcow2_refcount_area()
  block/qcow2: Metadata preallocation for truncate
  block/qcow2: Lock s->lock in preallocate()
  block/qcow2: Generalize preallocate()
  block/file-posix: Preallocation for truncate
  block/file-posix: Generalize raw_regular_truncate
  block/file-posix: Extract raw_regular_truncate()
  block/file-posix: Small fixes in raw_create()
  qemu-img: Expose PreallocMode for resizing
  block: Add PreallocMode to blk_truncate()
  block: Add PreallocMode to bdrv_truncate()
  block: Add PreallocMode to BD.bdrv_truncate()
  iotests: add test 178 for qemu-img measure
  qemu-iotests: support per-format golden output files
  qemu-img: add measure subcommand
  qcow2: add bdrv_measure() support
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2017-07-13 13:38:57 +01:00
commit 76fba746ea
123 changed files with 7560 additions and 1651 deletions

183
block.c
View File

@ -2185,6 +2185,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
ret = -EINVAL;
goto free_exit;
}
bdrv_set_aio_context(backing_hd, bdrv_get_aio_context(bs));
/* Hook up the backing file link; drop our reference, bs owns the
* backing_hd reference now */
@ -2573,15 +2574,7 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
goto close_and_fail;
}
if (!bdrv_key_required(bs)) {
bdrv_parent_cb_change_media(bs, true);
} else if (!runstate_check(RUN_STATE_PRELAUNCH)
&& !runstate_check(RUN_STATE_INMIGRATE)
&& !runstate_check(RUN_STATE_PAUSED)) { /* HACK */
error_setg(errp,
"Guest must be stopped for opening of encrypted image");
goto close_and_fail;
}
bdrv_parent_cb_change_media(bs, true);
QDECREF(options);
@ -2989,24 +2982,45 @@ error:
void bdrv_reopen_commit(BDRVReopenState *reopen_state)
{
BlockDriver *drv;
BlockDriverState *bs;
bool old_can_write, new_can_write;
assert(reopen_state != NULL);
drv = reopen_state->bs->drv;
bs = reopen_state->bs;
drv = bs->drv;
assert(drv != NULL);
old_can_write =
!bdrv_is_read_only(bs) && !(bdrv_get_flags(bs) & BDRV_O_INACTIVE);
/* If there are any driver level actions to take */
if (drv->bdrv_reopen_commit) {
drv->bdrv_reopen_commit(reopen_state);
}
/* set BDS specific flags now */
QDECREF(reopen_state->bs->explicit_options);
QDECREF(bs->explicit_options);
reopen_state->bs->explicit_options = reopen_state->explicit_options;
reopen_state->bs->open_flags = reopen_state->flags;
reopen_state->bs->read_only = !(reopen_state->flags & BDRV_O_RDWR);
bs->explicit_options = reopen_state->explicit_options;
bs->open_flags = reopen_state->flags;
bs->read_only = !(reopen_state->flags & BDRV_O_RDWR);
bdrv_refresh_limits(reopen_state->bs, NULL);
bdrv_refresh_limits(bs, NULL);
new_can_write =
!bdrv_is_read_only(bs) && !(bdrv_get_flags(bs) & BDRV_O_INACTIVE);
if (!old_can_write && new_can_write && drv->bdrv_reopen_bitmaps_rw) {
Error *local_err = NULL;
if (drv->bdrv_reopen_bitmaps_rw(bs, &local_err) < 0) {
/* This is not fatal, bitmaps just left read-only, so all following
* writes will fail. User can remove read-only bitmaps to unblock
* writes.
*/
error_reportf_err(local_err,
"%s: Failed to make dirty bitmaps writable: ",
bdrv_get_node_name(bs));
}
}
}
/*
@ -3040,9 +3054,6 @@ static void bdrv_close(BlockDriverState *bs)
bdrv_flush(bs);
bdrv_drain(bs); /* in case flush left pending I/O */
bdrv_release_named_dirty_bitmaps(bs);
assert(QLIST_EMPTY(&bs->dirty_bitmaps));
if (bs->drv) {
BdrvChild *child, *next;
@ -3072,7 +3083,6 @@ static void bdrv_close(BlockDriverState *bs)
bs->backing_format[0] = '\0';
bs->total_sectors = 0;
bs->encrypted = false;
bs->valid_key = false;
bs->sg = false;
QDECREF(bs->options);
QDECREF(bs->explicit_options);
@ -3081,6 +3091,9 @@ static void bdrv_close(BlockDriverState *bs)
bs->full_open_options = NULL;
}
bdrv_release_named_dirty_bitmaps(bs);
assert(QLIST_EMPTY(&bs->dirty_bitmaps));
QLIST_FOREACH_SAFE(ban, &bs->aio_notifiers, list, ban_next) {
g_free(ban);
}
@ -3398,7 +3411,8 @@ exit:
/**
* Truncate file to 'offset' bytes (needed only for file protocols)
*/
int bdrv_truncate(BdrvChild *child, int64_t offset, Error **errp)
int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc,
Error **errp)
{
BlockDriverState *bs = child->bs;
BlockDriver *drv = bs->drv;
@ -3421,7 +3435,7 @@ int bdrv_truncate(BdrvChild *child, int64_t offset, Error **errp)
assert(!(bs->open_flags & BDRV_O_INACTIVE));
ret = drv->bdrv_truncate(bs, offset, errp);
ret = drv->bdrv_truncate(bs, offset, prealloc, errp);
if (ret == 0) {
ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
bdrv_dirty_bitmap_truncate(bs);
@ -3450,6 +3464,41 @@ int64_t bdrv_get_allocated_file_size(BlockDriverState *bs)
return -ENOTSUP;
}
/*
* bdrv_measure:
* @drv: Format driver
* @opts: Creation options for new image
* @in_bs: Existing image containing data for new image (may be NULL)
* @errp: Error object
* Returns: A #BlockMeasureInfo (free using qapi_free_BlockMeasureInfo())
* or NULL on error
*
* Calculate file size required to create a new image.
*
* If @in_bs is given then space for allocated clusters and zero clusters
* from that image are included in the calculation. If @opts contains a
* backing file that is shared by @in_bs then backing clusters may be omitted
* from the calculation.
*
* If @in_bs is NULL then the calculation includes no allocated clusters
* unless a preallocation option is given in @opts.
*
* Note that @in_bs may use a different BlockDriver from @drv.
*
* If an error occurs the @errp pointer is set.
*/
BlockMeasureInfo *bdrv_measure(BlockDriver *drv, QemuOpts *opts,
BlockDriverState *in_bs, Error **errp)
{
if (!drv->bdrv_measure) {
error_setg(errp, "Block driver '%s' does not support size measurement",
drv->format_name);
return NULL;
}
return drv->bdrv_measure(opts, in_bs, errp);
}
/**
* Return number of sectors on success, -errno on error.
*/
@ -3502,72 +3551,6 @@ bool bdrv_is_encrypted(BlockDriverState *bs)
return bs->encrypted;
}
bool bdrv_key_required(BlockDriverState *bs)
{
BdrvChild *backing = bs->backing;
if (backing && backing->bs->encrypted && !backing->bs->valid_key) {
return true;
}
return (bs->encrypted && !bs->valid_key);
}
int bdrv_set_key(BlockDriverState *bs, const char *key)
{
int ret;
if (bs->backing && bs->backing->bs->encrypted) {
ret = bdrv_set_key(bs->backing->bs, key);
if (ret < 0)
return ret;
if (!bs->encrypted)
return 0;
}
if (!bs->encrypted) {
return -EINVAL;
} else if (!bs->drv || !bs->drv->bdrv_set_key) {
return -ENOMEDIUM;
}
ret = bs->drv->bdrv_set_key(bs, key);
if (ret < 0) {
bs->valid_key = false;
} else if (!bs->valid_key) {
/* call the change callback now, we skipped it on open */
bs->valid_key = true;
bdrv_parent_cb_change_media(bs, true);
}
return ret;
}
/*
* Provide an encryption key for @bs.
* If @key is non-null:
* If @bs is not encrypted, fail.
* Else if the key is invalid, fail.
* Else set @bs's key to @key, replacing the existing key, if any.
* If @key is null:
* If @bs is encrypted and still lacks a key, fail.
* Else do nothing.
* On failure, store an error object through @errp if non-null.
*/
void bdrv_add_key(BlockDriverState *bs, const char *key, Error **errp)
{
if (key) {
if (!bdrv_is_encrypted(bs)) {
error_setg(errp, "Node '%s' is not encrypted",
bdrv_get_device_or_node_name(bs));
} else if (bdrv_set_key(bs, key) < 0) {
error_setg(errp, QERR_INVALID_PASSWORD);
}
} else {
if (bdrv_key_required(bs)) {
error_set(errp, ERROR_CLASS_DEVICE_ENCRYPTED,
"'%s' (%s) is encrypted",
bdrv_get_device_or_node_name(bs),
bdrv_get_encrypted_filename(bs));
}
}
}
const char *bdrv_get_format_name(BlockDriverState *bs)
{
return bs->drv ? bs->drv->format_name : NULL;
@ -4135,6 +4118,10 @@ static int bdrv_inactivate_recurse(BlockDriverState *bs,
}
}
/* At this point persistent bitmaps should be already stored by the format
* driver */
bdrv_release_persistent_dirty_bitmaps(bs);
return 0;
}
@ -4933,3 +4920,25 @@ void bdrv_del_child(BlockDriverState *parent_bs, BdrvChild *child, Error **errp)
parent_bs->drv->bdrv_del_child(parent_bs, child, errp);
}
bool bdrv_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name,
uint32_t granularity, Error **errp)
{
BlockDriver *drv = bs->drv;
if (!drv) {
error_setg_errno(errp, ENOMEDIUM,
"Can't store persistent bitmaps to %s",
bdrv_get_device_or_node_name(bs));
return false;
}
if (!drv->bdrv_can_store_new_dirty_bitmap) {
error_setg_errno(errp, ENOTSUP,
"Can't store persistent bitmaps to %s",
bdrv_get_device_or_node_name(bs));
return false;
}
return drv->bdrv_can_store_new_dirty_bitmap(bs, name, granularity, errp);
}

View File

@ -1,5 +1,5 @@
block-obj-y += raw-format.o qcow.o vdi.o vmdk.o cloop.o bochs.o vpc.o vvfat.o dmg.o
block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o
block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o qcow2-bitmap.o
block-obj-y += qed.o qed-l2-cache.o qed-table.o qed-cluster.o
block-obj-y += qed-check.o
block-obj-y += vhdx.o vhdx-endian.o vhdx-log.o

View File

@ -821,9 +821,10 @@ static int64_t blkdebug_getlength(BlockDriverState *bs)
return bdrv_getlength(bs->file->bs);
}
static int blkdebug_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
static int blkdebug_truncate(BlockDriverState *bs, int64_t offset,
PreallocMode prealloc, Error **errp)
{
return bdrv_truncate(bs->file, offset, errp);
return bdrv_truncate(bs->file, offset, prealloc, errp);
}
static void blkdebug_refresh_filename(BlockDriverState *bs, QDict *options)

View File

@ -1773,14 +1773,15 @@ int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf,
BDRV_REQ_WRITE_COMPRESSED);
}
int blk_truncate(BlockBackend *blk, int64_t offset, Error **errp)
int blk_truncate(BlockBackend *blk, int64_t offset, PreallocMode prealloc,
Error **errp)
{
if (!blk_is_available(blk)) {
error_setg(errp, "No medium inserted");
return -ENOMEDIUM;
}
return bdrv_truncate(blk->root, offset, errp);
return bdrv_truncate(blk->root, offset, prealloc, errp);
}
static void blk_pdiscard_entry(void *opaque)

View File

@ -163,7 +163,7 @@ static void coroutine_fn commit_run(void *opaque)
}
if (base_len < s->common.len) {
ret = blk_truncate(s->base, s->common.len, NULL);
ret = blk_truncate(s->base, s->common.len, PREALLOC_MODE_OFF, NULL);
if (ret) {
goto out;
}
@ -521,7 +521,7 @@ int bdrv_commit(BlockDriverState *bs)
* grow the backing file image if possible. If not possible,
* we must return an error */
if (length > backing_length) {
ret = blk_truncate(backing, length, &local_err);
ret = blk_truncate(backing, length, PREALLOC_MODE_OFF, &local_err);
if (ret < 0) {
error_report_err(local_err);
goto ro_cleanup;

View File

@ -24,16 +24,10 @@
#include "sysemu/block-backend.h"
#include "crypto/block.h"
#include "qapi/opts-visitor.h"
#include "qapi/qobject-input-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"
#define BLOCK_CRYPTO_OPT_LUKS_ITER_TIME "iter-time"
#include "block/crypto.h"
typedef struct BlockCrypto BlockCrypto;
@ -135,11 +129,7 @@ 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",
},
BLOCK_CRYPTO_OPT_DEF_LUKS_KEY_SECRET(""),
{ /* end of list */ }
},
};
@ -154,49 +144,21 @@ static QemuOptsList block_crypto_create_opts_luks = {
.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",
},
{
.name = BLOCK_CRYPTO_OPT_LUKS_ITER_TIME,
.type = QEMU_OPT_NUMBER,
.help = "Time to spend in PBKDF in milliseconds",
},
BLOCK_CRYPTO_OPT_DEF_LUKS_KEY_SECRET(""),
BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_ALG(""),
BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_MODE(""),
BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_ALG(""),
BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_HASH_ALG(""),
BLOCK_CRYPTO_OPT_DEF_LUKS_HASH_ALG(""),
BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME(""),
{ /* end of list */ }
},
};
static QCryptoBlockOpenOptions *
QCryptoBlockOpenOptions *
block_crypto_open_opts_init(QCryptoBlockFormat format,
QemuOpts *opts,
QDict *opts,
Error **errp)
{
Visitor *v;
@ -206,7 +168,7 @@ block_crypto_open_opts_init(QCryptoBlockFormat format,
ret = g_new0(QCryptoBlockOpenOptions, 1);
ret->format = format;
v = opts_visitor_new(opts);
v = qobject_input_visitor_new_keyval(QOBJECT(opts));
visit_start_struct(v, NULL, NULL, 0, &local_err);
if (local_err) {
@ -219,6 +181,11 @@ block_crypto_open_opts_init(QCryptoBlockFormat format,
v, &ret->u.luks, &local_err);
break;
case Q_CRYPTO_BLOCK_FORMAT_QCOW:
visit_type_QCryptoBlockOptionsQCow_members(
v, &ret->u.qcow, &local_err);
break;
default:
error_setg(&local_err, "Unsupported block format %d", format);
break;
@ -240,9 +207,9 @@ block_crypto_open_opts_init(QCryptoBlockFormat format,
}
static QCryptoBlockCreateOptions *
QCryptoBlockCreateOptions *
block_crypto_create_opts_init(QCryptoBlockFormat format,
QemuOpts *opts,
QDict *opts,
Error **errp)
{
Visitor *v;
@ -252,7 +219,7 @@ block_crypto_create_opts_init(QCryptoBlockFormat format,
ret = g_new0(QCryptoBlockCreateOptions, 1);
ret->format = format;
v = opts_visitor_new(opts);
v = qobject_input_visitor_new_keyval(QOBJECT(opts));
visit_start_struct(v, NULL, NULL, 0, &local_err);
if (local_err) {
@ -265,6 +232,11 @@ block_crypto_create_opts_init(QCryptoBlockFormat format,
v, &ret->u.luks, &local_err);
break;
case Q_CRYPTO_BLOCK_FORMAT_QCOW:
visit_type_QCryptoBlockOptionsQCow_members(
v, &ret->u.qcow, &local_err);
break;
default:
error_setg(&local_err, "Unsupported block format %d", format);
break;
@ -299,6 +271,7 @@ static int block_crypto_open_generic(QCryptoBlockFormat format,
int ret = -EINVAL;
QCryptoBlockOpenOptions *open_opts = NULL;
unsigned int cflags = 0;
QDict *cryptoopts = NULL;
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
false, errp);
@ -313,7 +286,9 @@ static int block_crypto_open_generic(QCryptoBlockFormat format,
goto cleanup;
}
open_opts = block_crypto_open_opts_init(format, opts, errp);
cryptoopts = qemu_opts_to_qdict(opts, NULL);
open_opts = block_crypto_open_opts_init(format, cryptoopts, errp);
if (!open_opts) {
goto cleanup;
}
@ -321,7 +296,7 @@ static int block_crypto_open_generic(QCryptoBlockFormat format,
if (flags & BDRV_O_NO_IO) {
cflags |= QCRYPTO_BLOCK_OPEN_NO_IO;
}
crypto->block = qcrypto_block_open(open_opts,
crypto->block = qcrypto_block_open(open_opts, NULL,
block_crypto_read_func,
bs,
cflags,
@ -333,10 +308,10 @@ static int block_crypto_open_generic(QCryptoBlockFormat format,
}
bs->encrypted = true;
bs->valid_key = true;
ret = 0;
cleanup:
QDECREF(cryptoopts);
qapi_free_QCryptoBlockOpenOptions(open_opts);
return ret;
}
@ -356,13 +331,16 @@ static int block_crypto_create_generic(QCryptoBlockFormat format,
.opts = opts,
.filename = filename,
};
QDict *cryptoopts;
create_opts = block_crypto_create_opts_init(format, opts, errp);
cryptoopts = qemu_opts_to_qdict(opts, NULL);
create_opts = block_crypto_create_opts_init(format, cryptoopts, errp);
if (!create_opts) {
return -1;
}
crypto = qcrypto_block_create(create_opts,
crypto = qcrypto_block_create(create_opts, NULL,
block_crypto_init_func,
block_crypto_write_func,
&data,
@ -375,6 +353,7 @@ static int block_crypto_create_generic(QCryptoBlockFormat format,
ret = 0;
cleanup:
QDECREF(cryptoopts);
qcrypto_block_free(crypto);
blk_unref(data.blk);
qapi_free_QCryptoBlockCreateOptions(create_opts);
@ -382,7 +361,7 @@ static int block_crypto_create_generic(QCryptoBlockFormat format,
}
static int block_crypto_truncate(BlockDriverState *bs, int64_t offset,
Error **errp)
PreallocMode prealloc, Error **errp)
{
BlockCrypto *crypto = bs->opaque;
size_t payload_offset =
@ -390,7 +369,7 @@ static int block_crypto_truncate(BlockDriverState *bs, int64_t offset,
offset += payload_offset;
return bdrv_truncate(bs->file, offset, errp);
return bdrv_truncate(bs->file, offset, prealloc, errp);
}
static void block_crypto_close(BlockDriverState *bs)

101
block/crypto.h Normal file
View File

@ -0,0 +1,101 @@
/*
* QEMU block full disk encryption
*
* Copyright (c) 2015-2017 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/>.
*
*/
#ifndef BLOCK_CRYPTO_H__
#define BLOCK_CRYPTO_H__
#define BLOCK_CRYPTO_OPT_DEF_KEY_SECRET(prefix, helpstr) \
{ \
.name = prefix BLOCK_CRYPTO_OPT_QCOW_KEY_SECRET, \
.type = QEMU_OPT_STRING, \
.help = helpstr, \
}
#define BLOCK_CRYPTO_OPT_QCOW_KEY_SECRET "key-secret"
#define BLOCK_CRYPTO_OPT_DEF_QCOW_KEY_SECRET(prefix) \
BLOCK_CRYPTO_OPT_DEF_KEY_SECRET(prefix, \
"ID of the secret that provides the AES encryption key")
#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"
#define BLOCK_CRYPTO_OPT_LUKS_ITER_TIME "iter-time"
#define BLOCK_CRYPTO_OPT_DEF_LUKS_KEY_SECRET(prefix) \
BLOCK_CRYPTO_OPT_DEF_KEY_SECRET(prefix, \
"ID of the secret that provides the keyslot passphrase")
#define BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_ALG(prefix) \
{ \
.name = prefix BLOCK_CRYPTO_OPT_LUKS_CIPHER_ALG, \
.type = QEMU_OPT_STRING, \
.help = "Name of encryption cipher algorithm", \
}
#define BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_MODE(prefix) \
{ \
.name = prefix BLOCK_CRYPTO_OPT_LUKS_CIPHER_MODE, \
.type = QEMU_OPT_STRING, \
.help = "Name of encryption cipher mode", \
}
#define BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_ALG(prefix) \
{ \
.name = prefix BLOCK_CRYPTO_OPT_LUKS_IVGEN_ALG, \
.type = QEMU_OPT_STRING, \
.help = "Name of IV generator algorithm", \
}
#define BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_HASH_ALG(prefix) \
{ \
.name = prefix BLOCK_CRYPTO_OPT_LUKS_IVGEN_HASH_ALG, \
.type = QEMU_OPT_STRING, \
.help = "Name of IV generator hash algorithm", \
}
#define BLOCK_CRYPTO_OPT_DEF_LUKS_HASH_ALG(prefix) \
{ \
.name = prefix BLOCK_CRYPTO_OPT_LUKS_HASH_ALG, \
.type = QEMU_OPT_STRING, \
.help = "Name of encryption hash algorithm", \
}
#define BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME(prefix) \
{ \
.name = prefix BLOCK_CRYPTO_OPT_LUKS_ITER_TIME, \
.type = QEMU_OPT_NUMBER, \
.help = "Time to spend in PBKDF in milliseconds", \
}
QCryptoBlockCreateOptions *
block_crypto_create_opts_init(QCryptoBlockFormat format,
QDict *opts,
Error **errp);
QCryptoBlockOpenOptions *
block_crypto_open_opts_init(QCryptoBlockFormat format,
QDict *opts,
Error **errp);
#endif /* BLOCK_CRYPTO_H__ */

View File

@ -43,8 +43,18 @@ struct BdrvDirtyBitmap {
BdrvDirtyBitmap *successor; /* Anonymous child; implies frozen status */
char *name; /* Optional non-empty unique ID */
int64_t size; /* Size of the bitmap (Number of sectors) */
bool disabled; /* Bitmap is read-only */
bool disabled; /* Bitmap is disabled. It ignores all writes to
the device */
int active_iterators; /* How many iterators are active */
bool readonly; /* Bitmap is read-only. This field also
prevents the respective image from being
modified (i.e. blocks writes and discards).
Such operations must fail and both the image
and this bitmap must remain unchanged while
this flag is set. */
bool autoload; /* For persistent bitmaps: bitmap must be
autoloaded on image opening */
bool persistent; /* bitmap must be saved to owner disk image */
QLIST_ENTRY(BdrvDirtyBitmap) list;
};
@ -93,6 +103,8 @@ void bdrv_dirty_bitmap_make_anon(BdrvDirtyBitmap *bitmap)
assert(!bdrv_dirty_bitmap_frozen(bitmap));
g_free(bitmap->name);
bitmap->name = NULL;
bitmap->persistent = false;
bitmap->autoload = false;
}
/* Called with BQL taken. */
@ -289,6 +301,10 @@ BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs,
bitmap->name = NULL;
successor->name = name;
bitmap->successor = NULL;
successor->persistent = bitmap->persistent;
bitmap->persistent = false;
successor->autoload = bitmap->autoload;
bitmap->autoload = false;
bdrv_release_dirty_bitmap(bs, bitmap);
return successor;
@ -340,15 +356,20 @@ void bdrv_dirty_bitmap_truncate(BlockDriverState *bs)
bdrv_dirty_bitmaps_unlock(bs);
}
static bool bdrv_dirty_bitmap_has_name(BdrvDirtyBitmap *bitmap)
{
return !!bdrv_dirty_bitmap_name(bitmap);
}
/* Called with BQL taken. */
static void bdrv_do_release_matching_dirty_bitmap(BlockDriverState *bs,
BdrvDirtyBitmap *bitmap,
bool only_named)
static void bdrv_do_release_matching_dirty_bitmap(
BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
bool (*cond)(BdrvDirtyBitmap *bitmap))
{
BdrvDirtyBitmap *bm, *next;
bdrv_dirty_bitmaps_lock(bs);
QLIST_FOREACH_SAFE(bm, &bs->dirty_bitmaps, list, next) {
if ((!bitmap || bm == bitmap) && (!only_named || bm->name)) {
if ((!bitmap || bm == bitmap) && (!cond || cond(bm))) {
assert(!bm->active_iterators);
assert(!bdrv_dirty_bitmap_frozen(bm));
assert(!bm->meta);
@ -373,17 +394,47 @@ out:
/* Called with BQL taken. */
void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
{
bdrv_do_release_matching_dirty_bitmap(bs, bitmap, false);
bdrv_do_release_matching_dirty_bitmap(bs, bitmap, NULL);
}
/**
* Release all named dirty bitmaps attached to a BDS (for use in bdrv_close()).
* There must not be any frozen bitmaps attached.
* This function does not remove persistent bitmaps from the storage.
* Called with BQL taken.
*/
void bdrv_release_named_dirty_bitmaps(BlockDriverState *bs)
{
bdrv_do_release_matching_dirty_bitmap(bs, NULL, true);
bdrv_do_release_matching_dirty_bitmap(bs, NULL, bdrv_dirty_bitmap_has_name);
}
/**
* Release all persistent dirty bitmaps attached to a BDS (for use in
* bdrv_inactivate_recurse()).
* There must not be any frozen bitmaps attached.
* This function does not remove persistent bitmaps from the storage.
*/
void bdrv_release_persistent_dirty_bitmaps(BlockDriverState *bs)
{
bdrv_do_release_matching_dirty_bitmap(bs, NULL,
bdrv_dirty_bitmap_get_persistance);
}
/**
* Remove persistent dirty bitmap from the storage if it exists.
* Absence of bitmap is not an error, because we have the following scenario:
* BdrvDirtyBitmap can have .persistent = true but not yet saved and have no
* stored version. For such bitmap bdrv_remove_persistent_dirty_bitmap() should
* not fail.
* This function doesn't release corresponding BdrvDirtyBitmap.
*/
void bdrv_remove_persistent_dirty_bitmap(BlockDriverState *bs,
const char *name,
Error **errp)
{
if (bs->drv && bs->drv->bdrv_remove_persistent_dirty_bitmap) {
bs->drv->bdrv_remove_persistent_dirty_bitmap(bs, name, errp);
}
}
/* Called with BQL taken. */
@ -455,7 +506,7 @@ uint32_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs)
return granularity;
}
uint32_t bdrv_dirty_bitmap_granularity(BdrvDirtyBitmap *bitmap)
uint32_t bdrv_dirty_bitmap_granularity(const BdrvDirtyBitmap *bitmap)
{
return BDRV_SECTOR_SIZE << hbitmap_granularity(bitmap->bitmap);
}
@ -504,6 +555,7 @@ void bdrv_set_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
int64_t cur_sector, int64_t nr_sectors)
{
assert(bdrv_dirty_bitmap_enabled(bitmap));
assert(!bdrv_dirty_bitmap_readonly(bitmap));
hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors);
}
@ -520,6 +572,7 @@ void bdrv_reset_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
int64_t cur_sector, int64_t nr_sectors)
{
assert(bdrv_dirty_bitmap_enabled(bitmap));
assert(!bdrv_dirty_bitmap_readonly(bitmap));
hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors);
}
@ -534,6 +587,7 @@ void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out)
{
assert(bdrv_dirty_bitmap_enabled(bitmap));
assert(!bdrv_dirty_bitmap_readonly(bitmap));
bdrv_dirty_bitmap_lock(bitmap);
if (!out) {
hbitmap_reset_all(bitmap->bitmap);
@ -550,6 +604,7 @@ void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *in)
{
HBitmap *tmp = bitmap->bitmap;
assert(bdrv_dirty_bitmap_enabled(bitmap));
assert(!bdrv_dirty_bitmap_readonly(bitmap));
bitmap->bitmap = in;
hbitmap_free(tmp);
}
@ -586,6 +641,13 @@ void bdrv_dirty_bitmap_deserialize_zeroes(BdrvDirtyBitmap *bitmap,
hbitmap_deserialize_zeroes(bitmap->bitmap, start, count, finish);
}
void bdrv_dirty_bitmap_deserialize_ones(BdrvDirtyBitmap *bitmap,
uint64_t start, uint64_t count,
bool finish)
{
hbitmap_deserialize_ones(bitmap->bitmap, start, count, finish);
}
void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap)
{
hbitmap_deserialize_finish(bitmap->bitmap);
@ -605,6 +667,7 @@ void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
if (!bdrv_dirty_bitmap_enabled(bitmap)) {
continue;
}
assert(!bdrv_dirty_bitmap_readonly(bitmap));
hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors);
}
bdrv_dirty_bitmaps_unlock(bs);
@ -627,3 +690,78 @@ int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap)
{
return hbitmap_count(bitmap->meta);
}
bool bdrv_dirty_bitmap_readonly(const BdrvDirtyBitmap *bitmap)
{
return bitmap->readonly;
}
/* Called with BQL taken. */
void bdrv_dirty_bitmap_set_readonly(BdrvDirtyBitmap *bitmap, bool value)
{
qemu_mutex_lock(bitmap->mutex);
bitmap->readonly = value;
qemu_mutex_unlock(bitmap->mutex);
}
bool bdrv_has_readonly_bitmaps(BlockDriverState *bs)
{
BdrvDirtyBitmap *bm;
QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) {
if (bm->readonly) {
return true;
}
}
return false;
}
/* Called with BQL taken. */
void bdrv_dirty_bitmap_set_autoload(BdrvDirtyBitmap *bitmap, bool autoload)
{
qemu_mutex_lock(bitmap->mutex);
bitmap->autoload = autoload;
qemu_mutex_unlock(bitmap->mutex);
}
bool bdrv_dirty_bitmap_get_autoload(const BdrvDirtyBitmap *bitmap)
{
return bitmap->autoload;
}
/* Called with BQL taken. */
void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap, bool persistent)
{
qemu_mutex_lock(bitmap->mutex);
bitmap->persistent = persistent;
qemu_mutex_unlock(bitmap->mutex);
}
bool bdrv_dirty_bitmap_get_persistance(BdrvDirtyBitmap *bitmap)
{
return bitmap->persistent;
}
bool bdrv_has_changed_persistent_bitmaps(BlockDriverState *bs)
{
BdrvDirtyBitmap *bm;
QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) {
if (bm->persistent && !bm->readonly) {
return true;
}
}
return false;
}
BdrvDirtyBitmap *bdrv_dirty_bitmap_next(BlockDriverState *bs,
BdrvDirtyBitmap *bitmap)
{
return bitmap == NULL ? QLIST_FIRST(&bs->dirty_bitmaps) :
QLIST_NEXT(bitmap, list);
}
char *bdrv_dirty_bitmap_sha256(const BdrvDirtyBitmap *bitmap, Error **errp)
{
return hbitmap_sha256(bitmap->bitmap, errp);
}

View File

@ -1624,7 +1624,122 @@ static void raw_close(BlockDriverState *bs)
}
}
static int raw_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
/**
* Truncates the given regular file @fd to @offset and, when growing, fills the
* new space according to @prealloc.
*
* Returns: 0 on success, -errno on failure.
*/
static int raw_regular_truncate(int fd, int64_t offset, PreallocMode prealloc,
Error **errp)
{
int result = 0;
int64_t current_length = 0;
char *buf = NULL;
struct stat st;
if (fstat(fd, &st) < 0) {
result = -errno;
error_setg_errno(errp, -result, "Could not stat file");
return result;
}
current_length = st.st_size;
if (current_length > offset && prealloc != PREALLOC_MODE_OFF) {
error_setg(errp, "Cannot use preallocation for shrinking files");
return -ENOTSUP;
}
switch (prealloc) {
#ifdef CONFIG_POSIX_FALLOCATE
case PREALLOC_MODE_FALLOC:
/*
* Truncating before posix_fallocate() makes it about twice slower on
* file systems that do not support fallocate(), trying to check if a
* block is allocated before allocating it, so don't do that here.
*/
result = -posix_fallocate(fd, current_length, offset - current_length);
if (result != 0) {
/* posix_fallocate() doesn't set errno. */
error_setg_errno(errp, -result,
"Could not preallocate new data");
}
goto out;
#endif
case PREALLOC_MODE_FULL:
{
int64_t num = 0, left = offset - current_length;
/*
* Knowing the final size from the beginning could allow the file
* system driver to do less allocations and possibly avoid
* fragmentation of the file.
*/
if (ftruncate(fd, offset) != 0) {
result = -errno;
error_setg_errno(errp, -result, "Could not resize file");
goto out;
}
buf = g_malloc0(65536);
result = lseek(fd, current_length, SEEK_SET);
if (result < 0) {
result = -errno;
error_setg_errno(errp, -result,
"Failed to seek to the old end of file");
goto out;
}
while (left > 0) {
num = MIN(left, 65536);
result = write(fd, buf, num);
if (result < 0) {
result = -errno;
error_setg_errno(errp, -result,
"Could not write zeros for preallocation");
goto out;
}
left -= result;
}
if (result >= 0) {
result = fsync(fd);
if (result < 0) {
result = -errno;
error_setg_errno(errp, -result,
"Could not flush file to disk");
goto out;
}
}
goto out;
}
case PREALLOC_MODE_OFF:
if (ftruncate(fd, offset) != 0) {
result = -errno;
error_setg_errno(errp, -result, "Could not resize file");
}
return result;
default:
result = -ENOTSUP;
error_setg(errp, "Unsupported preallocation mode: %s",
PreallocMode_lookup[prealloc]);
return result;
}
out:
if (result < 0) {
if (ftruncate(fd, current_length) < 0) {
error_report("Failed to restore old file length: %s",
strerror(errno));
}
}
g_free(buf);
return result;
}
static int raw_truncate(BlockDriverState *bs, int64_t offset,
PreallocMode prealloc, Error **errp)
{
BDRVRawState *s = bs->opaque;
struct stat st;
@ -1637,12 +1752,16 @@ static int raw_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
}
if (S_ISREG(st.st_mode)) {
if (ftruncate(s->fd, offset) < 0) {
ret = -errno;
error_setg_errno(errp, -ret, "Failed to resize the file");
return ret;
}
} else if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) {
return raw_regular_truncate(s->fd, offset, prealloc, errp);
}
if (prealloc != PREALLOC_MODE_OFF) {
error_setg(errp, "Preallocation mode '%s' unsupported for this "
"non-regular file", PreallocMode_lookup[prealloc]);
return -ENOTSUP;
}
if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) {
if (offset > raw_getlength(bs)) {
error_setg(errp, "Cannot grow device files");
return -EINVAL;
@ -1885,71 +2004,9 @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
#endif
}
switch (prealloc) {
#ifdef CONFIG_POSIX_FALLOCATE
case PREALLOC_MODE_FALLOC:
/*
* Truncating before posix_fallocate() makes it about twice slower on
* file systems that do not support fallocate(), trying to check if a
* block is allocated before allocating it, so don't do that here.
*/
result = -posix_fallocate(fd, 0, total_size);
if (result != 0) {
/* posix_fallocate() doesn't set errno. */
error_setg_errno(errp, -result,
"Could not preallocate data for the new file");
}
break;
#endif
case PREALLOC_MODE_FULL:
{
/*
* Knowing the final size from the beginning could allow the file
* system driver to do less allocations and possibly avoid
* fragmentation of the file.
*/
if (ftruncate(fd, total_size) != 0) {
result = -errno;
error_setg_errno(errp, -result, "Could not resize file");
goto out_close;
}
int64_t num = 0, left = total_size;
buf = g_malloc0(65536);
while (left > 0) {
num = MIN(left, 65536);
result = write(fd, buf, num);
if (result < 0) {
result = -errno;
error_setg_errno(errp, -result,
"Could not write to the new file");
break;
}
left -= result;
}
if (result >= 0) {
result = fsync(fd);
if (result < 0) {
result = -errno;
error_setg_errno(errp, -result,
"Could not flush new file to disk");
}
}
g_free(buf);
break;
}
case PREALLOC_MODE_OFF:
if (ftruncate(fd, total_size) != 0) {
result = -errno;
error_setg_errno(errp, -result, "Could not resize file");
}
break;
default:
result = -EINVAL;
error_setg(errp, "Unsupported preallocation mode: %s",
PreallocMode_lookup[prealloc]);
break;
result = raw_regular_truncate(fd, total_size, prealloc, errp);
if (result < 0) {
goto out_close;
}
out_close:

View File

@ -461,12 +461,19 @@ static void raw_close(BlockDriverState *bs)
}
}
static int raw_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
static int raw_truncate(BlockDriverState *bs, int64_t offset,
PreallocMode prealloc, Error **errp)
{
BDRVRawState *s = bs->opaque;
LONG low, high;
DWORD dwPtrLow;
if (prealloc != PREALLOC_MODE_OFF) {
error_setg(errp, "Unsupported preallocation mode '%s'",
PreallocMode_lookup[prealloc]);
return -ENOTSUP;
}
low = offset;
high = offset >> 32;

View File

@ -1096,11 +1096,17 @@ static coroutine_fn int qemu_gluster_co_rw(BlockDriverState *bs,
}
static int qemu_gluster_truncate(BlockDriverState *bs, int64_t offset,
Error **errp)
PreallocMode prealloc, Error **errp)
{
int ret;
BDRVGlusterState *s = bs->opaque;
if (prealloc != PREALLOC_MODE_OFF) {
error_setg(errp, "Unsupported preallocation mode '%s'",
PreallocMode_lookup[prealloc]);
return -ENOTSUP;
}
ret = glfs_ftruncate(s->fd, offset);
if (ret < 0) {
ret = -errno;

View File

@ -1315,6 +1315,10 @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
uint64_t bytes_remaining = bytes;
int max_transfer;
if (bdrv_has_readonly_bitmaps(bs)) {
return -EPERM;
}
assert(is_power_of_2(align));
assert((offset & (align - 1)) == 0);
assert((bytes & (align - 1)) == 0);
@ -2287,6 +2291,10 @@ int coroutine_fn bdrv_co_pdiscard(BlockDriverState *bs, int64_t offset,
return -ENOMEDIUM;
}
if (bdrv_has_readonly_bitmaps(bs)) {
return -EPERM;
}
ret = bdrv_check_byte_request(bs, offset, bytes);
if (ret < 0) {
return ret;

View File

@ -2079,11 +2079,18 @@ static void iscsi_reopen_commit(BDRVReopenState *reopen_state)
}
}
static int iscsi_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
static int iscsi_truncate(BlockDriverState *bs, int64_t offset,
PreallocMode prealloc, Error **errp)
{
IscsiLun *iscsilun = bs->opaque;
Error *local_err = NULL;
if (prealloc != PREALLOC_MODE_OFF) {
error_setg(errp, "Unsupported preallocation mode '%s'",
PreallocMode_lookup[prealloc]);
return -ENOTSUP;
}
if (iscsilun->type != TYPE_DISK) {
error_setg(errp, "Cannot resize non-disk iSCSI devices");
return -ENOTSUP;

View File

@ -739,7 +739,8 @@ static void coroutine_fn mirror_run(void *opaque)
}
if (s->bdev_length > base_length) {
ret = blk_truncate(s->target, s->bdev_length, NULL);
ret = blk_truncate(s->target, s->bdev_length, PREALLOC_MODE_OFF,
NULL);
if (ret < 0) {
goto immediate_exit;
}

View File

@ -759,11 +759,18 @@ static int64_t nfs_get_allocated_file_size(BlockDriverState *bs)
return (task.ret < 0 ? task.ret : st.st_blocks * 512);
}
static int nfs_file_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
static int nfs_file_truncate(BlockDriverState *bs, int64_t offset,
PreallocMode prealloc, Error **errp)
{
NFSClient *client = bs->opaque;
int ret;
if (prealloc != PREALLOC_MODE_OFF) {
error_setg(errp, "Unsupported preallocation mode '%s'",
PreallocMode_lookup[prealloc]);
return -ENOTSUP;
}
ret = nfs_ftruncate(client->context, client->fh, offset);
if (ret < 0) {
error_setg_errno(errp, -ret, "Failed to truncate file");

View File

@ -224,7 +224,7 @@ static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num,
} else {
ret = bdrv_truncate(bs->file,
(s->data_end + space) << BDRV_SECTOR_BITS,
NULL);
PREALLOC_MODE_OFF, NULL);
}
if (ret < 0) {
return ret;
@ -458,7 +458,8 @@ static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res,
res->leaks += count;
if (fix & BDRV_FIX_LEAKS) {
Error *local_err = NULL;
ret = bdrv_truncate(bs->file, res->image_end_offset, &local_err);
ret = bdrv_truncate(bs->file, res->image_end_offset,
PREALLOC_MODE_OFF, &local_err);
if (ret < 0) {
error_report_err(local_err);
res->check_errors++;
@ -507,7 +508,7 @@ static int parallels_create(const char *filename, QemuOpts *opts, Error **errp)
blk_set_allow_write_beyond_eof(file, true);
ret = blk_truncate(file, 0, errp);
ret = blk_truncate(file, 0, PREALLOC_MODE_OFF, errp);
if (ret < 0) {
goto exit;
}
@ -699,7 +700,8 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
}
if (!(flags & BDRV_O_RESIZE) || !bdrv_has_zero_init(bs->file->bs) ||
bdrv_truncate(bs->file, bdrv_getlength(bs->file->bs), NULL) != 0) {
bdrv_truncate(bs->file, bdrv_getlength(bs->file->bs),
PREALLOC_MODE_OFF, NULL) != 0) {
s->prealloc_mode = PRL_PREALLOC_MODE_FALLOCATE;
}
@ -742,7 +744,8 @@ static void parallels_close(BlockDriverState *bs)
}
if (bs->open_flags & BDRV_O_RDWR) {
bdrv_truncate(bs->file, s->data_end << BDRV_SECTOR_BITS, NULL);
bdrv_truncate(bs->file, s->data_end << BDRV_SECTOR_BITS,
PREALLOC_MODE_OFF, NULL);
}
g_free(s->bat_dirty_bmap);

View File

@ -45,7 +45,7 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
info->ro = bs->read_only;
info->drv = g_strdup(bs->drv->format_name);
info->encrypted = bs->encrypted;
info->encryption_key_missing = bdrv_key_required(bs);
info->encryption_key_missing = false;
info->cache = g_new(BlockdevCacheInfo, 1);
*info->cache = (BlockdevCacheInfo) {

View File

@ -31,8 +31,10 @@
#include "qemu/bswap.h"
#include <zlib.h>
#include "qapi/qmp/qerror.h"
#include "crypto/cipher.h"
#include "qapi/qmp/qstring.h"
#include "crypto/block.h"
#include "migration/blocker.h"
#include "block/crypto.h"
/**************************************************************/
/* QEMU COW block driver with compression and encryption support */
@ -77,7 +79,7 @@ typedef struct BDRVQcowState {
uint8_t *cluster_cache;
uint8_t *cluster_data;
uint64_t cluster_cache_offset;
QCryptoCipher *cipher; /* NULL if no key yet */
QCryptoBlock *crypto; /* Disk encryption format driver */
uint32_t crypt_method_header;
CoMutex lock;
Error *migration_blocker;
@ -97,6 +99,15 @@ static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
return 0;
}
static QemuOptsList qcow_runtime_opts = {
.name = "qcow",
.head = QTAILQ_HEAD_INITIALIZER(qcow_runtime_opts.head),
.desc = {
BLOCK_CRYPTO_OPT_DEF_QCOW_KEY_SECRET("encrypt."),
{ /* end of list */ }
},
};
static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
Error **errp)
{
@ -105,11 +116,19 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
int ret;
QCowHeader header;
Error *local_err = NULL;
QCryptoBlockOpenOptions *crypto_opts = NULL;
unsigned int cflags = 0;
QDict *encryptopts = NULL;
const char *encryptfmt;
qdict_extract_subqdict(options, &encryptopts, "encrypt.");
encryptfmt = qdict_get_try_str(encryptopts, "format");
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
false, errp);
if (!bs->file) {
return -EINVAL;
ret = -EINVAL;
goto fail;
}
ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
@ -155,17 +174,6 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
goto fail;
}
if (header.crypt_method > QCOW_CRYPT_AES) {
error_setg(errp, "invalid encryption method in qcow header");
ret = -EINVAL;
goto fail;
}
if (!qcrypto_cipher_supports(QCRYPTO_CIPHER_ALG_AES_128,
QCRYPTO_CIPHER_MODE_CBC)) {
error_setg(errp, "AES cipher not available");
ret = -EINVAL;
goto fail;
}
s->crypt_method_header = header.crypt_method;
if (s->crypt_method_header) {
if (bdrv_uses_whitelist() &&
@ -181,8 +189,44 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
ret = -ENOSYS;
goto fail;
}
if (s->crypt_method_header == QCOW_CRYPT_AES) {
if (encryptfmt && !g_str_equal(encryptfmt, "aes")) {
error_setg(errp,
"Header reported 'aes' encryption format but "
"options specify '%s'", encryptfmt);
ret = -EINVAL;
goto fail;
}
qdict_del(encryptopts, "format");
crypto_opts = block_crypto_open_opts_init(
Q_CRYPTO_BLOCK_FORMAT_QCOW, encryptopts, errp);
if (!crypto_opts) {
ret = -EINVAL;
goto fail;
}
if (flags & BDRV_O_NO_IO) {
cflags |= QCRYPTO_BLOCK_OPEN_NO_IO;
}
s->crypto = qcrypto_block_open(crypto_opts, "encrypt.",
NULL, NULL, cflags, errp);
if (!s->crypto) {
ret = -EINVAL;
goto fail;
}
} else {
error_setg(errp, "invalid encryption method in qcow header");
ret = -EINVAL;
goto fail;
}
bs->encrypted = true;
} else {
if (encryptfmt) {
error_setg(errp, "No encryption in image header, but options "
"specified format '%s'", encryptfmt);
ret = -EINVAL;
goto fail;
}
}
s->cluster_bits = header.cluster_bits;
s->cluster_size = 1 << s->cluster_bits;
@ -266,6 +310,8 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
goto fail;
}
QDECREF(encryptopts);
qapi_free_QCryptoBlockOpenOptions(crypto_opts);
qemu_co_mutex_init(&s->lock);
return 0;
@ -274,6 +320,9 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
qemu_vfree(s->l2_cache);
g_free(s->cluster_cache);
g_free(s->cluster_data);
qcrypto_block_free(s->crypto);
QDECREF(encryptopts);
qapi_free_QCryptoBlockOpenOptions(crypto_opts);
return ret;
}
@ -286,85 +335,6 @@ static int qcow_reopen_prepare(BDRVReopenState *state,
return 0;
}
static int qcow_set_key(BlockDriverState *bs, const char *key)
{
BDRVQcowState *s = bs->opaque;
uint8_t keybuf[16];
int len, i;
Error *err;
memset(keybuf, 0, 16);
len = strlen(key);
if (len > 16)
len = 16;
/* XXX: we could compress the chars to 7 bits to increase
entropy */
for(i = 0;i < len;i++) {
keybuf[i] = key[i];
}
assert(bs->encrypted);
qcrypto_cipher_free(s->cipher);
s->cipher = qcrypto_cipher_new(
QCRYPTO_CIPHER_ALG_AES_128,
QCRYPTO_CIPHER_MODE_CBC,
keybuf, G_N_ELEMENTS(keybuf),
&err);
if (!s->cipher) {
/* XXX would be nice if errors in this method could
* be properly propagate to the caller. Would need
* the bdrv_set_key() API signature to be fixed. */
error_free(err);
return -1;
}
return 0;
}
/* The crypt function is compatible with the linux cryptoloop
algorithm for < 4 GB images. NOTE: out_buf == in_buf is
supported */
static int encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
uint8_t *out_buf, const uint8_t *in_buf,
int nb_sectors, bool enc, Error **errp)
{
union {
uint64_t ll[2];
uint8_t b[16];
} ivec;
int i;
int ret;
for(i = 0; i < nb_sectors; i++) {
ivec.ll[0] = cpu_to_le64(sector_num);
ivec.ll[1] = 0;
if (qcrypto_cipher_setiv(s->cipher,
ivec.b, G_N_ELEMENTS(ivec.b),
errp) < 0) {
return -1;
}
if (enc) {
ret = qcrypto_cipher_encrypt(s->cipher,
in_buf,
out_buf,
512,
errp);
} else {
ret = qcrypto_cipher_decrypt(s->cipher,
in_buf,
out_buf,
512,
errp);
}
if (ret < 0) {
return -1;
}
sector_num++;
in_buf += 512;
out_buf += 512;
}
return 0;
}
/* 'allocate' is:
*
@ -473,22 +443,23 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
/* round to cluster size */
cluster_offset = (cluster_offset + s->cluster_size - 1) &
~(s->cluster_size - 1);
bdrv_truncate(bs->file, cluster_offset + s->cluster_size, NULL);
bdrv_truncate(bs->file, cluster_offset + s->cluster_size,
PREALLOC_MODE_OFF, NULL);
/* if encrypted, we must initialize the cluster
content which won't be written */
if (bs->encrypted &&
(n_end - n_start) < s->cluster_sectors) {
uint64_t start_sect;
assert(s->cipher);
assert(s->crypto);
start_sect = (offset & ~(s->cluster_size - 1)) >> 9;
memset(s->cluster_data + 512, 0x00, 512);
for(i = 0; i < s->cluster_sectors; i++) {
if (i < n_start || i >= n_end) {
Error *err = NULL;
if (encrypt_sectors(s, start_sect + i,
s->cluster_data,
s->cluster_data + 512, 1,
true, &err) < 0) {
memset(s->cluster_data, 0x00, 512);
if (qcrypto_block_encrypt(s->crypto, start_sect + i,
s->cluster_data,
BDRV_SECTOR_SIZE,
&err) < 0) {
error_free(err);
errno = EIO;
return -1;
@ -533,7 +504,7 @@ static int64_t coroutine_fn qcow_co_get_block_status(BlockDriverState *bs,
if (!cluster_offset) {
return 0;
}
if ((cluster_offset & QCOW_OFLAG_COMPRESSED) || s->cipher) {
if ((cluster_offset & QCOW_OFLAG_COMPRESSED) || s->crypto) {
return BDRV_BLOCK_DATA;
}
cluster_offset |= (index_in_cluster << BDRV_SECTOR_BITS);
@ -664,9 +635,9 @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
break;
}
if (bs->encrypted) {
assert(s->cipher);
if (encrypt_sectors(s, sector_num, buf, buf,
n, false, &err) < 0) {
assert(s->crypto);
if (qcrypto_block_decrypt(s->crypto, sector_num, buf,
n * BDRV_SECTOR_SIZE, &err) < 0) {
goto fail;
}
}
@ -700,9 +671,7 @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
BDRVQcowState *s = bs->opaque;
int index_in_cluster;
uint64_t cluster_offset;
const uint8_t *src_buf;
int ret = 0, n;
uint8_t *cluster_data = NULL;
struct iovec hd_iov;
QEMUIOVector hd_qiov;
uint8_t *buf;
@ -710,7 +679,9 @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
s->cluster_cache_offset = -1; /* disable compressed cache */
if (qiov->niov > 1) {
/* We must always copy the iov when encrypting, so we
* don't modify the original data buffer during encryption */
if (bs->encrypted || qiov->niov > 1) {
buf = orig_buf = qemu_try_blockalign(bs, qiov->size);
if (buf == NULL) {
return -ENOMEM;
@ -739,22 +710,16 @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
}
if (bs->encrypted) {
Error *err = NULL;
assert(s->cipher);
if (!cluster_data) {
cluster_data = g_malloc0(s->cluster_size);
}
if (encrypt_sectors(s, sector_num, cluster_data, buf,
n, true, &err) < 0) {
assert(s->crypto);
if (qcrypto_block_encrypt(s->crypto, sector_num, buf,
n * BDRV_SECTOR_SIZE, &err) < 0) {
error_free(err);
ret = -EIO;
break;
}
src_buf = cluster_data;
} else {
src_buf = buf;
}
hd_iov.iov_base = (void *)src_buf;
hd_iov.iov_base = (void *)buf;
hd_iov.iov_len = n * 512;
qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
qemu_co_mutex_unlock(&s->lock);
@ -773,10 +738,7 @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
}
qemu_co_mutex_unlock(&s->lock);
if (qiov->niov > 1) {
qemu_vfree(orig_buf);
}
g_free(cluster_data);
qemu_vfree(orig_buf);
return ret;
}
@ -785,8 +747,8 @@ static void qcow_close(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
qcrypto_cipher_free(s->cipher);
s->cipher = NULL;
qcrypto_block_free(s->crypto);
s->crypto = NULL;
g_free(s->l1_table);
qemu_vfree(s->l2_cache);
g_free(s->cluster_cache);
@ -803,17 +765,35 @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp)
uint8_t *tmp;
int64_t total_size = 0;
char *backing_file = NULL;
int flags = 0;
Error *local_err = NULL;
int ret;
BlockBackend *qcow_blk;
const char *encryptfmt = NULL;
QDict *options;
QDict *encryptopts = NULL;
QCryptoBlockCreateOptions *crypto_opts = NULL;
QCryptoBlock *crypto = NULL;
/* Read out options */
total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
BDRV_SECTOR_SIZE);
if (total_size == 0) {
error_setg(errp, "Image size is too small, cannot be zero length");
ret = -EINVAL;
goto cleanup;
}
backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ENCRYPT, false)) {
flags |= BLOCK_FLAG_ENCRYPT;
encryptfmt = qemu_opt_get_del(opts, BLOCK_OPT_ENCRYPT_FORMAT);
if (encryptfmt) {
if (qemu_opt_get(opts, BLOCK_OPT_ENCRYPT)) {
error_setg(errp, "Options " BLOCK_OPT_ENCRYPT " and "
BLOCK_OPT_ENCRYPT_FORMAT " are mutually exclusive");
ret = -EINVAL;
goto cleanup;
}
} else if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ENCRYPT, false)) {
encryptfmt = "aes";
}
ret = bdrv_create_file(filename, opts, &local_err);
@ -833,7 +813,7 @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp)
blk_set_allow_write_beyond_eof(qcow_blk, true);
ret = blk_truncate(qcow_blk, 0, errp);
ret = blk_truncate(qcow_blk, 0, PREALLOC_MODE_OFF, errp);
if (ret < 0) {
goto exit;
}
@ -867,8 +847,32 @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp)
l1_size = (total_size + (1LL << shift) - 1) >> shift;
header.l1_table_offset = cpu_to_be64(header_size);
if (flags & BLOCK_FLAG_ENCRYPT) {
options = qemu_opts_to_qdict(opts, NULL);
qdict_extract_subqdict(options, &encryptopts, "encrypt.");
QDECREF(options);
if (encryptfmt) {
if (!g_str_equal(encryptfmt, "aes")) {
error_setg(errp, "Unknown encryption format '%s', expected 'aes'",
encryptfmt);
ret = -EINVAL;
goto exit;
}
header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES);
crypto_opts = block_crypto_create_opts_init(
Q_CRYPTO_BLOCK_FORMAT_QCOW, encryptopts, errp);
if (!crypto_opts) {
ret = -EINVAL;
goto exit;
}
crypto = qcrypto_block_create(crypto_opts, "encrypt.",
NULL, NULL, NULL, errp);
if (!crypto) {
ret = -EINVAL;
goto exit;
}
} else {
header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE);
}
@ -903,6 +907,9 @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp)
exit:
blk_unref(qcow_blk);
cleanup:
QDECREF(encryptopts);
qcrypto_block_free(crypto);
qapi_free_QCryptoBlockCreateOptions(crypto_opts);
g_free(backing_file);
return ret;
}
@ -917,7 +924,8 @@ static int qcow_make_empty(BlockDriverState *bs)
if (bdrv_pwrite_sync(bs->file, s->l1_table_offset, s->l1_table,
l1_length) < 0)
return -1;
ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length, NULL);
ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length,
PREALLOC_MODE_OFF, NULL);
if (ret < 0)
return ret;
@ -1041,9 +1049,15 @@ static QemuOptsList qcow_create_opts = {
{
.name = BLOCK_OPT_ENCRYPT,
.type = QEMU_OPT_BOOL,
.help = "Encrypt the image",
.def_value_str = "off"
.help = "Encrypt the image with format 'aes'. (Deprecated "
"in favor of " BLOCK_OPT_ENCRYPT_FORMAT "=aes)",
},
{
.name = BLOCK_OPT_ENCRYPT_FORMAT,
.type = QEMU_OPT_STRING,
.help = "Encrypt the image, format choices: 'aes'",
},
BLOCK_CRYPTO_OPT_DEF_QCOW_KEY_SECRET("encrypt."),
{ /* end of list */ }
}
};
@ -1064,7 +1078,6 @@ static BlockDriver bdrv_qcow = {
.bdrv_co_writev = qcow_co_writev,
.bdrv_co_get_block_status = qcow_co_get_block_status,
.bdrv_set_key = qcow_set_key,
.bdrv_make_empty = qcow_make_empty,
.bdrv_co_pwritev_compressed = qcow_co_pwritev_compressed,
.bdrv_get_info = qcow_get_info,

1482
block/qcow2-bitmap.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -357,52 +357,6 @@ static int count_contiguous_clusters_unallocated(int nb_clusters,
return i;
}
/* The crypt function is compatible with the linux cryptoloop
algorithm for < 4 GB images. NOTE: out_buf == in_buf is
supported */
int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num,
uint8_t *out_buf, const uint8_t *in_buf,
int nb_sectors, bool enc,
Error **errp)
{
union {
uint64_t ll[2];
uint8_t b[16];
} ivec;
int i;
int ret;
for(i = 0; i < nb_sectors; i++) {
ivec.ll[0] = cpu_to_le64(sector_num);
ivec.ll[1] = 0;
if (qcrypto_cipher_setiv(s->cipher,
ivec.b, G_N_ELEMENTS(ivec.b),
errp) < 0) {
return -1;
}
if (enc) {
ret = qcrypto_cipher_encrypt(s->cipher,
in_buf,
out_buf,
512,
errp);
} else {
ret = qcrypto_cipher_decrypt(s->cipher,
in_buf,
out_buf,
512,
errp);
}
if (ret < 0) {
return -1;
}
sector_num++;
in_buf += 512;
out_buf += 512;
}
return 0;
}
static int coroutine_fn do_perform_cow_read(BlockDriverState *bs,
uint64_t src_cluster_offset,
unsigned offset_in_cluster,
@ -435,19 +389,22 @@ static int coroutine_fn do_perform_cow_read(BlockDriverState *bs,
static bool coroutine_fn do_perform_cow_encrypt(BlockDriverState *bs,
uint64_t src_cluster_offset,
uint64_t cluster_offset,
unsigned offset_in_cluster,
uint8_t *buffer,
unsigned bytes)
{
if (bytes && bs->encrypted) {
BDRVQcow2State *s = bs->opaque;
int64_t sector = (src_cluster_offset + offset_in_cluster)
int64_t sector = (s->crypt_physical_offset ?
(cluster_offset + offset_in_cluster) :
(src_cluster_offset + offset_in_cluster))
>> BDRV_SECTOR_BITS;
assert(s->cipher);
assert((offset_in_cluster & ~BDRV_SECTOR_MASK) == 0);
assert((bytes & ~BDRV_SECTOR_MASK) == 0);
if (qcow2_encrypt_sectors(s, sector, buffer, buffer,
bytes >> BDRV_SECTOR_BITS, true, NULL) < 0) {
assert(s->crypto);
if (qcrypto_block_encrypt(s->crypto, sector, buffer,
bytes, NULL) < 0) {
return false;
}
}
@ -834,10 +791,11 @@ static int perform_cow(BlockDriverState *bs, QCowL2Meta *m)
/* Encrypt the data if necessary before writing it */
if (bs->encrypted) {
if (!do_perform_cow_encrypt(bs, m->offset, start->offset,
start_buffer, start->nb_bytes) ||
!do_perform_cow_encrypt(bs, m->offset, end->offset,
end_buffer, end->nb_bytes)) {
if (!do_perform_cow_encrypt(bs, m->offset, m->alloc_offset,
start->offset, start_buffer,
start->nb_bytes) ||
!do_perform_cow_encrypt(bs, m->offset, m->alloc_offset,
end->offset, end_buffer, end->nb_bytes)) {
ret = -EIO;
goto fail;
}

View File

@ -281,25 +281,6 @@ int qcow2_get_refcount(BlockDriverState *bs, int64_t cluster_index,
return 0;
}
/*
* Rounds the refcount table size up to avoid growing the table for each single
* refcount block that is allocated.
*/
static unsigned int next_refcount_table_size(BDRVQcow2State *s,
unsigned int min_size)
{
unsigned int min_clusters = (min_size >> (s->cluster_bits - 3)) + 1;
unsigned int refcount_table_clusters =
MAX(1, s->refcount_table_size >> (s->cluster_bits - 3));
while (min_clusters > refcount_table_clusters) {
refcount_table_clusters = (refcount_table_clusters * 3 + 1) / 2;
}
return refcount_table_clusters << (s->cluster_bits - 3);
}
/* Checks if two offsets are described by the same refcount block */
static int in_same_refcount_block(BDRVQcow2State *s, uint64_t offset_a,
uint64_t offset_b)
@ -321,7 +302,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
{
BDRVQcow2State *s = bs->opaque;
unsigned int refcount_table_index;
int ret;
int64_t ret;
BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC);
@ -396,7 +377,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
ret = qcow2_cache_get_empty(bs, s->refcount_block_cache, new_block,
refcount_block);
if (ret < 0) {
goto fail_block;
goto fail;
}
memset(*refcount_block, 0, s->cluster_size);
@ -411,12 +392,12 @@ static int alloc_refcount_block(BlockDriverState *bs,
ret = update_refcount(bs, new_block, s->cluster_size, 1, false,
QCOW2_DISCARD_NEVER);
if (ret < 0) {
goto fail_block;
goto fail;
}
ret = qcow2_cache_flush(bs, s->refcount_block_cache);
if (ret < 0) {
goto fail_block;
goto fail;
}
/* Initialize the new refcount block only after updating its refcount,
@ -424,7 +405,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
ret = qcow2_cache_get_empty(bs, s->refcount_block_cache, new_block,
refcount_block);
if (ret < 0) {
goto fail_block;
goto fail;
}
memset(*refcount_block, 0, s->cluster_size);
@ -435,7 +416,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
qcow2_cache_entry_mark_dirty(bs, s->refcount_block_cache, *refcount_block);
ret = qcow2_cache_flush(bs, s->refcount_block_cache);
if (ret < 0) {
goto fail_block;
goto fail;
}
/* If the refcount table is big enough, just hook the block up there */
@ -446,7 +427,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
s->refcount_table_offset + refcount_table_index * sizeof(uint64_t),
&data64, sizeof(data64));
if (ret < 0) {
goto fail_block;
goto fail;
}
s->refcount_table[refcount_table_index] = new_block;
@ -490,74 +471,201 @@ static int alloc_refcount_block(BlockDriverState *bs,
(new_block >> s->cluster_bits) + 1),
s->refcount_block_size);
if (blocks_used > QCOW_MAX_REFTABLE_SIZE / sizeof(uint64_t)) {
return -EFBIG;
}
/* And now we need at least one block more for the new metadata */
uint64_t table_size = next_refcount_table_size(s, blocks_used + 1);
uint64_t last_table_size;
uint64_t blocks_clusters;
do {
uint64_t table_clusters =
size_to_clusters(s, table_size * sizeof(uint64_t));
blocks_clusters = 1 +
DIV_ROUND_UP(table_clusters, s->refcount_block_size);
uint64_t meta_clusters = table_clusters + blocks_clusters;
last_table_size = table_size;
table_size = next_refcount_table_size(s, blocks_used +
DIV_ROUND_UP(meta_clusters, s->refcount_block_size));
} while (last_table_size != table_size);
#ifdef DEBUG_ALLOC2
fprintf(stderr, "qcow2: Grow refcount table %" PRId32 " => %" PRId64 "\n",
s->refcount_table_size, table_size);
#endif
/* Create the new refcount table and blocks */
uint64_t meta_offset = (blocks_used * s->refcount_block_size) *
s->cluster_size;
uint64_t table_offset = meta_offset + blocks_clusters * s->cluster_size;
uint64_t *new_table = g_try_new0(uint64_t, table_size);
void *new_blocks = g_try_malloc0(blocks_clusters * s->cluster_size);
assert(table_size > 0 && blocks_clusters > 0);
if (new_table == NULL || new_blocks == NULL) {
ret = qcow2_refcount_area(bs, meta_offset, 0, false,
refcount_table_index, new_block);
if (ret < 0) {
return ret;
}
ret = load_refcount_block(bs, new_block, refcount_block);
if (ret < 0) {
return ret;
}
/* If we were trying to do the initial refcount update for some cluster
* allocation, we might have used the same clusters to store newly
* allocated metadata. Make the caller search some new space. */
return -EAGAIN;
fail:
if (*refcount_block != NULL) {
qcow2_cache_put(bs, s->refcount_block_cache, refcount_block);
}
return ret;
}
/*
* Starting at @start_offset, this function creates new self-covering refcount
* structures: A new refcount table and refcount blocks which cover all of
* themselves, and a number of @additional_clusters beyond their end.
* @start_offset must be at the end of the image file, that is, there must be
* only empty space beyond it.
* If @exact_size is false, the refcount table will have 50 % more entries than
* necessary so it will not need to grow again soon.
* If @new_refblock_offset is not zero, it contains the offset of a refcount
* block that should be entered into the new refcount table at index
* @new_refblock_index.
*
* Returns: The offset after the new refcount structures (i.e. where the
* @additional_clusters may be placed) on success, -errno on error.
*/
int64_t qcow2_refcount_area(BlockDriverState *bs, uint64_t start_offset,
uint64_t additional_clusters, bool exact_size,
int new_refblock_index,
uint64_t new_refblock_offset)
{
BDRVQcow2State *s = bs->opaque;
uint64_t total_refblock_count_u64, additional_refblock_count;
int total_refblock_count, table_size, area_reftable_index, table_clusters;
int i;
uint64_t table_offset, block_offset, end_offset;
int ret;
uint64_t *new_table;
assert(!(start_offset % s->cluster_size));
qcow2_refcount_metadata_size(start_offset / s->cluster_size +
additional_clusters,
s->cluster_size, s->refcount_order,
!exact_size, &total_refblock_count_u64);
if (total_refblock_count_u64 > QCOW_MAX_REFTABLE_SIZE) {
return -EFBIG;
}
total_refblock_count = total_refblock_count_u64;
/* Index in the refcount table of the first refcount block to cover the area
* of refcount structures we are about to create; we know that
* @total_refblock_count can cover @start_offset, so this will definitely
* fit into an int. */
area_reftable_index = (start_offset / s->cluster_size) /
s->refcount_block_size;
if (exact_size) {
table_size = total_refblock_count;
} else {
table_size = total_refblock_count +
DIV_ROUND_UP(total_refblock_count, 2);
}
/* The qcow2 file can only store the reftable size in number of clusters */
table_size = ROUND_UP(table_size, s->cluster_size / sizeof(uint64_t));
table_clusters = (table_size * sizeof(uint64_t)) / s->cluster_size;
if (table_size > QCOW_MAX_REFTABLE_SIZE) {
return -EFBIG;
}
new_table = g_try_new0(uint64_t, table_size);
assert(table_size > 0);
if (new_table == NULL) {
ret = -ENOMEM;
goto fail_table;
goto fail;
}
/* Fill the new refcount table */
memcpy(new_table, s->refcount_table,
s->refcount_table_size * sizeof(uint64_t));
new_table[refcount_table_index] = new_block;
int i;
for (i = 0; i < blocks_clusters; i++) {
new_table[blocks_used + i] = meta_offset + (i * s->cluster_size);
if (table_size > s->max_refcount_table_index) {
/* We're actually growing the reftable */
memcpy(new_table, s->refcount_table,
(s->max_refcount_table_index + 1) * sizeof(uint64_t));
} else {
/* Improbable case: We're shrinking the reftable. However, the caller
* has assured us that there is only empty space beyond @start_offset,
* so we can simply drop all of the refblocks that won't fit into the
* new reftable. */
memcpy(new_table, s->refcount_table, table_size * sizeof(uint64_t));
}
/* Fill the refcount blocks */
uint64_t table_clusters = size_to_clusters(s, table_size * sizeof(uint64_t));
int block = 0;
for (i = 0; i < table_clusters + blocks_clusters; i++) {
s->set_refcount(new_blocks, block++, 1);
if (new_refblock_offset) {
assert(new_refblock_index < total_refblock_count);
new_table[new_refblock_index] = new_refblock_offset;
}
/* Count how many new refblocks we have to create */
additional_refblock_count = 0;
for (i = area_reftable_index; i < total_refblock_count; i++) {
if (!new_table[i]) {
additional_refblock_count++;
}
}
table_offset = start_offset + additional_refblock_count * s->cluster_size;
end_offset = table_offset + table_clusters * s->cluster_size;
/* Fill the refcount blocks, and create new ones, if necessary */
block_offset = start_offset;
for (i = area_reftable_index; i < total_refblock_count; i++) {
void *refblock_data;
uint64_t first_offset_covered;
/* Reuse an existing refblock if possible, create a new one otherwise */
if (new_table[i]) {
ret = qcow2_cache_get(bs, s->refcount_block_cache, new_table[i],
&refblock_data);
if (ret < 0) {
goto fail;
}
} else {
ret = qcow2_cache_get_empty(bs, s->refcount_block_cache,
block_offset, &refblock_data);
if (ret < 0) {
goto fail;
}
memset(refblock_data, 0, s->cluster_size);
qcow2_cache_entry_mark_dirty(bs, s->refcount_block_cache,
refblock_data);
new_table[i] = block_offset;
block_offset += s->cluster_size;
}
/* First host offset covered by this refblock */
first_offset_covered = (uint64_t)i * s->refcount_block_size *
s->cluster_size;
if (first_offset_covered < end_offset) {
int j, end_index;
/* Set the refcount of all of the new refcount structures to 1 */
if (first_offset_covered < start_offset) {
assert(i == area_reftable_index);
j = (start_offset - first_offset_covered) / s->cluster_size;
assert(j < s->refcount_block_size);
} else {
j = 0;
}
end_index = MIN((end_offset - first_offset_covered) /
s->cluster_size,
s->refcount_block_size);
for (; j < end_index; j++) {
/* The caller guaranteed us this space would be empty */
assert(s->get_refcount(refblock_data, j) == 0);
s->set_refcount(refblock_data, j, 1);
}
qcow2_cache_entry_mark_dirty(bs, s->refcount_block_cache,
refblock_data);
}
qcow2_cache_put(bs, s->refcount_block_cache, &refblock_data);
}
assert(block_offset == table_offset);
/* Write refcount blocks to disk */
BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS);
ret = bdrv_pwrite_sync(bs->file, meta_offset, new_blocks,
blocks_clusters * s->cluster_size);
g_free(new_blocks);
new_blocks = NULL;
ret = qcow2_cache_flush(bs, s->refcount_block_cache);
if (ret < 0) {
goto fail_table;
goto fail;
}
/* Write refcount table to disk */
for(i = 0; i < table_size; i++) {
for (i = 0; i < total_refblock_count; i++) {
cpu_to_be64s(&new_table[i]);
}
@ -565,10 +673,10 @@ static int alloc_refcount_block(BlockDriverState *bs,
ret = bdrv_pwrite_sync(bs->file, table_offset, new_table,
table_size * sizeof(uint64_t));
if (ret < 0) {
goto fail_table;
goto fail;
}
for(i = 0; i < table_size; i++) {
for (i = 0; i < total_refblock_count; i++) {
be64_to_cpus(&new_table[i]);
}
@ -584,7 +692,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
offsetof(QCowHeader, refcount_table_offset),
&data, sizeof(data));
if (ret < 0) {
goto fail_table;
goto fail;
}
/* And switch it in memory */
@ -601,23 +709,10 @@ static int alloc_refcount_block(BlockDriverState *bs,
qcow2_free_clusters(bs, old_table_offset, old_table_size * sizeof(uint64_t),
QCOW2_DISCARD_OTHER);
ret = load_refcount_block(bs, new_block, refcount_block);
if (ret < 0) {
return ret;
}
return end_offset;
/* If we were trying to do the initial refcount update for some cluster
* allocation, we might have used the same clusters to store newly
* allocated metadata. Make the caller search some new space. */
return -EAGAIN;
fail_table:
g_free(new_blocks);
fail:
g_free(new_table);
fail_block:
if (*refcount_block != NULL) {
qcow2_cache_put(bs, s->refcount_block_cache, refcount_block);
}
return ret;
}
@ -1323,11 +1418,10 @@ static int realloc_refcount_array(BDRVQcow2State *s, void **array,
*
* Modifies the number of errors in res.
*/
static int inc_refcounts(BlockDriverState *bs,
BdrvCheckResult *res,
void **refcount_table,
int64_t *refcount_table_size,
int64_t offset, int64_t size)
int qcow2_inc_refcounts_imrt(BlockDriverState *bs, BdrvCheckResult *res,
void **refcount_table,
int64_t *refcount_table_size,
int64_t offset, int64_t size)
{
BDRVQcow2State *s = bs->opaque;
uint64_t start, last, cluster_offset, k, refcount;
@ -1420,8 +1514,9 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
nb_csectors = ((l2_entry >> s->csize_shift) &
s->csize_mask) + 1;
l2_entry &= s->cluster_offset_mask;
ret = inc_refcounts(bs, res, refcount_table, refcount_table_size,
l2_entry & ~511, nb_csectors * 512);
ret = qcow2_inc_refcounts_imrt(bs, res,
refcount_table, refcount_table_size,
l2_entry & ~511, nb_csectors * 512);
if (ret < 0) {
goto fail;
}
@ -1454,8 +1549,9 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
}
/* Mark cluster as used */
ret = inc_refcounts(bs, res, refcount_table, refcount_table_size,
offset, s->cluster_size);
ret = qcow2_inc_refcounts_imrt(bs, res,
refcount_table, refcount_table_size,
offset, s->cluster_size);
if (ret < 0) {
goto fail;
}
@ -1508,8 +1604,8 @@ static int check_refcounts_l1(BlockDriverState *bs,
l1_size2 = l1_size * sizeof(uint64_t);
/* Mark L1 table as used */
ret = inc_refcounts(bs, res, refcount_table, refcount_table_size,
l1_table_offset, l1_size2);
ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table, refcount_table_size,
l1_table_offset, l1_size2);
if (ret < 0) {
goto fail;
}
@ -1538,8 +1634,9 @@ static int check_refcounts_l1(BlockDriverState *bs,
if (l2_offset) {
/* Mark L2 table as used */
l2_offset &= L1E_OFFSET_MASK;
ret = inc_refcounts(bs, res, refcount_table, refcount_table_size,
l2_offset, s->cluster_size);
ret = qcow2_inc_refcounts_imrt(bs, res,
refcount_table, refcount_table_size,
l2_offset, s->cluster_size);
if (ret < 0) {
goto fail;
}
@ -1730,7 +1827,7 @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
}
ret = bdrv_truncate(bs->file, offset + s->cluster_size,
&local_err);
PREALLOC_MODE_OFF, &local_err);
if (ret < 0) {
error_report_err(local_err);
goto resize_fail;
@ -1757,14 +1854,15 @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
}
res->corruptions_fixed++;
ret = inc_refcounts(bs, res, refcount_table, nb_clusters,
offset, s->cluster_size);
ret = qcow2_inc_refcounts_imrt(bs, res,
refcount_table, nb_clusters,
offset, s->cluster_size);
if (ret < 0) {
return ret;
}
/* No need to check whether the refcount is now greater than 1:
* This area was just allocated and zeroed, so it can only be
* exactly 1 after inc_refcounts() */
* exactly 1 after qcow2_inc_refcounts_imrt() */
continue;
resize_fail:
@ -1779,8 +1877,8 @@ resize_fail:
}
if (offset != 0) {
ret = inc_refcounts(bs, res, refcount_table, nb_clusters,
offset, s->cluster_size);
ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table, nb_clusters,
offset, s->cluster_size);
if (ret < 0) {
return ret;
}
@ -1820,8 +1918,8 @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
}
/* header */
ret = inc_refcounts(bs, res, refcount_table, nb_clusters,
0, s->cluster_size);
ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table, nb_clusters,
0, s->cluster_size);
if (ret < 0) {
return ret;
}
@ -1842,16 +1940,32 @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
return ret;
}
}
ret = inc_refcounts(bs, res, refcount_table, nb_clusters,
s->snapshots_offset, s->snapshots_size);
ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table, nb_clusters,
s->snapshots_offset, s->snapshots_size);
if (ret < 0) {
return ret;
}
/* refcount data */
ret = inc_refcounts(bs, res, refcount_table, nb_clusters,
s->refcount_table_offset,
s->refcount_table_size * sizeof(uint64_t));
ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table, nb_clusters,
s->refcount_table_offset,
s->refcount_table_size * sizeof(uint64_t));
if (ret < 0) {
return ret;
}
/* encryption */
if (s->crypto_header.length) {
ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table, nb_clusters,
s->crypto_header.offset,
s->crypto_header.length);
if (ret < 0) {
return ret;
}
}
/* bitmaps */
ret = qcow2_check_bitmaps_refcounts(bs, res, refcount_table, nb_clusters);
if (ret < 0) {
return ret;
}

File diff suppressed because it is too large Load Diff

View File

@ -25,7 +25,7 @@
#ifndef BLOCK_QCOW2_H
#define BLOCK_QCOW2_H
#include "crypto/cipher.h"
#include "crypto/block.h"
#include "qemu/coroutine.h"
//#define DEBUG_ALLOC
@ -36,6 +36,7 @@
#define QCOW_CRYPT_NONE 0
#define QCOW_CRYPT_AES 1
#define QCOW_CRYPT_LUKS 2
#define QCOW_MAX_CRYPT_CLUSTERS 32
#define QCOW_MAX_SNAPSHOTS 65536
@ -52,6 +53,10 @@
* space for snapshot names and IDs */
#define QCOW_MAX_SNAPSHOTS_SIZE (1024 * QCOW_MAX_SNAPSHOTS)
/* Bitmap header extension constraints */
#define QCOW2_MAX_BITMAPS 65535
#define QCOW2_MAX_BITMAP_DIRECTORY_SIZE (1024 * QCOW2_MAX_BITMAPS)
/* indicate that the refcount of the referenced cluster is exactly one. */
#define QCOW_OFLAG_COPIED (1ULL << 63)
/* indicate that the cluster is compressed (they never have the copied flag) */
@ -163,6 +168,11 @@ typedef struct QCowSnapshot {
struct Qcow2Cache;
typedef struct Qcow2Cache Qcow2Cache;
typedef struct Qcow2CryptoHeaderExtension {
uint64_t offset;
uint64_t length;
} QEMU_PACKED Qcow2CryptoHeaderExtension;
typedef struct Qcow2UnknownHeaderExtension {
uint32_t magic;
uint32_t len;
@ -195,6 +205,14 @@ enum {
QCOW2_COMPAT_FEAT_MASK = QCOW2_COMPAT_LAZY_REFCOUNTS,
};
/* Autoclear feature bits */
enum {
QCOW2_AUTOCLEAR_BITMAPS_BITNR = 0,
QCOW2_AUTOCLEAR_BITMAPS = 1 << QCOW2_AUTOCLEAR_BITMAPS_BITNR,
QCOW2_AUTOCLEAR_MASK = QCOW2_AUTOCLEAR_BITMAPS,
};
enum qcow2_discard_type {
QCOW2_DISCARD_NEVER = 0,
QCOW2_DISCARD_ALWAYS,
@ -222,6 +240,13 @@ typedef uint64_t Qcow2GetRefcountFunc(const void *refcount_array,
typedef void Qcow2SetRefcountFunc(void *refcount_array,
uint64_t index, uint64_t value);
typedef struct Qcow2BitmapHeaderExt {
uint32_t nb_bitmaps;
uint32_t reserved32;
uint64_t bitmap_directory_size;
uint64_t bitmap_directory_offset;
} QEMU_PACKED Qcow2BitmapHeaderExt;
typedef struct BDRVQcow2State {
int cluster_bits;
int cluster_size;
@ -257,13 +282,21 @@ typedef struct BDRVQcow2State {
CoMutex lock;
QCryptoCipher *cipher; /* current cipher, NULL if no key yet */
Qcow2CryptoHeaderExtension crypto_header; /* QCow2 header extension */
QCryptoBlockOpenOptions *crypto_opts; /* Disk encryption runtime options */
QCryptoBlock *crypto; /* Disk encryption format driver */
bool crypt_physical_offset; /* Whether to use virtual or physical offset
for encryption initialization vector tweak */
uint32_t crypt_method_header;
uint64_t snapshots_offset;
int snapshots_size;
unsigned int nb_snapshots;
QCowSnapshot *snapshots;
uint32_t nb_bitmaps;
uint64_t bitmap_directory_size;
uint64_t bitmap_directory_offset;
int flags;
int qcow_version;
bool use_lazy_refcounts;
@ -492,6 +525,10 @@ static inline uint64_t refcount_diff(uint64_t r1, uint64_t r2)
int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov,
int64_t sector_num, int nb_sectors);
int64_t qcow2_refcount_metadata_size(int64_t clusters, size_t cluster_size,
int refcount_order, bool generous_increase,
uint64_t *refblock_count);
int qcow2_mark_dirty(BlockDriverState *bs);
int qcow2_mark_corrupt(BlockDriverState *bs);
int qcow2_mark_consistent(BlockDriverState *bs);
@ -512,6 +549,11 @@ int qcow2_update_cluster_refcount(BlockDriverState *bs, int64_t cluster_index,
uint64_t addend, bool decrease,
enum qcow2_discard_type type);
int64_t qcow2_refcount_area(BlockDriverState *bs, uint64_t offset,
uint64_t additional_clusters, bool exact_size,
int new_refblock_index,
uint64_t new_refblock_offset);
int64_t qcow2_alloc_clusters(BlockDriverState *bs, uint64_t size);
int64_t qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
int64_t nb_clusters);
@ -534,6 +576,10 @@ int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset,
int64_t size);
int qcow2_pre_write_overlap_check(BlockDriverState *bs, int ign, int64_t offset,
int64_t size);
int qcow2_inc_refcounts_imrt(BlockDriverState *bs, BdrvCheckResult *res,
void **refcount_table,
int64_t *refcount_table_size,
int64_t offset, int64_t size);
int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order,
BlockDriverAmendStatusCB *status_cb,
@ -545,8 +591,7 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index);
int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset);
int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num,
uint8_t *out_buf, const uint8_t *in_buf,
int nb_sectors, bool enc, Error **errp);
uint8_t *buf, int nb_sectors, bool enc, Error **errp);
int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
unsigned int *bytes, uint64_t *cluster_offset);
@ -605,4 +650,20 @@ int qcow2_cache_get_empty(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
void **table);
void qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, void **table);
/* qcow2-bitmap.c functions */
int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
void **refcount_table,
int64_t *refcount_table_size);
bool qcow2_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp);
int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp);
void qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp);
int qcow2_reopen_bitmaps_ro(BlockDriverState *bs, Error **errp);
bool qcow2_can_store_new_dirty_bitmap(BlockDriverState *bs,
const char *name,
uint32_t granularity,
Error **errp);
void qcow2_remove_persistent_dirty_bitmap(BlockDriverState *bs,
const char *name,
Error **errp);
#endif

View File

@ -583,7 +583,7 @@ static int qed_create(const char *filename, uint32_t cluster_size,
blk_set_allow_write_beyond_eof(blk, true);
/* File must start empty and grow, check truncate is supported */
ret = blk_truncate(blk, 0, errp);
ret = blk_truncate(blk, 0, PREALLOC_MODE_OFF, errp);
if (ret < 0) {
goto out;
}
@ -1342,12 +1342,19 @@ static int coroutine_fn bdrv_qed_co_pwrite_zeroes(BlockDriverState *bs,
QED_AIOCB_WRITE | QED_AIOCB_ZERO);
}
static int bdrv_qed_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
static int bdrv_qed_truncate(BlockDriverState *bs, int64_t offset,
PreallocMode prealloc, Error **errp)
{
BDRVQEDState *s = bs->opaque;
uint64_t old_image_size;
int ret;
if (prealloc != PREALLOC_MODE_OFF) {
error_setg(errp, "Unsupported preallocation mode '%s'",
PreallocMode_lookup[prealloc]);
return -ENOTSUP;
}
if (!qed_is_image_size_valid(offset, s->header.cluster_size,
s->header.table_size)) {
error_setg(errp, "Invalid image size specified");

View File

@ -312,6 +312,31 @@ static int64_t raw_getlength(BlockDriverState *bs)
return s->size;
}
static BlockMeasureInfo *raw_measure(QemuOpts *opts, BlockDriverState *in_bs,
Error **errp)
{
BlockMeasureInfo *info;
int64_t required;
if (in_bs) {
required = bdrv_getlength(in_bs);
if (required < 0) {
error_setg_errno(errp, -required, "Unable to get image size");
return NULL;
}
} else {
required = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
BDRV_SECTOR_SIZE);
}
info = g_new(BlockMeasureInfo, 1);
info->required = required;
/* Unallocated sectors count towards the file size in raw images */
info->fully_allocated = info->required;
return info;
}
static int raw_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
{
return bdrv_get_info(bs->file->bs, bdi);
@ -327,7 +352,8 @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
}
}
static int raw_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
static int raw_truncate(BlockDriverState *bs, int64_t offset,
PreallocMode prealloc, Error **errp)
{
BDRVRawState *s = bs->opaque;
@ -343,7 +369,7 @@ static int raw_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
s->size = offset;
offset += s->offset;
return bdrv_truncate(bs->file, offset, errp);
return bdrv_truncate(bs->file, offset, prealloc, errp);
}
static int raw_media_changed(BlockDriverState *bs)
@ -479,6 +505,7 @@ BlockDriver bdrv_raw = {
.bdrv_truncate = &raw_truncate,
.bdrv_getlength = &raw_getlength,
.has_variable_length = true,
.bdrv_measure = &raw_measure,
.bdrv_get_info = &raw_get_info,
.bdrv_refresh_limits = &raw_refresh_limits,
.bdrv_probe_blocksizes = &raw_probe_blocksizes,

View File

@ -936,11 +936,18 @@ static int64_t qemu_rbd_getlength(BlockDriverState *bs)
return info.size;
}
static int qemu_rbd_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
static int qemu_rbd_truncate(BlockDriverState *bs, int64_t offset,
PreallocMode prealloc, Error **errp)
{
BDRVRBDState *s = bs->opaque;
int r;
if (prealloc != PREALLOC_MODE_OFF) {
error_setg(errp, "Unsupported preallocation mode '%s'",
PreallocMode_lookup[prealloc]);
return -ENOTSUP;
}
r = rbd_resize(s->image, offset);
if (r < 0) {
error_setg_errno(errp, -r, "Failed to resize file");

View File

@ -2153,13 +2153,20 @@ static int64_t sd_getlength(BlockDriverState *bs)
return s->inode.vdi_size;
}
static int sd_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
static int sd_truncate(BlockDriverState *bs, int64_t offset,
PreallocMode prealloc, Error **errp)
{
BDRVSheepdogState *s = bs->opaque;
int ret, fd;
unsigned int datalen;
uint64_t max_vdi_size;
if (prealloc != PREALLOC_MODE_OFF) {
error_setg(errp, "Unsupported preallocation mode '%s'",
PreallocMode_lookup[prealloc]);
return -ENOTSUP;
}
max_vdi_size = (UINT64_C(1) << s->inode.block_size_shift) * MAX_DATA_OBJS;
if (offset < s->inode.vdi_size) {
error_setg(errp, "shrinking is not supported");
@ -2448,7 +2455,7 @@ static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num,
BDRVSheepdogState *s = bs->opaque;
if (offset > s->inode.vdi_size) {
ret = sd_truncate(bs, offset, NULL);
ret = sd_truncate(bs, offset, PREALLOC_MODE_OFF, NULL);
if (ret < 0) {
return ret;
}

View File

@ -832,7 +832,8 @@ static int vdi_create(const char *filename, QemuOpts *opts, Error **errp)
}
if (image_type == VDI_TYPE_STATIC) {
ret = blk_truncate(blk, offset + blocks * block_size, errp);
ret = blk_truncate(blk, offset + blocks * block_size,
PREALLOC_MODE_OFF, errp);
if (ret < 0) {
error_prepend(errp, "Failed to statically allocate %s", filename);
goto exit;

View File

@ -548,7 +548,7 @@ static int vhdx_log_flush(BlockDriverState *bs, BDRVVHDXState *s,
if (new_file_size % (1024*1024)) {
/* round up to nearest 1MB boundary */
new_file_size = ((new_file_size >> 20) + 1) << 20;
bdrv_truncate(bs->file, new_file_size, NULL);
bdrv_truncate(bs->file, new_file_size, PREALLOC_MODE_OFF, NULL);
}
}
qemu_vfree(desc_entries);

View File

@ -1171,7 +1171,8 @@ static int vhdx_allocate_block(BlockDriverState *bs, BDRVVHDXState *s,
/* per the spec, the address for a block is in units of 1MB */
*new_offset = ROUND_UP(*new_offset, 1024 * 1024);
return bdrv_truncate(bs->file, *new_offset + s->block_size, NULL);
return bdrv_truncate(bs->file, *new_offset + s->block_size,
PREALLOC_MODE_OFF, NULL);
}
/*
@ -1607,12 +1608,13 @@ static int vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s,
if (type == VHDX_TYPE_DYNAMIC) {
/* All zeroes, so we can just extend the file - the end of the BAT
* is the furthest thing we have written yet */
ret = blk_truncate(blk, data_file_offset, errp);
ret = blk_truncate(blk, data_file_offset, PREALLOC_MODE_OFF, errp);
if (ret < 0) {
goto exit;
}
} else if (type == VHDX_TYPE_FIXED) {
ret = blk_truncate(blk, data_file_offset + image_size, errp);
ret = blk_truncate(blk, data_file_offset + image_size,
PREALLOC_MODE_OFF, errp);
if (ret < 0) {
goto exit;
}

View File

@ -1714,7 +1714,7 @@ static int vmdk_create_extent(const char *filename, int64_t filesize,
blk_set_allow_write_beyond_eof(blk, true);
if (flat) {
ret = blk_truncate(blk, filesize, errp);
ret = blk_truncate(blk, filesize, PREALLOC_MODE_OFF, errp);
goto exit;
}
magic = cpu_to_be32(VMDK4_MAGIC);
@ -1777,7 +1777,8 @@ static int vmdk_create_extent(const char *filename, int64_t filesize,
goto exit;
}
ret = blk_truncate(blk, le64_to_cpu(header.grain_offset) << 9, errp);
ret = blk_truncate(blk, le64_to_cpu(header.grain_offset) << 9,
PREALLOC_MODE_OFF, errp);
if (ret < 0) {
goto exit;
}
@ -2086,7 +2087,7 @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp)
/* bdrv_pwrite write padding zeros to align to sector, we don't need that
* for description file */
if (desc_offset == 0) {
ret = blk_truncate(new_blk, desc_len, errp);
ret = blk_truncate(new_blk, desc_len, PREALLOC_MODE_OFF, errp);
}
exit:
if (new_blk) {

View File

@ -858,7 +858,7 @@ static int create_fixed_disk(BlockBackend *blk, uint8_t *buf,
/* Add footer to total size */
total_size += HEADER_SIZE;
ret = blk_truncate(blk, total_size, errp);
ret = blk_truncate(blk, total_size, PREALLOC_MODE_OFF, errp);
if (ret < 0) {
return ret;
}

View File

@ -593,10 +593,6 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
bs->detect_zeroes = detect_zeroes;
if (bdrv_key_required(bs)) {
autostart = 0;
}
block_acct_setup(blk_get_stats(blk), account_invalid, account_failed);
if (!parse_stats_intervals(blk_get_stats(blk), interval_list, errp)) {
@ -1987,6 +1983,8 @@ static void block_dirty_bitmap_add_prepare(BlkActionState *common,
/* AIO context taken and released within qmp_block_dirty_bitmap_add */
qmp_block_dirty_bitmap_add(action->node, action->name,
action->has_granularity, action->granularity,
action->has_persistent, action->persistent,
action->has_autoload, action->autoload,
&local_err);
if (!local_err) {
@ -2037,6 +2035,9 @@ static void block_dirty_bitmap_clear_prepare(BlkActionState *common,
} else if (!bdrv_dirty_bitmap_enabled(state->bitmap)) {
error_setg(errp, "Cannot clear a disabled bitmap");
return;
} else if (bdrv_dirty_bitmap_readonly(state->bitmap)) {
error_setg(errp, "Cannot clear a readonly bitmap");
return;
}
bdrv_clear_dirty_bitmap(state->bitmap, &state->backup);
@ -2265,24 +2266,8 @@ void qmp_block_passwd(bool has_device, const char *device,
bool has_node_name, const char *node_name,
const char *password, Error **errp)
{
Error *local_err = NULL;
BlockDriverState *bs;
AioContext *aio_context;
bs = bdrv_lookup_bs(has_device ? device : NULL,
has_node_name ? node_name : NULL,
&local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context);
bdrv_add_key(bs, password, errp);
aio_context_release(aio_context);
error_setg(errp,
"Setting block passwords directly is no longer supported");
}
/*
@ -2591,12 +2576,6 @@ void qmp_blockdev_change_medium(bool has_device, const char *device,
goto fail;
}
bdrv_add_key(medium_bs, NULL, &err);
if (err) {
error_propagate(errp, err);
goto fail;
}
rc = do_open_tray(has_device ? device : NULL,
has_id ? id : NULL,
false, &err);
@ -2731,9 +2710,12 @@ out:
void qmp_block_dirty_bitmap_add(const char *node, const char *name,
bool has_granularity, uint32_t granularity,
bool has_persistent, bool persistent,
bool has_autoload, bool autoload,
Error **errp)
{
BlockDriverState *bs;
BdrvDirtyBitmap *bitmap;
if (!name || name[0] == '\0') {
error_setg(errp, "Bitmap name cannot be empty");
@ -2756,7 +2738,32 @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name,
granularity = bdrv_get_default_bitmap_granularity(bs);
}
bdrv_create_dirty_bitmap(bs, granularity, name, errp);
if (!has_persistent) {
persistent = false;
}
if (!has_autoload) {
autoload = false;
}
if (has_autoload && !persistent) {
error_setg(errp, "Autoload flag must be used only for persistent "
"bitmaps");
return;
}
if (persistent &&
!bdrv_can_store_new_dirty_bitmap(bs, name, granularity, errp))
{
return;
}
bitmap = bdrv_create_dirty_bitmap(bs, granularity, name, errp);
if (bitmap == NULL) {
return;
}
bdrv_dirty_bitmap_set_persistance(bitmap, persistent);
bdrv_dirty_bitmap_set_autoload(bitmap, autoload);
}
void qmp_block_dirty_bitmap_remove(const char *node, const char *name,
@ -2764,6 +2771,7 @@ void qmp_block_dirty_bitmap_remove(const char *node, const char *name,
{
BlockDriverState *bs;
BdrvDirtyBitmap *bitmap;
Error *local_err = NULL;
bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
if (!bitmap || !bs) {
@ -2776,6 +2784,15 @@ void qmp_block_dirty_bitmap_remove(const char *node, const char *name,
name);
return;
}
if (bdrv_dirty_bitmap_get_persistance(bitmap)) {
bdrv_remove_persistent_dirty_bitmap(bs, name, &local_err);
if (local_err != NULL) {
error_propagate(errp, local_err);
return;
}
}
bdrv_dirty_bitmap_make_anon(bitmap);
bdrv_release_dirty_bitmap(bs, bitmap);
}
@ -2805,11 +2822,39 @@ void qmp_block_dirty_bitmap_clear(const char *node, const char *name,
"Bitmap '%s' is currently disabled and cannot be cleared",
name);
return;
} else if (bdrv_dirty_bitmap_readonly(bitmap)) {
error_setg(errp, "Bitmap '%s' is readonly and cannot be cleared", name);
return;
}
bdrv_clear_dirty_bitmap(bitmap, NULL);
}
BlockDirtyBitmapSha256 *qmp_x_debug_block_dirty_bitmap_sha256(const char *node,
const char *name,
Error **errp)
{
BdrvDirtyBitmap *bitmap;
BlockDriverState *bs;
BlockDirtyBitmapSha256 *ret = NULL;
char *sha256;
bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
if (!bitmap || !bs) {
return NULL;
}
sha256 = bdrv_dirty_bitmap_sha256(bitmap, errp);
if (sha256 == NULL) {
return NULL;
}
ret = g_new(BlockDirtyBitmapSha256, 1);
ret->sha256 = sha256;
return ret;
}
void hmp_drive_del(Monitor *mon, const QDict *qdict)
{
const char *id = qdict_get_str(qdict, "id");
@ -2913,7 +2958,7 @@ void qmp_block_resize(bool has_device, const char *device,
}
bdrv_drained_begin(bs);
ret = blk_truncate(blk, size, errp);
ret = blk_truncate(blk, size, PREALLOC_MODE_OFF, errp);
bdrv_drained_end(bs);
out:
@ -3866,13 +3911,6 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
QTAILQ_INSERT_TAIL(&monitor_bdrv_states, bs, monitor_list);
if (bs && bdrv_key_required(bs)) {
QTAILQ_REMOVE(&monitor_bdrv_states, bs, monitor_list);
bdrv_unref(bs);
error_setg(errp, "blockdev-add doesn't support encrypted devices");
goto fail;
}
fail:
visit_free(v);
}

View File

@ -638,6 +638,7 @@ qcrypto_block_luks_find_key(QCryptoBlock *block,
static int
qcrypto_block_luks_open(QCryptoBlock *block,
QCryptoBlockOpenOptions *options,
const char *optprefix,
QCryptoBlockReadFunc readfunc,
void *opaque,
unsigned int flags,
@ -661,7 +662,8 @@ qcrypto_block_luks_open(QCryptoBlock *block,
if (!(flags & QCRYPTO_BLOCK_OPEN_NO_IO)) {
if (!options->u.luks.key_secret) {
error_setg(errp, "Parameter 'key-secret' is required for cipher");
error_setg(errp, "Parameter '%skey-secret' is required for cipher",
optprefix ? optprefix : "");
return -1;
}
password = qcrypto_secret_lookup_as_utf8(
@ -885,6 +887,7 @@ qcrypto_block_luks_uuid_gen(uint8_t *uuidstr)
static int
qcrypto_block_luks_create(QCryptoBlock *block,
QCryptoBlockCreateOptions *options,
const char *optprefix,
QCryptoBlockInitFunc initfunc,
QCryptoBlockWriteFunc writefunc,
void *opaque,
@ -937,7 +940,8 @@ qcrypto_block_luks_create(QCryptoBlock *block,
* be silently ignored, for compatibility with dm-crypt */
if (!options->u.luks.key_secret) {
error_setg(errp, "Parameter 'key-secret' is required for cipher");
error_setg(errp, "Parameter '%skey-secret' is required for cipher",
optprefix ? optprefix : "");
return -1;
}
password = qcrypto_secret_lookup_as_utf8(luks_opts.key_secret, errp);

View File

@ -94,6 +94,7 @@ qcrypto_block_qcow_init(QCryptoBlock *block,
static int
qcrypto_block_qcow_open(QCryptoBlock *block,
QCryptoBlockOpenOptions *options,
const char *optprefix,
QCryptoBlockReadFunc readfunc G_GNUC_UNUSED,
void *opaque G_GNUC_UNUSED,
unsigned int flags,
@ -104,7 +105,8 @@ qcrypto_block_qcow_open(QCryptoBlock *block,
} else {
if (!options->u.qcow.key_secret) {
error_setg(errp,
"Parameter 'key-secret' is required for cipher");
"Parameter '%skey-secret' is required for cipher",
optprefix ? optprefix : "");
return -1;
}
return qcrypto_block_qcow_init(block,
@ -116,13 +118,15 @@ qcrypto_block_qcow_open(QCryptoBlock *block,
static int
qcrypto_block_qcow_create(QCryptoBlock *block,
QCryptoBlockCreateOptions *options,
const char *optprefix,
QCryptoBlockInitFunc initfunc G_GNUC_UNUSED,
QCryptoBlockWriteFunc writefunc G_GNUC_UNUSED,
void *opaque G_GNUC_UNUSED,
Error **errp)
{
if (!options->u.qcow.key_secret) {
error_setg(errp, "Parameter 'key-secret' is required for cipher");
error_setg(errp, "Parameter '%skey-secret' is required for cipher",
optprefix ? optprefix : "");
return -1;
}
/* QCow2 has no special header, since everything is hardwired */

View File

@ -48,6 +48,7 @@ bool qcrypto_block_has_format(QCryptoBlockFormat format,
QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options,
const char *optprefix,
QCryptoBlockReadFunc readfunc,
void *opaque,
unsigned int flags,
@ -67,7 +68,7 @@ QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options,
block->driver = qcrypto_block_drivers[options->format];
if (block->driver->open(block, options,
if (block->driver->open(block, options, optprefix,
readfunc, opaque, flags, errp) < 0) {
g_free(block);
return NULL;
@ -78,6 +79,7 @@ QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options,
QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options,
const char *optprefix,
QCryptoBlockInitFunc initfunc,
QCryptoBlockWriteFunc writefunc,
void *opaque,
@ -97,7 +99,7 @@ QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options,
block->driver = qcrypto_block_drivers[options->format];
if (block->driver->create(block, options, initfunc,
if (block->driver->create(block, options, optprefix, initfunc,
writefunc, opaque, errp) < 0) {
g_free(block);
return NULL;

View File

@ -41,6 +41,7 @@ struct QCryptoBlock {
struct QCryptoBlockDriver {
int (*open)(QCryptoBlock *block,
QCryptoBlockOpenOptions *options,
const char *optprefix,
QCryptoBlockReadFunc readfunc,
void *opaque,
unsigned int flags,
@ -48,6 +49,7 @@ struct QCryptoBlockDriver {
int (*create)(QCryptoBlock *block,
QCryptoBlockCreateOptions *options,
const char *optprefix,
QCryptoBlockInitFunc initfunc,
QCryptoBlockWriteFunc writefunc,
void *opaque,

View File

@ -45,6 +45,7 @@ The first cluster of a qcow2 image contains the file header:
32 - 35: crypt_method
0 for no encryption
1 for AES encryption
2 for LUKS encryption
36 - 39: l1_size
Number of entries in the active L1 table
@ -135,6 +136,7 @@ be stored. Each extension has a structure like the following:
0xE2792ACA - Backing file format name
0x6803f857 - Feature name table
0x23852875 - Bitmaps extension
0x0537be77 - Full disk encryption header pointer
other - Unknown header extension, can be safely
ignored
@ -201,12 +203,113 @@ The fields of the bitmaps extension are:
8 - 15: bitmap_directory_size
Size of the bitmap directory in bytes. It is the cumulative
size of all (nb_bitmaps) bitmap headers.
size of all (nb_bitmaps) bitmap directory entries.
16 - 23: bitmap_directory_offset
Offset into the image file at which the bitmap directory
starts. Must be aligned to a cluster boundary.
== Full disk encryption header pointer ==
The full disk encryption header must be present if, and only if, the
'crypt_method' header requires metadata. Currently this is only true
of the 'LUKS' crypt method. The header extension must be absent for
other methods.
This header provides the offset at which the crypt method can store
its additional data, as well as the length of such data.
Byte 0 - 7: Offset into the image file at which the encryption
header starts in bytes. Must be aligned to a cluster
boundary.
Byte 8 - 15: Length of the written encryption header in bytes.
Note actual space allocated in the qcow2 file may
be larger than this value, since it will be rounded
to the nearest multiple of the cluster size. Any
unused bytes in the allocated space will be initialized
to 0.
For the LUKS crypt method, the encryption header works as follows.
The first 592 bytes of the header clusters will contain the LUKS
partition header. This is then followed by the key material data areas.
The size of the key material data areas is determined by the number of
stripes in the key slot and key size. Refer to the LUKS format
specification ('docs/on-disk-format.pdf' in the cryptsetup source
package) for details of the LUKS partition header format.
In the LUKS partition header, the "payload-offset" field will be
calculated as normal for the LUKS spec. ie the size of the LUKS
header, plus key material regions, plus padding, relative to the
start of the LUKS header. This offset value is not required to be
qcow2 cluster aligned. Its value is currently never used in the
context of qcow2, since the qcow2 file format itself defines where
the real payload offset is, but none the less a valid payload offset
should always be present.
In the LUKS key slots header, the "key-material-offset" is relative
to the start of the LUKS header clusters in the qcow2 container,
not the start of the qcow2 file.
Logically the layout looks like
+-----------------------------+
| QCow2 header |
| QCow2 header extension X |
| QCow2 header extension FDE |
| QCow2 header extension ... |
| QCow2 header extension Z |
+-----------------------------+
| ....other QCow2 tables.... |
. .
. .
+-----------------------------+
| +-------------------------+ |
| | LUKS partition header | |
| +-------------------------+ |
| | LUKS key material 1 | |
| +-------------------------+ |
| | LUKS key material 2 | |
| +-------------------------+ |
| | LUKS key material ... | |
| +-------------------------+ |
| | LUKS key material 8 | |
| +-------------------------+ |
+-----------------------------+
| QCow2 cluster payload |
. .
. .
. .
| |
+-----------------------------+
== Data encryption ==
When an encryption method is requested in the header, the image payload
data must be encrypted/decrypted on every write/read. The image headers
and metadata are never encrypted.
The algorithms used for encryption vary depending on the method
- AES:
The AES cipher, in CBC mode, with 256 bit keys.
Initialization vectors generated using plain64 method, with
the virtual disk sector as the input tweak.
This format is no longer supported in QEMU system emulators, due
to a number of design flaws affecting its security. It is only
supported in the command line tools for the sake of back compatibility
and data liberation.
- LUKS:
The algorithms are specified in the LUKS header.
Initialization vectors generated using the method specified
in the LUKS header, with the physical disk sector as the
input tweak.
== Host cluster management ==
@ -426,8 +529,7 @@ Each bitmap saved in the image is described in a bitmap directory entry. The
bitmap directory is a contiguous area in the image file, whose starting offset
and length are given by the header extension fields bitmap_directory_offset and
bitmap_directory_size. The entries of the bitmap directory have variable
length, depending on the lengths of the bitmap name and extra data. These
entries are also called bitmap headers.
length, depending on the lengths of the bitmap name and extra data.
Structure of a bitmap directory entry:
@ -472,8 +574,7 @@ Structure of a bitmap directory entry:
17: granularity_bits
Granularity bits. Valid values: 0 - 63.
Note: Qemu currently doesn't support granularity_bits
greater than 31.
Note: Qemu currently supports only values 9 - 31.
Granularity is calculated as
granularity = 1 << granularity_bits

View File

@ -1646,6 +1646,8 @@ STEXI
@item block_passwd @var{device} @var{password}
@findex block_passwd
Set the encrypted device @var{device} password to @var{password}
This command is now obsolete and will always return an error since 2.10
ETEXI
{

31
hmp.c
View File

@ -1088,37 +1088,12 @@ void hmp_ringbuf_read(Monitor *mon, const QDict *qdict)
g_free(data);
}
static void hmp_cont_cb(void *opaque, int err)
{
if (!err) {
qmp_cont(NULL);
}
}
static bool key_is_missing(const BlockInfo *bdev)
{
return (bdev->inserted && bdev->inserted->encryption_key_missing);
}
void hmp_cont(Monitor *mon, const QDict *qdict)
{
BlockInfoList *bdev_list, *bdev;
Error *err = NULL;
bdev_list = qmp_query_block(NULL);
for (bdev = bdev_list; bdev; bdev = bdev->next) {
if (key_is_missing(bdev->value)) {
monitor_read_block_device_key(mon, bdev->value->device,
hmp_cont_cb, NULL);
goto out;
}
}
qmp_cont(&err);
hmp_handle_error(mon, &err);
out:
qapi_free_BlockInfoList(bdev_list);
}
void hmp_system_wakeup(Monitor *mon, const QDict *qdict)
@ -1741,12 +1716,6 @@ void hmp_change(Monitor *mon, const QDict *qdict)
qmp_blockdev_change_medium(true, device, false, NULL, target,
!!arg, arg, !!read_only, read_only_mode,
&err);
if (err &&
error_get_class(err) == ERROR_CLASS_DEVICE_ENCRYPTED) {
error_free(err);
monitor_read_block_device_key(mon, device, NULL, NULL);
return;
}
}
hmp_handle_error(mon, &err);

View File

@ -302,10 +302,13 @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
const char *backing_file);
int bdrv_get_backing_file_depth(BlockDriverState *bs);
void bdrv_refresh_filename(BlockDriverState *bs);
int bdrv_truncate(BdrvChild *child, int64_t offset, Error **errp);
int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc,
Error **errp);
int64_t bdrv_nb_sectors(BlockDriverState *bs);
int64_t bdrv_getlength(BlockDriverState *bs);
int64_t bdrv_get_allocated_file_size(BlockDriverState *bs);
BlockMeasureInfo *bdrv_measure(BlockDriver *drv, QemuOpts *opts,
BlockDriverState *in_bs, Error **errp);
void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr);
void bdrv_refresh_limits(BlockDriverState *bs, Error **errp);
int bdrv_commit(BlockDriverState *bs);
@ -464,9 +467,6 @@ BlockDriverState *bdrv_next(BdrvNextIterator *it);
BlockDriverState *bdrv_next_monitor_owned(BlockDriverState *bs);
bool bdrv_is_encrypted(BlockDriverState *bs);
bool bdrv_key_required(BlockDriverState *bs);
int bdrv_set_key(BlockDriverState *bs, const char *key);
void bdrv_add_key(BlockDriverState *bs, const char *key, Error **errp);
void bdrv_iterate_format(void (*it)(void *opaque, const char *name),
void *opaque);
const char *bdrv_get_node_name(const BlockDriverState *bs);
@ -620,4 +620,7 @@ void bdrv_add_child(BlockDriverState *parent, BlockDriverState *child,
Error **errp);
void bdrv_del_child(BlockDriverState *parent, BdrvChild *child, Error **errp);
bool bdrv_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name,
uint32_t granularity, Error **errp);
#endif

View File

@ -37,11 +37,11 @@
#include "qemu/main-loop.h"
#include "qemu/throttle.h"
#define BLOCK_FLAG_ENCRYPT 1
#define BLOCK_FLAG_LAZY_REFCOUNTS 8
#define BLOCK_OPT_SIZE "size"
#define BLOCK_OPT_ENCRYPT "encryption"
#define BLOCK_OPT_ENCRYPT_FORMAT "encrypt.format"
#define BLOCK_OPT_COMPAT6 "compat6"
#define BLOCK_OPT_HWVERSION "hwversion"
#define BLOCK_OPT_BACKING_FILE "backing_file"
@ -204,11 +204,14 @@ struct BlockDriver {
int coroutine_fn (*bdrv_co_flush_to_os)(BlockDriverState *bs);
const char *protocol_name;
int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset, Error **errp);
int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset,
PreallocMode prealloc, Error **errp);
int64_t (*bdrv_getlength)(BlockDriverState *bs);
bool has_variable_length;
int64_t (*bdrv_get_allocated_file_size)(BlockDriverState *bs);
BlockMeasureInfo *(*bdrv_measure)(QemuOpts *opts, BlockDriverState *in_bs,
Error **errp);
int coroutine_fn (*bdrv_co_pwritev_compressed)(BlockDriverState *bs,
uint64_t offset, uint64_t bytes, QEMUIOVector *qiov);
@ -381,6 +384,20 @@ struct BlockDriver {
uint64_t parent_perm, uint64_t parent_shared,
uint64_t *nperm, uint64_t *nshared);
/**
* Bitmaps should be marked as 'IN_USE' in the image on reopening image
* as rw. This handler should realize it. It also should unset readonly
* field of BlockDirtyBitmap's in case of success.
*/
int (*bdrv_reopen_bitmaps_rw)(BlockDriverState *bs, Error **errp);
bool (*bdrv_can_store_new_dirty_bitmap)(BlockDriverState *bs,
const char *name,
uint32_t granularity,
Error **errp);
void (*bdrv_remove_persistent_dirty_bitmap)(BlockDriverState *bs,
const char *name,
Error **errp);
QLIST_ENTRY(BlockDriver) list;
};
@ -529,7 +546,6 @@ struct BlockDriverState {
int open_flags; /* flags used to open the file, re-used for re-open */
bool read_only; /* if true, the media is read only */
bool encrypted; /* if true, the media is encrypted */
bool valid_key; /* if true, a valid encryption key has been set */
bool sg; /* if true, the device is a /dev/sg* */
bool probed; /* if true, format was probed rather than specified */
bool force_share; /* if true, always allow all shared permissions */

View File

@ -25,11 +25,15 @@ BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs,
void bdrv_dirty_bitmap_make_anon(BdrvDirtyBitmap *bitmap);
void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap);
void bdrv_release_named_dirty_bitmaps(BlockDriverState *bs);
void bdrv_release_persistent_dirty_bitmaps(BlockDriverState *bs);
void bdrv_remove_persistent_dirty_bitmap(BlockDriverState *bs,
const char *name,
Error **errp);
void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap);
void bdrv_enable_dirty_bitmap(BdrvDirtyBitmap *bitmap);
BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs);
uint32_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs);
uint32_t bdrv_dirty_bitmap_granularity(BdrvDirtyBitmap *bitmap);
uint32_t bdrv_dirty_bitmap_granularity(const BdrvDirtyBitmap *bitmap);
uint32_t bdrv_dirty_bitmap_meta_granularity(BdrvDirtyBitmap *bitmap);
bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap);
bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap);
@ -66,8 +70,16 @@ void bdrv_dirty_bitmap_deserialize_part(BdrvDirtyBitmap *bitmap,
void bdrv_dirty_bitmap_deserialize_zeroes(BdrvDirtyBitmap *bitmap,
uint64_t start, uint64_t count,
bool finish);
void bdrv_dirty_bitmap_deserialize_ones(BdrvDirtyBitmap *bitmap,
uint64_t start, uint64_t count,
bool finish);
void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap);
void bdrv_dirty_bitmap_set_readonly(BdrvDirtyBitmap *bitmap, bool value);
void bdrv_dirty_bitmap_set_autoload(BdrvDirtyBitmap *bitmap, bool autoload);
void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap,
bool persistent);
/* Functions that require manual locking. */
void bdrv_dirty_bitmap_lock(BdrvDirtyBitmap *bitmap);
void bdrv_dirty_bitmap_unlock(BdrvDirtyBitmap *bitmap);
@ -82,5 +94,13 @@ void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *hbi, int64_t sector_num);
int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap);
int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap);
void bdrv_dirty_bitmap_truncate(BlockDriverState *bs);
bool bdrv_dirty_bitmap_readonly(const BdrvDirtyBitmap *bitmap);
bool bdrv_has_readonly_bitmaps(BlockDriverState *bs);
bool bdrv_dirty_bitmap_get_autoload(const BdrvDirtyBitmap *bitmap);
bool bdrv_dirty_bitmap_get_persistance(BdrvDirtyBitmap *bitmap);
bool bdrv_has_changed_persistent_bitmaps(BlockDriverState *bs);
BdrvDirtyBitmap *bdrv_dirty_bitmap_next(BlockDriverState *bs,
BdrvDirtyBitmap *bitmap);
char *bdrv_dirty_bitmap_sha256(const BdrvDirtyBitmap *bitmap, Error **errp);
#endif

View File

@ -71,6 +71,7 @@ typedef enum {
/**
* qcrypto_block_open:
* @options: the encryption options
* @optprefix: name prefix for options
* @readfunc: callback for reading data from the volume
* @opaque: data to pass to @readfunc
* @flags: bitmask of QCryptoBlockOpenFlags values
@ -102,6 +103,7 @@ typedef enum {
* Returns: a block encryption format, or NULL on error
*/
QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options,
const char *optprefix,
QCryptoBlockReadFunc readfunc,
void *opaque,
unsigned int flags,
@ -109,7 +111,8 @@ QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options,
/**
* qcrypto_block_create:
* @format: the encryption format
* @options: the encryption options
* @optprefix: name prefix for options
* @initfunc: callback for initializing volume header
* @writefunc: callback for writing data to the volume header
* @opaque: data to pass to @initfunc and @writefunc
@ -133,6 +136,7 @@ QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options,
* Returns: a block encryption format, or NULL on error
*/
QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options,
const char *optprefix,
QCryptoBlockInitFunc initfunc,
QCryptoBlockWriteFunc writefunc,
void *opaque,

View File

@ -23,13 +23,6 @@ void monitor_cleanup(void);
int monitor_suspend(Monitor *mon);
void monitor_resume(Monitor *mon);
int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
BlockCompletionFunc *completion_cb,
void *opaque);
int monitor_read_block_device_key(Monitor *mon, const char *device,
BlockCompletionFunc *completion_cb,
void *opaque);
int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp);
int monitor_fd_param(Monitor *mon, const char *fdname, Error **errp);

View File

@ -125,7 +125,6 @@
typedef enum ErrorClass {
ERROR_CLASS_GENERIC_ERROR = QAPI_ERROR_CLASS_GENERICERROR,
ERROR_CLASS_COMMAND_NOT_FOUND = QAPI_ERROR_CLASS_COMMANDNOTFOUND,
ERROR_CLASS_DEVICE_ENCRYPTED = QAPI_ERROR_CLASS_DEVICEENCRYPTED,
ERROR_CLASS_DEVICE_NOT_ACTIVE = QAPI_ERROR_CLASS_DEVICENOTACTIVE,
ERROR_CLASS_DEVICE_NOT_FOUND = QAPI_ERROR_CLASS_DEVICENOTFOUND,
ERROR_CLASS_KVM_MISSING_CAP = QAPI_ERROR_CLASS_KVMMISSINGCAP,

View File

@ -228,6 +228,21 @@ void hbitmap_deserialize_part(HBitmap *hb, uint8_t *buf,
void hbitmap_deserialize_zeroes(HBitmap *hb, uint64_t start, uint64_t count,
bool finish);
/**
* hbitmap_deserialize_ones
* @hb: HBitmap to operate on.
* @start: First bit to restore.
* @count: Number of bits to restore.
* @finish: Whether to call hbitmap_deserialize_finish automatically.
*
* Fills the bitmap with ones.
*
* If @finish is false, caller must call hbitmap_serialize_finish before using
* the bitmap.
*/
void hbitmap_deserialize_ones(HBitmap *hb, uint64_t start, uint64_t count,
bool finish);
/**
* hbitmap_deserialize_finish
* @hb: HBitmap to operate on.
@ -237,6 +252,14 @@ void hbitmap_deserialize_zeroes(HBitmap *hb, uint64_t start, uint64_t count,
*/
void hbitmap_deserialize_finish(HBitmap *hb);
/**
* hbitmap_sha256:
* @bitmap: HBitmap to operate on.
*
* Returns SHA256 hash of the last level.
*/
char *hbitmap_sha256(const HBitmap *bitmap, Error **errp);
/**
* hbitmap_free:
* @hb: HBitmap to operate on.
@ -256,10 +279,9 @@ void hbitmap_free(HBitmap *hb);
* the lowest-numbered bit that is set in @hb, starting at @first.
*
* Concurrent setting of bits is acceptable, and will at worst cause the
* iteration to miss some of those bits. Resetting bits before the current
* position of the iterator is also okay. However, concurrent resetting of
* bits can lead to unexpected behavior if the iterator has not yet reached
* those bits.
* iteration to miss some of those bits.
*
* The concurrent resetting of bits is OK.
*/
void hbitmap_iter_init(HBitmapIter *hbi, const HBitmap *hb, uint64_t first);
@ -298,24 +320,7 @@ void hbitmap_free_meta(HBitmap *hb);
* Return the next bit that is set in @hbi's associated HBitmap,
* or -1 if all remaining bits are zero.
*/
static inline int64_t hbitmap_iter_next(HBitmapIter *hbi)
{
unsigned long cur = hbi->cur[HBITMAP_LEVELS - 1];
int64_t item;
if (cur == 0) {
cur = hbitmap_iter_skip_words(hbi);
if (cur == 0) {
return -1;
}
}
/* The next call will resume work from the next bit. */
hbi->cur[HBITMAP_LEVELS - 1] = cur & (cur - 1);
item = ((uint64_t)hbi->pos << BITS_PER_LEVEL) + ctzl(cur);
return item << hbi->granularity;
}
int64_t hbitmap_iter_next(HBitmapIter *hbi);
/**
* hbitmap_iter_next_word:

View File

@ -457,8 +457,6 @@ void qemu_set_tty_echo(int fd, bool echo);
void os_mem_prealloc(int fd, char *area, size_t sz, int smp_cpus,
Error **errp);
int qemu_read_password(char *buf, int buf_size);
/**
* qemu_get_pid_name:
* @pid: pid of a process

View File

@ -223,7 +223,8 @@ int coroutine_fn blk_co_pwrite_zeroes(BlockBackend *blk, int64_t offset,
int bytes, BdrvRequestFlags flags);
int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf,
int bytes);
int blk_truncate(BlockBackend *blk, int64_t offset, Error **errp);
int blk_truncate(BlockBackend *blk, int64_t offset, PreallocMode prealloc,
Error **errp);
int blk_pdiscard(BlockBackend *blk, int64_t offset, int bytes);
int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
int64_t pos, int size);

View File

@ -4136,74 +4136,6 @@ void monitor_cleanup(void)
qemu_mutex_unlock(&monitor_lock);
}
static void bdrv_password_cb(void *opaque, const char *password,
void *readline_opaque)
{
Monitor *mon = opaque;
BlockDriverState *bs = readline_opaque;
int ret = 0;
Error *local_err = NULL;
bdrv_add_key(bs, password, &local_err);
if (local_err) {
error_report_err(local_err);
ret = -EPERM;
}
if (mon->password_completion_cb)
mon->password_completion_cb(mon->password_opaque, ret);
monitor_read_command(mon, 1);
}
int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
BlockCompletionFunc *completion_cb,
void *opaque)
{
int err;
monitor_printf(mon, "%s (%s) is encrypted.\n", bdrv_get_device_name(bs),
bdrv_get_encrypted_filename(bs));
mon->password_completion_cb = completion_cb;
mon->password_opaque = opaque;
err = monitor_read_password(mon, bdrv_password_cb, bs);
if (err && completion_cb)
completion_cb(opaque, err);
return err;
}
int monitor_read_block_device_key(Monitor *mon, const char *device,
BlockCompletionFunc *completion_cb,
void *opaque)
{
Error *err = NULL;
BlockBackend *blk;
blk = blk_by_name(device);
if (!blk) {
monitor_printf(mon, "Device not found %s\n", device);
return -1;
}
if (!blk_bs(blk)) {
monitor_printf(mon, "Device '%s' has no medium\n", device);
return -1;
}
bdrv_add_key(blk_bs(blk), NULL, &err);
if (err) {
error_free(err);
return monitor_read_bdrv_key_start(mon, blk_bs(blk), completion_cb, opaque);
}
if (completion_cb) {
completion_cb(opaque, 0);
}
return 0;
}
QemuOptsList qemu_mon_opts = {
.name = "mon",
.implied_opt_name = "chardev",

View File

@ -2431,8 +2431,6 @@
# Since: 0.14.0
#
# Returns: If successful, nothing
# If QEMU was started with an encrypted block device and a key has
# not yet been set, DeviceEncrypted.
#
# Notes: This command will succeed if the guest is currently running. It
# will also succeed if the guest is in the "inmigrate" state; in
@ -2713,8 +2711,7 @@
# * This command is stateless, this means that commands that depend
# on state information (such as getfd) might not work
#
# * Commands that prompt the user for data (eg. 'cont' when the block
# device is encrypted) don't currently work
# * Commands that prompt the user for data don't currently work
#
# Example:
#
@ -3019,11 +3016,6 @@
#
# Returns: Nothing on success.
# If @device is not a valid block device, DeviceNotFound
# If the new block device is encrypted, DeviceEncrypted. Note that
# if this error is returned, the device has been opened successfully
# and an additional call to @block_passwd is required to set the
# device's password. The behavior of reads and writes to the block
# device between when these calls are executed is undefined.
#
# Notes: This interface is deprecated, and it is strongly recommended that you
# avoid using it. For changing block devices, use

View File

@ -32,6 +32,27 @@
'date-sec': 'int', 'date-nsec': 'int',
'vm-clock-sec': 'int', 'vm-clock-nsec': 'int' } }
##
# @ImageInfoSpecificQCow2EncryptionBase:
#
# @format: The encryption format
#
# Since: 2.10
##
{ 'struct': 'ImageInfoSpecificQCow2EncryptionBase',
'data': { 'format': 'BlockdevQcow2EncryptionFormat'}}
##
# @ImageInfoSpecificQCow2Encryption:
#
# Since: 2.10
##
{ 'union': 'ImageInfoSpecificQCow2Encryption',
'base': 'ImageInfoSpecificQCow2EncryptionBase',
'discriminator': 'format',
'data': { 'aes': 'QCryptoBlockInfoQCow',
'luks': 'QCryptoBlockInfoLUKS' } }
##
# @ImageInfoSpecificQCow2:
#
@ -44,6 +65,9 @@
#
# @refcount-bits: width of a refcount entry in bits (since 2.3)
#
# @encrypt: details about encryption parameters; only set if image
# is encrypted (since 2.10)
#
# Since: 1.7
##
{ 'struct': 'ImageInfoSpecificQCow2',
@ -51,7 +75,8 @@
'compat': 'str',
'*lazy-refcounts': 'bool',
'*corrupt': 'bool',
'refcount-bits': 'int'
'refcount-bits': 'int',
'*encrypt': 'ImageInfoSpecificQCow2Encryption'
} }
##
@ -259,8 +284,7 @@
#
# @encrypted: true if the backing device is encrypted
#
# @encryption_key_missing: true if the backing device is encrypted but an
# valid encryption key is missing
# @encryption_key_missing: Deprecated; always false
#
# @detect_zeroes: detect and optimize zero writes (Since 2.1)
#
@ -463,6 +487,31 @@
'*tray_open': 'bool', '*io-status': 'BlockDeviceIoStatus',
'*dirty-bitmaps': ['BlockDirtyInfo'] } }
##
# @BlockMeasureInfo:
#
# Image file size calculation information. This structure describes the size
# requirements for creating a new image file.
#
# The size requirements depend on the new image file format. File size always
# equals virtual disk size for the 'raw' format, even for sparse POSIX files.
# Compact formats such as 'qcow2' represent unallocated and zero regions
# efficiently so file size may be smaller than virtual disk size.
#
# The values are upper bounds that are guaranteed to fit the new image file.
# Subsequent modification, such as internal snapshot or bitmap creation, may
# require additional space and is not covered here.
#
# @required: Size required for a new image file, in bytes.
#
# @fully-allocated: Image file size, in bytes, once data has been written
# to all sectors.
#
# Since: 2.10
##
{ 'struct': 'BlockMeasureInfo',
'data': {'required': 'int', 'fully-allocated': 'int'} }
##
# @query-block:
#
@ -946,39 +995,7 @@
# This command sets the password of a block device that has not been open
# with a password and requires one.
#
# The two cases where this can happen are a block device is created through
# QEMU's initial command line or a block device is changed through the legacy
# @change interface.
#
# In the event that the block device is created through the initial command
# line, the VM will start in the stopped state regardless of whether '-S' is
# used. The intention is for a management tool to query the block devices to
# determine which ones are encrypted, set the passwords with this command, and
# then start the guest with the @cont command.
#
# Either @device or @node-name must be set but not both.
#
# @device: the name of the block backend device to set the password on
#
# @node-name: graph node name to set the password on (Since 2.0)
#
# @password: the password to use for the device
#
# Returns: nothing on success
# If @device is not a valid block device, DeviceNotFound
# If @device is not encrypted, DeviceNotEncrypted
#
# Notes: Not all block formats support encryption and some that do are not
# able to validate that a password is correct. Disk corruption may
# occur if an invalid password is specified.
#
# Since: 0.14.0
#
# Example:
#
# -> { "execute": "block_passwd", "arguments": { "device": "ide0-hd0",
# "password": "12345" } }
# <- { "return": {} }
# This command is now obsolete and will always return an error since 2.10
#
##
{ 'command': 'block_passwd', 'data': {'*device': 'str',
@ -1561,10 +1578,20 @@
# @granularity: the bitmap granularity, default is 64k for
# block-dirty-bitmap-add
#
# @persistent: the bitmap is persistent, i.e. it will be saved to the
# corresponding block device image file on its close. For now only
# Qcow2 disks support persistent bitmaps. Default is false for
# block-dirty-bitmap-add. (Since: 2.10)
#
# @autoload: the bitmap will be automatically loaded when the image it is stored
# in is opened. This flag may only be specified for persistent
# bitmaps. Default is false for block-dirty-bitmap-add. (Since: 2.10)
#
# Since: 2.4
##
{ 'struct': 'BlockDirtyBitmapAdd',
'data': { 'node': 'str', 'name': 'str', '*granularity': 'uint32' } }
'data': { 'node': 'str', 'name': 'str', '*granularity': 'uint32',
'*persistent': 'bool', '*autoload': 'bool' } }
##
# @block-dirty-bitmap-add:
@ -1591,7 +1618,8 @@
# @block-dirty-bitmap-remove:
#
# Stop write tracking and remove the dirty bitmap that was created
# with block-dirty-bitmap-add.
# with block-dirty-bitmap-add. If the bitmap is persistent, remove it from its
# storage too.
#
# Returns: nothing on success
# If @node is not a valid block device or node, DeviceNotFound
@ -1633,6 +1661,33 @@
{ 'command': 'block-dirty-bitmap-clear',
'data': 'BlockDirtyBitmap' }
##
# @BlockDirtyBitmapSha256:
#
# SHA256 hash of dirty bitmap data
#
# @sha256: ASCII representation of SHA256 bitmap hash
#
# Since: 2.10
##
{ 'struct': 'BlockDirtyBitmapSha256',
'data': {'sha256': 'str'} }
##
# @x-debug-block-dirty-bitmap-sha256:
#
# Get bitmap SHA256
#
# Returns: BlockDirtyBitmapSha256 on success
# If @node is not a valid block device, DeviceNotFound
# If @name is not found or if hashing has failed, GenericError with an
# explanation
#
# Since: 2.10
##
{ 'command': 'x-debug-block-dirty-bitmap-sha256',
'data': 'BlockDirtyBitmap', 'returns': 'BlockDirtyBitmapSha256' }
##
# @blockdev-mirror:
#
@ -2281,6 +2336,63 @@
'data': { 'flags': 'Qcow2OverlapCheckFlags',
'mode': 'Qcow2OverlapCheckMode' } }
##
# @BlockdevQcowEncryptionFormat:
#
# @aes: AES-CBC with plain64 initialization vectors
#
# Since: 2.10
##
{ 'enum': 'BlockdevQcowEncryptionFormat',
'data': [ 'aes' ] }
##
# @BlockdevQcowEncryption:
#
# Since: 2.10
##
{ 'union': 'BlockdevQcowEncryption',
'base': { 'format': 'BlockdevQcowEncryptionFormat' },
'discriminator': 'format',
'data': { 'aes': 'QCryptoBlockOptionsQCow' } }
##
# @BlockdevOptionsQcow:
#
# Driver specific block device options for qcow.
#
# @encrypt: Image decryption options. Mandatory for
# encrypted images, except when doing a metadata-only
# probe of the image.
#
# Since: 2.10
##
{ 'struct': 'BlockdevOptionsQcow',
'base': 'BlockdevOptionsGenericCOWFormat',
'data': { '*encrypt': 'BlockdevQcowEncryption' } }
##
# @BlockdevQcow2EncryptionFormat:
# @aes: AES-CBC with plain64 initialization venctors
#
# Since: 2.10
##
{ 'enum': 'BlockdevQcow2EncryptionFormat',
'data': [ 'aes', 'luks' ] }
##
# @BlockdevQcow2Encryption:
#
# Since: 2.10
##
{ 'union': 'BlockdevQcow2Encryption',
'base': { 'format': 'BlockdevQcow2EncryptionFormat' },
'discriminator': 'format',
'data': { 'aes': 'QCryptoBlockOptionsQCow',
'luks': 'QCryptoBlockOptionsLUKS'} }
##
# @BlockdevOptionsQcow2:
#
@ -2315,6 +2427,9 @@
# @cache-clean-interval: clean unused entries in the L2 and refcount
# caches. The interval is in seconds. The default value
# is 0 and it disables this feature (since 2.5)
# @encrypt: Image decryption options. Mandatory for
# encrypted images, except when doing a metadata-only
# probe of the image. (since 2.10)
#
# Since: 2.9
##
@ -2328,8 +2443,8 @@
'*cache-size': 'int',
'*l2-cache-size': 'int',
'*refcount-cache-size': 'int',
'*cache-clean-interval': 'int' } }
'*cache-clean-interval': 'int',
'*encrypt': 'BlockdevQcow2Encryption' } }
##
# @BlockdevOptionsSsh:
@ -2976,7 +3091,7 @@
'null-co': 'BlockdevOptionsNull',
'parallels': 'BlockdevOptionsGenericFormat',
'qcow2': 'BlockdevOptionsQcow2',
'qcow': 'BlockdevOptionsGenericCOWFormat',
'qcow': 'BlockdevOptionsQcow',
'qed': 'BlockdevOptionsGenericCOWFormat',
'quorum': 'BlockdevOptionsQuorum',
'raw': 'BlockdevOptionsRaw',

View File

@ -14,9 +14,6 @@
#
# @CommandNotFound: the requested command has not been found
#
# @DeviceEncrypted: the requested operation can't be fulfilled because the
# selected device is encrypted
#
# @DeviceNotActive: a device has failed to be become active
#
# @DeviceNotFound: the requested device has not been found
@ -28,7 +25,7 @@
##
{ 'enum': 'QapiErrorClass',
# Keep this in sync with ErrorClass in error.h
'data': [ 'GenericError', 'CommandNotFound', 'DeviceEncrypted',
'data': [ 'GenericError', 'CommandNotFound',
'DeviceNotActive', 'DeviceNotFound', 'KVMMissingCap' ] }
##

View File

@ -540,10 +540,20 @@ File name of a base image (see @option{create} subcommand)
@item backing_fmt
Image format of the base image
@item encryption
If this option is set to @code{on}, the image is encrypted with 128-bit AES-CBC.
This option is deprecated and equivalent to @code{encrypt.format=aes}
The use of encryption in qcow and qcow2 images is considered to be flawed by
modern cryptography standards, suffering from a number of design problems:
@item encrypt.format
If this is set to @code{luks}, it requests that the qcow2 payload (not
qcow2 header) be encrypted using the LUKS format. The passphrase to
use to unlock the LUKS key slot is given by the @code{encrypt.key-secret}
parameter. LUKS encryption parameters can be tuned with the other
@code{encrypt.*} parameters.
If this is set to @code{aes}, the image is encrypted with 128-bit AES-CBC.
The encryption key is given by the @code{encrypt.key-secret} parameter.
This encryption format is considered to be flawed by modern cryptography
standards, suffering from a number of design problems:
@itemize @minus
@item The AES-CBC cipher is used with predictable initialization vectors based
@ -558,10 +568,45 @@ original file must then be securely erased using a program like shred,
though even this is ineffective with many modern storage technologies.
@end itemize
Use of qcow / qcow2 encryption with QEMU is deprecated, and support for
it will go away in a future release. Users are recommended to use an
alternative encryption technology such as the Linux dm-crypt / LUKS
system.
The use of this is no longer supported in system emulators. Support only
remains in the command line utilities, for the purposes of data liberation
and interoperability with old versions of QEMU. The @code{luks} format
should be used instead.
@item encrypt.key-secret
Provides the ID of a @code{secret} object that contains the passphrase
(@code{encrypt.format=luks}) or encryption key (@code{encrypt.format=aes}).
@item encrypt.cipher-alg
Name of the cipher algorithm and key length. Currently defaults
to @code{aes-256}. Only used when @code{encrypt.format=luks}.
@item encrypt.cipher-mode
Name of the encryption mode to use. Currently defaults to @code{xts}.
Only used when @code{encrypt.format=luks}.
@item encrypt.ivgen-alg
Name of the initialization vector generator algorithm. Currently defaults
to @code{plain64}. Only used when @code{encrypt.format=luks}.
@item encrypt.ivgen-hash-alg
Name of the hash algorithm to use with the initialization vector generator
(if required). Defaults to @code{sha256}. Only used when @code{encrypt.format=luks}.
@item encrypt.hash-alg
Name of the hash algorithm to use for PBKDF algorithm
Defaults to @code{sha256}. Only used when @code{encrypt.format=luks}.
@item encrypt.iter-time
Amount of time, in milliseconds, to use for PBKDF algorithm per key slot.
Defaults to @code{2000}. Only used when @code{encrypt.format=luks}.
@item cluster_size
Changes the qcow2 cluster size (must be between 512 and 2M). Smaller cluster
@ -636,7 +681,69 @@ Supported options:
@item backing_file
File name of a base image (see @option{create} subcommand)
@item encryption
If this option is set to @code{on}, the image is encrypted.
This option is deprecated and equivalent to @code{encrypt.format=aes}
@item encrypt.format
If this is set to @code{aes}, the image is encrypted with 128-bit AES-CBC.
The encryption key is given by the @code{encrypt.key-secret} parameter.
This encryption format is considered to be flawed by modern cryptography
standards, suffering from a number of design problems enumerated previously
against the @code{qcow2} image format.
The use of this is no longer supported in system emulators. Support only
remains in the command line utilities, for the purposes of data liberation
and interoperability with old versions of QEMU.
Users requiring native encryption should use the @code{qcow2} format
instead with @code{encrypt.format=luks}.
@item encrypt.key-secret
Provides the ID of a @code{secret} object that contains the encryption
key (@code{encrypt.format=aes}).
@end table
@item luks
LUKS v1 encryption format, compatible with Linux dm-crypt/cryptsetup
Supported options:
@table @code
@item key-secret
Provides the ID of a @code{secret} object that contains the passphrase.
@item cipher-alg
Name of the cipher algorithm and key length. Currently defaults
to @code{aes-256}.
@item cipher-mode
Name of the encryption mode to use. Currently defaults to @code{xts}.
@item ivgen-alg
Name of the initialization vector generator algorithm. Currently defaults
to @code{plain64}.
@item ivgen-hash-alg
Name of the hash algorithm to use with the initialization vector generator
(if required). Defaults to @code{sha256}.
@item hash-alg
Name of the hash algorithm to use for PBKDF algorithm
Defaults to @code{sha256}.
@item iter-time
Amount of time, in milliseconds, to use for PBKDF algorithm per key slot.
Defaults to @code{2000}.
@end table
@item vdi

View File

@ -63,6 +63,12 @@ STEXI
@item map [--object @var{objectdef}] [--image-opts] [-f @var{fmt}] [--output=@var{ofmt}] [-U] @var{filename}
ETEXI
DEF("measure", img_measure,
"measure [--output=ofmt] [-O output_fmt] [-o options] [--size N | [--object objectdef] [--image-opts] [-f fmt] [-l snapshot_param] filename]")
STEXI
@item measure [--output=@var{ofmt}] [-O @var{output_fmt}] [-o @var{options}] [--size @var{N} | [--object @var{objectdef}] [--image-opts] [-f @var{fmt}] [-l @var{snapshot_param}] @var{filename}]
ETEXI
DEF("snapshot", img_snapshot,
"snapshot [--object objectdef] [--image-opts] [-U] [-q] [-l | -a snapshot | -c snapshot | -d snapshot] filename")
STEXI

View File

@ -24,6 +24,7 @@
#include "qemu/osdep.h"
#include "qemu-version.h"
#include "qapi/error.h"
#include "qapi/util.h"
#include "qapi-visit.h"
#include "qapi/qobject-output-visitor.h"
#include "qapi/qmp/qerror.h"
@ -61,6 +62,8 @@ enum {
OPTION_FLUSH_INTERVAL = 261,
OPTION_NO_DRAIN = 262,
OPTION_TARGET_IMAGE_OPTS = 263,
OPTION_SIZE = 264,
OPTION_PREALLOCATION = 265,
};
typedef enum OutputFormat {
@ -260,29 +263,6 @@ static int print_block_option_help(const char *filename, const char *fmt)
}
static int img_open_password(BlockBackend *blk, const char *filename,
int flags, bool quiet)
{
BlockDriverState *bs;
char password[256];
bs = blk_bs(blk);
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");
return -1;
}
if (bdrv_set_key(bs, password) < 0) {
error_report("invalid password");
return -1;
}
}
return 0;
}
static BlockBackend *img_open_opts(const char *optstr,
QemuOpts *opts, int flags, bool writethrough,
bool quiet, bool force_share)
@ -307,10 +287,6 @@ static BlockBackend *img_open_opts(const char *optstr,
}
blk_set_enable_write_cache(blk, !writethrough);
if (img_open_password(blk, optstr, flags, quiet) < 0) {
blk_unref(blk);
return NULL;
}
return blk;
}
@ -340,10 +316,6 @@ static BlockBackend *img_open_file(const char *filename,
}
blk_set_enable_write_cache(blk, !writethrough);
if (img_open_password(blk, filename, flags, quiet) < 0) {
blk_unref(blk);
return NULL;
}
return blk;
}
@ -2264,6 +2236,8 @@ static int img_convert(int argc, char **argv)
if (s.compressed) {
bool encryption =
qemu_opt_get_bool(opts, BLOCK_OPT_ENCRYPT, false);
const char *encryptfmt =
qemu_opt_get(opts, BLOCK_OPT_ENCRYPT_FORMAT);
const char *preallocation =
qemu_opt_get(opts, BLOCK_OPT_PREALLOC);
@ -2273,7 +2247,7 @@ static int img_convert(int argc, char **argv)
goto out;
}
if (encryption) {
if (encryption || encryptfmt) {
error_report("Compression and encryption not supported at "
"the same time");
ret = -1;
@ -3436,9 +3410,10 @@ static int img_resize(int argc, char **argv)
Error *err = NULL;
int c, ret, relative;
const char *filename, *fmt, *size;
int64_t n, total_size;
int64_t n, total_size, current_size;
bool quiet = false;
BlockBackend *blk = NULL;
PreallocMode prealloc = PREALLOC_MODE_OFF;
QemuOpts *param;
static QemuOptsList resize_options = {
@ -3472,6 +3447,7 @@ static int img_resize(int argc, char **argv)
{"help", no_argument, 0, 'h'},
{"object", required_argument, 0, OPTION_OBJECT},
{"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
{"preallocation", required_argument, 0, OPTION_PREALLOCATION},
{0, 0, 0, 0}
};
c = getopt_long(argc, argv, ":f:hq",
@ -3506,6 +3482,15 @@ static int img_resize(int argc, char **argv)
case OPTION_IMAGE_OPTS:
image_opts = true;
break;
case OPTION_PREALLOCATION:
prealloc = qapi_enum_parse(PreallocMode_lookup, optarg,
PREALLOC_MODE__MAX, PREALLOC_MODE__MAX,
NULL);
if (prealloc == PREALLOC_MODE__MAX) {
error_report("Invalid preallocation mode '%s'", optarg);
return 1;
}
break;
}
}
if (optind != argc - 1) {
@ -3554,8 +3539,16 @@ static int img_resize(int argc, char **argv)
goto out;
}
current_size = blk_getlength(blk);
if (current_size < 0) {
error_report("Failed to inquire current image length: %s",
strerror(-current_size));
ret = -1;
goto out;
}
if (relative) {
total_size = blk_getlength(blk) + n * relative;
total_size = current_size + n * relative;
} else {
total_size = n;
}
@ -3565,7 +3558,13 @@ static int img_resize(int argc, char **argv)
goto out;
}
ret = blk_truncate(blk, total_size, &err);
if (total_size <= current_size && prealloc != PREALLOC_MODE_OFF) {
error_report("Preallocation can only be used for growing images");
ret = -1;
goto out;
}
ret = blk_truncate(blk, total_size, prealloc, &err);
if (!ret) {
qprintf(quiet, "Image resized.\n");
} else {
@ -4448,6 +4447,239 @@ out:
return 0;
}
static void dump_json_block_measure_info(BlockMeasureInfo *info)
{
QString *str;
QObject *obj;
Visitor *v = qobject_output_visitor_new(&obj);
visit_type_BlockMeasureInfo(v, NULL, &info, &error_abort);
visit_complete(v, &obj);
str = qobject_to_json_pretty(obj);
assert(str != NULL);
printf("%s\n", qstring_get_str(str));
qobject_decref(obj);
visit_free(v);
QDECREF(str);
}
static int img_measure(int argc, char **argv)
{
static const struct option long_options[] = {
{"help", no_argument, 0, 'h'},
{"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
{"object", required_argument, 0, OPTION_OBJECT},
{"output", required_argument, 0, OPTION_OUTPUT},
{"size", required_argument, 0, OPTION_SIZE},
{"force-share", no_argument, 0, 'U'},
{0, 0, 0, 0}
};
OutputFormat output_format = OFORMAT_HUMAN;
BlockBackend *in_blk = NULL;
BlockDriver *drv;
const char *filename = NULL;
const char *fmt = NULL;
const char *out_fmt = "raw";
char *options = NULL;
char *snapshot_name = NULL;
bool force_share = false;
QemuOpts *opts = NULL;
QemuOpts *object_opts = NULL;
QemuOpts *sn_opts = NULL;
QemuOptsList *create_opts = NULL;
bool image_opts = false;
uint64_t img_size = UINT64_MAX;
BlockMeasureInfo *info = NULL;
Error *local_err = NULL;
int ret = 1;
int c;
while ((c = getopt_long(argc, argv, "hf:O:o:l:U",
long_options, NULL)) != -1) {
switch (c) {
case '?':
case 'h':
help();
break;
case 'f':
fmt = optarg;
break;
case 'O':
out_fmt = optarg;
break;
case 'o':
if (!is_valid_option_list(optarg)) {
error_report("Invalid option list: %s", optarg);
goto out;
}
if (!options) {
options = g_strdup(optarg);
} else {
char *old_options = options;
options = g_strdup_printf("%s,%s", options, optarg);
g_free(old_options);
}
break;
case 'l':
if (strstart(optarg, SNAPSHOT_OPT_BASE, NULL)) {
sn_opts = qemu_opts_parse_noisily(&internal_snapshot_opts,
optarg, false);
if (!sn_opts) {
error_report("Failed in parsing snapshot param '%s'",
optarg);
goto out;
}
} else {
snapshot_name = optarg;
}
break;
case 'U':
force_share = true;
break;
case OPTION_OBJECT:
object_opts = qemu_opts_parse_noisily(&qemu_object_opts,
optarg, true);
if (!object_opts) {
goto out;
}
break;
case OPTION_IMAGE_OPTS:
image_opts = true;
break;
case OPTION_OUTPUT:
if (!strcmp(optarg, "json")) {
output_format = OFORMAT_JSON;
} else if (!strcmp(optarg, "human")) {
output_format = OFORMAT_HUMAN;
} else {
error_report("--output must be used with human or json "
"as argument.");
goto out;
}
break;
case OPTION_SIZE:
{
int64_t sval;
sval = cvtnum(optarg);
if (sval < 0) {
if (sval == -ERANGE) {
error_report("Image size must be less than 8 EiB!");
} else {
error_report("Invalid image size specified! You may use "
"k, M, G, T, P or E suffixes for ");
error_report("kilobytes, megabytes, gigabytes, terabytes, "
"petabytes and exabytes.");
}
goto out;
}
img_size = (uint64_t)sval;
}
break;
}
}
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
NULL, NULL)) {
goto out;
}
if (argc - optind > 1) {
error_report("At most one filename argument is allowed.");
goto out;
} else if (argc - optind == 1) {
filename = argv[optind];
}
if (!filename &&
(object_opts || image_opts || fmt || snapshot_name || sn_opts)) {
error_report("--object, --image-opts, -f, and -l "
"require a filename argument.");
goto out;
}
if (filename && img_size != UINT64_MAX) {
error_report("--size N cannot be used together with a filename.");
goto out;
}
if (!filename && img_size == UINT64_MAX) {
error_report("Either --size N or one filename must be specified.");
goto out;
}
if (filename) {
in_blk = img_open(image_opts, filename, fmt, 0,
false, false, force_share);
if (!in_blk) {
goto out;
}
if (sn_opts) {
bdrv_snapshot_load_tmp(blk_bs(in_blk),
qemu_opt_get(sn_opts, SNAPSHOT_OPT_ID),
qemu_opt_get(sn_opts, SNAPSHOT_OPT_NAME),
&local_err);
} else if (snapshot_name != NULL) {
bdrv_snapshot_load_tmp_by_id_or_name(blk_bs(in_blk),
snapshot_name, &local_err);
}
if (local_err) {
error_reportf_err(local_err, "Failed to load snapshot: ");
goto out;
}
}
drv = bdrv_find_format(out_fmt);
if (!drv) {
error_report("Unknown file format '%s'", out_fmt);
goto out;
}
if (!drv->create_opts) {
error_report("Format driver '%s' does not support image creation",
drv->format_name);
goto out;
}
create_opts = qemu_opts_append(create_opts, drv->create_opts);
create_opts = qemu_opts_append(create_opts, bdrv_file.create_opts);
opts = qemu_opts_create(create_opts, NULL, 0, &error_abort);
if (options) {
qemu_opts_do_parse(opts, options, NULL, &local_err);
if (local_err) {
error_report_err(local_err);
error_report("Invalid options for file format '%s'", out_fmt);
goto out;
}
}
if (img_size != UINT64_MAX) {
qemu_opt_set_number(opts, BLOCK_OPT_SIZE, img_size, &error_abort);
}
info = bdrv_measure(drv, opts, in_blk ? blk_bs(in_blk) : NULL, &local_err);
if (local_err) {
error_report_err(local_err);
goto out;
}
if (output_format == OFORMAT_HUMAN) {
printf("required size: %" PRIu64 "\n", info->required);
printf("fully allocated size: %" PRIu64 "\n", info->fully_allocated);
} else {
dump_json_block_measure_info(info);
}
ret = 0;
out:
qapi_free_BlockMeasureInfo(info);
qemu_opts_del(object_opts);
qemu_opts_del(opts);
qemu_opts_del(sn_opts);
qemu_opts_free(create_opts);
g_free(options);
blk_unref(in_blk);
return ret;
}
static const img_cmd_t img_cmds[] = {
#define DEF(option, callback, arg_string) \

View File

@ -438,6 +438,36 @@ preallocated.
For more information, consult @file{include/block/block.h} in QEMU's
source code.
@item measure [--output=@var{ofmt}] [-O @var{output_fmt}] [-o @var{options}] [--size @var{N} | [--object @var{objectdef}] [--image-opts] [-f @var{fmt}] [-l @var{snapshot_param}] @var{filename}]
Calculate the file size required for a new image. This information can be used
to size logical volumes or SAN LUNs appropriately for the image that will be
placed in them. The values reported are guaranteed to be large enough to fit
the image. The command can output in the format @var{ofmt} which is either
@code{human} or @code{json}.
If the size @var{N} is given then act as if creating a new empty image file
using @command{qemu-img create}. If @var{filename} is given then act as if
converting an existing image file using @command{qemu-img convert}. The format
of the new file is given by @var{output_fmt} while the format of an existing
file is given by @var{fmt}.
A snapshot in an existing image can be specified using @var{snapshot_param}.
The following fields are reported:
@example
required size: 524288
fully allocated size: 1074069504
@end example
The @code{required size} is the file size of the new image. It may be smaller
than the virtual disk size if the image format supports compact representation.
The @code{fully allocated size} is the file size of the new image once data has
been written to all sectors. This is the maximum size that the image file can
occupy with the exception of internal snapshots, dirty bitmaps, vmstate data,
and other advanced image format features.
@item snapshot [-l | -a @var{snapshot} | -c @var{snapshot} | -d @var{snapshot} ] @var{filename}
List, apply, create or delete snapshots in image @var{filename}.
@ -499,7 +529,7 @@ qemu-img rebase -b base.img diff.qcow2
At this point, @code{modified.img} can be discarded, since
@code{base.img + diff.qcow2} contains the same information.
@item resize @var{filename} [+ | -]@var{size}
@item resize [--preallocation=@var{prealloc}] @var{filename} [+ | -]@var{size}
Change the disk image as if it had been created with @var{size}.
@ -511,6 +541,11 @@ After using this command to grow a disk image, you must use file system and
partitioning tools inside the VM to actually begin using the new space on the
device.
When growing an image, the @code{--preallocation} option may be used to specify
how the additional image area should be allocated on the host. See the format
description in the @code{NOTES} section which values are allowed. Using this
option may result in slightly more data being allocated than necessary.
@item amend [-p] [-f @var{fmt}] [-t @var{cache}] -o @var{options} @var{filename}
Amends the image format specific @var{options} for the image file
@ -567,16 +602,29 @@ The use of encryption in qcow and qcow2 images is considered to be flawed by
modern cryptography standards, suffering from a number of design problems:
@itemize @minus
@item The AES-CBC cipher is used with predictable initialization vectors based
@item
The AES-CBC cipher is used with predictable initialization vectors based
on the sector number. This makes it vulnerable to chosen plaintext attacks
which can reveal the existence of encrypted data.
@item The user passphrase is directly used as the encryption key. A poorly
@item
The user passphrase is directly used as the encryption key. A poorly
chosen or short passphrase will compromise the security of the encryption.
@item In the event of the passphrase being compromised there is no way to
@item
In the event of the passphrase being compromised there is no way to
change the passphrase to protect data in any qcow images. The files must
be cloned, using a different encryption passphrase in the new file. The
original file must then be securely erased using a program like shred,
though even this is ineffective with many modern storage technologies.
@item
Initialization vectors used to encrypt sectors are based on the
guest virtual sector number, instead of the host physical sector. When
a disk image has multiple internal snapshots this means that data in
multiple physical sectors is encrypted with the same initialization
vector. With the CBC mode, this opens the possibility of watermarking
attacks if the attack can collect multiple sectors encrypted with the
same IV and some predictable data. Having multiple qcow2 images with
the same passphrase also exposes this weakness since the passphrase
is directly used as the key.
@end itemize
Use of qcow / qcow2 encryption is thus strongly discouraged. Users are

View File

@ -1577,7 +1577,7 @@ static int truncate_f(BlockBackend *blk, int argc, char **argv)
return 0;
}
ret = blk_truncate(blk, offset, &local_err);
ret = blk_truncate(blk, offset, PREALLOC_MODE_OFF, &local_err);
if (ret < 0) {
error_report_err(local_err);
return 0;

View File

@ -58,7 +58,6 @@ static int openfile(char *name, int flags, bool writethrough, bool force_share,
QDict *opts)
{
Error *local_err = NULL;
BlockDriverState *bs;
if (qemuio_blk) {
error_report("file open already, try 'help close'");
@ -85,28 +84,9 @@ static int openfile(char *name, int flags, bool writethrough, bool force_share,
return 1;
}
bs = blk_bs(qemuio_blk);
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) {
error_report("No password given");
goto error;
}
if (bdrv_set_key(bs, password) < 0) {
error_report("invalid password");
goto error;
}
}
blk_set_enable_write_cache(qemuio_blk, !writethrough);
return 0;
error:
blk_unref(qemuio_blk);
qemuio_blk = NULL;
return 1;
}
static void open_help(void)

View File

@ -4374,7 +4374,7 @@ The simplest (insecure) usage is to provide the secret inline
The simplest secure usage is to provide the secret via a file
# echo -n "letmein" > mypasswd.txt
# printf "letmein" > mypasswd.txt
# $QEMU -object secret,id=sec0,file=mypasswd.txt,format=raw
For greater security, AES-256-CBC should be used. To illustrate usage,
@ -4402,7 +4402,7 @@ telling openssl to base64 encode the result, but it could be left
as raw bytes if desired.
@example
# SECRET=$(echo -n "letmein" |
# SECRET=$(printf "letmein" |
openssl enc -aes-256-cbc -a -K $KEY -iv $IV)
@end example

12
qmp.c
View File

@ -164,10 +164,8 @@ SpiceInfo *qmp_query_spice(Error **errp)
void qmp_cont(Error **errp)
{
Error *local_err = NULL;
BlockBackend *blk;
BlockDriverState *bs;
BdrvNextIterator it;
Error *local_err = NULL;
/* if there is a dump in background, we should wait until the dump
* finished */
@ -187,14 +185,6 @@ void qmp_cont(Error **errp)
blk_iostatus_reset(blk);
}
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
bdrv_add_key(bs, NULL, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
}
/* Continuing after completed migration. Images have been inactivated to
* allow the destination to take control. Need to get control back now.
*

View File

@ -554,7 +554,7 @@ tests/test-blockjob$(EXESUF): tests/test-blockjob.o $(test-block-obj-y) $(test-u
tests/test-blockjob-txn$(EXESUF): tests/test-blockjob-txn.o $(test-block-obj-y) $(test-util-obj-y)
tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(test-block-obj-y)
tests/test-iov$(EXESUF): tests/test-iov.o $(test-util-obj-y)
tests/test-hbitmap$(EXESUF): tests/test-hbitmap.o $(test-util-obj-y)
tests/test-hbitmap$(EXESUF): tests/test-hbitmap.o $(test-util-obj-y) $(test-crypto-obj-y)
tests/test-x86-cpuid$(EXESUF): tests/test-x86-cpuid.o
tests/test-xbzrle$(EXESUF): tests/test-xbzrle.o migration/xbzrle.o migration/page_cache.o $(test-util-obj-y)
tests/test-cutils$(EXESUF): tests/test-cutils.o util/cutils.o

View File

@ -26,7 +26,7 @@ run_qemu() {
local kernel=$1
shift
echo -e "\n\n=== Running test case: $kernel $@ ===\n" >> test.log
printf %b "\n\n=== Running test case: $kernel $@ ===\n\n" >> test.log
$QEMU \
-kernel $kernel \
@ -68,21 +68,21 @@ for t in mmap modules; do
pass=1
if [ $debugexit != 1 ]; then
echo -e "\e[31m ?? \e[0m $t (no debugexit used, exit code $ret)"
printf %b "\e[31m ?? \e[0m $t (no debugexit used, exit code $ret)\n"
pass=0
elif [ $ret != 0 ]; then
echo -e "\e[31mFAIL\e[0m $t (exit code $ret)"
printf %b "\e[31mFAIL\e[0m $t (exit code $ret)\n"
pass=0
fi
if ! diff $t.out test.log > /dev/null 2>&1; then
echo -e "\e[31mFAIL\e[0m $t (output difference)"
printf %b "\e[31mFAIL\e[0m $t (output difference)\n"
diff -u $t.out test.log
pass=0
fi
if [ $pass == 1 ]; then
echo -e "\e[32mPASS\e[0m $t"
printf %b "\e[32mPASS\e[0m $t\n"
fi
done

View File

@ -50,10 +50,18 @@ do_test()
local align=$1
local iocmd=$2
local img=$3
if [ "$IMGOPTSSYNTAX" = "true" ]
then
IO_OPEN_ARG="$img"
IO_EXTRA_ARGS="--image-opts"
else
IO_OPEN_ARG="-o driver=$IMGFMT,file.align=$align blkdebug::$img"
IO_EXTRA_ARGS=""
fi
{
echo "open -o driver=$IMGFMT,file.align=$align blkdebug::$img"
echo "open $IO_OPEN_ARG"
echo $iocmd
} | $QEMU_IO
} | $QEMU_IO $IO_EXTRA_ARGS
}
for write_zero_cmd in "write -z" "aio_write -z"; do

View File

@ -37,7 +37,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
. ./common.rc
. ./common.filter
_supported_fmt qcow2 qcow qed
_supported_fmt qcow2 qed
_supported_proto file
_supported_os Linux

View File

@ -1,6 +1,6 @@
No errors were found on the image.
7292415/33554432 = 21.73% allocated, 0.00% fragmented, 0.00% compressed clusters
Image end offset: 4296152064
Image end offset: 4296217088
.
----------------------------------------------------------------------
Ran 1 tests

View File

@ -46,7 +46,7 @@ _compare()
. ./common.filter
. ./common.pattern
_supported_fmt raw qcow qcow2 qed luks
_supported_fmt raw qcow2 qed luks
_supported_proto file
_supported_os Linux

View File

@ -106,7 +106,7 @@ test_qemu_img create -f $IMGFMT -o preallocation=1234 "$TEST_IMG" 64M
echo "== Check encryption option =="
echo
test_qemu_img create -f $IMGFMT -o encryption=off "$TEST_IMG" 64M
test_qemu_img create -f $IMGFMT -o encryption=on "$TEST_IMG" 64M
test_qemu_img create -f $IMGFMT --object secret,id=sec0,data=123456 -o encryption=on,encrypt.key-secret=sec0 "$TEST_IMG" 64M
echo "== Check lazy_refcounts option (only with v3) =="
echo

View File

@ -4,90 +4,90 @@ QA output created by 049
== 1. Traditional size parameter ==
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024b
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1k
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1K
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1M
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1048576 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1048576 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1G
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1073741824 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1073741824 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1T
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1099511627776 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1099511627776 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024.0
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024.0b
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5k
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5K
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5M
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1572864 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1572864 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5G
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1610612736 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1610612736 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5T
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1649267441664 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1649267441664 cluster_size=65536 lazy_refcounts=off refcount_bits=16
== 2. Specifying size via -o ==
qemu-img create -f qcow2 -o size=1024 TEST_DIR/t.qcow2
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1024b TEST_DIR/t.qcow2
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1k TEST_DIR/t.qcow2
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1K TEST_DIR/t.qcow2
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1M TEST_DIR/t.qcow2
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1048576 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1048576 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1G TEST_DIR/t.qcow2
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1073741824 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1073741824 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1T TEST_DIR/t.qcow2
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1099511627776 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1099511627776 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1024.0 TEST_DIR/t.qcow2
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1024.0b TEST_DIR/t.qcow2
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1.5k TEST_DIR/t.qcow2
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1.5K TEST_DIR/t.qcow2
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1.5M TEST_DIR/t.qcow2
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1572864 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1572864 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1.5G TEST_DIR/t.qcow2
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1610612736 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1610612736 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1.5T TEST_DIR/t.qcow2
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1649267441664 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1649267441664 cluster_size=65536 lazy_refcounts=off refcount_bits=16
== 3. Invalid sizes ==
@ -128,84 +128,84 @@ qemu-img: TEST_DIR/t.qcow2: Invalid options for file format 'qcow2'
== Check correct interpretation of suffixes for cluster size ==
qemu-img create -f qcow2 -o cluster_size=1024 TEST_DIR/t.qcow2 64M
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o cluster_size=1024b TEST_DIR/t.qcow2 64M
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o cluster_size=1k TEST_DIR/t.qcow2 64M
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o cluster_size=1K TEST_DIR/t.qcow2 64M
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o cluster_size=1M TEST_DIR/t.qcow2 64M
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1048576 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1048576 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o cluster_size=1024.0 TEST_DIR/t.qcow2 64M
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o cluster_size=1024.0b TEST_DIR/t.qcow2 64M
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o cluster_size=0.5k TEST_DIR/t.qcow2 64M
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=512 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=512 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o cluster_size=0.5K TEST_DIR/t.qcow2 64M
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=512 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=512 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o cluster_size=0.5M TEST_DIR/t.qcow2 64M
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=524288 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=524288 lazy_refcounts=off refcount_bits=16
== Check compat level option ==
qemu-img create -f qcow2 -o compat=0.10 TEST_DIR/t.qcow2 64M
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o compat=1.1 TEST_DIR/t.qcow2 64M
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=1.1 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=1.1 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o compat=0.42 TEST_DIR/t.qcow2 64M
qemu-img: TEST_DIR/t.qcow2: Invalid compatibility level: '0.42'
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.42 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.42 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o compat=foobar TEST_DIR/t.qcow2 64M
qemu-img: TEST_DIR/t.qcow2: Invalid compatibility level: 'foobar'
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=foobar encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=foobar cluster_size=65536 lazy_refcounts=off refcount_bits=16
== Check preallocation option ==
qemu-img create -f qcow2 -o preallocation=off TEST_DIR/t.qcow2 64M
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 preallocation=off lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=65536 preallocation=off lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o preallocation=metadata TEST_DIR/t.qcow2 64M
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 preallocation=metadata lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=65536 preallocation=metadata lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o preallocation=1234 TEST_DIR/t.qcow2 64M
qemu-img: TEST_DIR/t.qcow2: invalid parameter value: 1234
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 preallocation=1234 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=65536 preallocation=1234 lazy_refcounts=off refcount_bits=16
== Check encryption option ==
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
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=on cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 --object secret,id=sec0,data=123456 -o encryption=on,encrypt.key-secret=sec0 TEST_DIR/t.qcow2 64M
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=on encrypt.key-secret=sec0 cluster_size=65536 lazy_refcounts=off refcount_bits=16
== Check lazy_refcounts option (only with v3) ==
qemu-img create -f qcow2 -o compat=1.1,lazy_refcounts=off TEST_DIR/t.qcow2 64M
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=1.1 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=1.1 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o compat=1.1,lazy_refcounts=on TEST_DIR/t.qcow2 64M
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=1.1 encryption=off cluster_size=65536 lazy_refcounts=on refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=1.1 cluster_size=65536 lazy_refcounts=on refcount_bits=16
qemu-img create -f qcow2 -o compat=0.10,lazy_refcounts=off TEST_DIR/t.qcow2 64M
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o compat=0.10,lazy_refcounts=on TEST_DIR/t.qcow2 64M
qemu-img: TEST_DIR/t.qcow2: Lazy refcounts only supported with compatibility level 1.1 and above (use compat=1.1 or greater)
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 encryption=off cluster_size=65536 lazy_refcounts=on refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 cluster_size=65536 lazy_refcounts=on refcount_bits=16
*** done

View File

@ -217,7 +217,7 @@ run_qemu -drive driver=null-co,cache=invalid_value
# Test 142 checks the direct=on cases
for cache in writeback writethrough unsafe invalid_value; do
echo -e "info block\ninfo block file\ninfo block backing\ninfo block backing-file" | \
printf "info block %s\n" '' file backing backing-file | \
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
@ -325,8 +325,9 @@ echo "qemu-io $device_id \"write -P 0x22 0 4k\"" | run_qemu -drive file="$TEST_I
$QEMU_IO -c "read -P 0x22 0 4k" "$TEST_IMG" | _filter_qemu_io
echo -e "qemu-io $device_id \"write -P 0x33 0 4k\"\ncommit $device_id" | run_qemu -drive file="$TEST_IMG",snapshot=on,if=none,id=$device_id\
| _filter_qemu_io
printf %b "qemu-io $device_id \"write -P 0x33 0 4k\"\ncommit $device_id\n" |
run_qemu -drive file="$TEST_IMG",snapshot=on,if=none,id=$device_id |
_filter_qemu_io
$QEMU_IO -c "read -P 0x33 0 4k" "$TEST_IMG" | _filter_qemu_io

View File

@ -76,7 +76,7 @@ for extra_args in \
_make_test_img $IMG_SIZE
# Give qemu some time to boot before saving the VM state
bash -c 'sleep 1; echo -e "savevm 0\nquit"' | _qemu $extra_args
{ sleep 1; printf "savevm 0\nquit\n"; } | _qemu $extra_args
# Now try to continue from that VM state (this should just work)
echo quit | _qemu $extra_args -loadvm 0
done

View File

@ -3,14 +3,14 @@ QA output created by 082
=== create: Options specified more than once ===
Testing: create -f foo -f qcow2 TEST_DIR/t.qcow2 128M
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16
image: TEST_DIR/t.IMGFMT
file format: IMGFMT
virtual size: 128M (134217728 bytes)
cluster_size: 65536
Testing: create -f qcow2 -o cluster_size=4k -o lazy_refcounts=on TEST_DIR/t.qcow2 128M
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 encryption=off cluster_size=4096 lazy_refcounts=on refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 cluster_size=4096 lazy_refcounts=on refcount_bits=16
image: TEST_DIR/t.IMGFMT
file format: IMGFMT
virtual size: 128M (134217728 bytes)
@ -22,7 +22,7 @@ Format specific information:
corrupt: false
Testing: create -f qcow2 -o cluster_size=4k -o lazy_refcounts=on -o cluster_size=8k TEST_DIR/t.qcow2 128M
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 encryption=off cluster_size=8192 lazy_refcounts=on refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 cluster_size=8192 lazy_refcounts=on refcount_bits=16
image: TEST_DIR/t.IMGFMT
file format: IMGFMT
virtual size: 128M (134217728 bytes)
@ -34,7 +34,7 @@ Format specific information:
corrupt: false
Testing: create -f qcow2 -o cluster_size=4k,cluster_size=8k TEST_DIR/t.qcow2 128M
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 encryption=off cluster_size=8192 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 cluster_size=8192 lazy_refcounts=off refcount_bits=16
image: TEST_DIR/t.IMGFMT
file format: IMGFMT
virtual size: 128M (134217728 bytes)
@ -48,7 +48,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
encryption Encrypt the image
encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
encrypt.format Encrypt the image, format choices: 'aes', 'luks'
encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
encrypt.cipher-alg Name of encryption cipher algorithm
encrypt.cipher-mode Name of encryption cipher mode
encrypt.ivgen-alg Name of IV generator algorithm
encrypt.ivgen-hash-alg Name of IV generator hash algorithm
encrypt.hash-alg Name of encryption hash algorithm
encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@ -61,7 +69,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
encryption Encrypt the image
encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
encrypt.format Encrypt the image, format choices: 'aes', 'luks'
encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
encrypt.cipher-alg Name of encryption cipher algorithm
encrypt.cipher-mode Name of encryption cipher mode
encrypt.ivgen-alg Name of IV generator algorithm
encrypt.ivgen-hash-alg Name of IV generator hash algorithm
encrypt.hash-alg Name of encryption hash algorithm
encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@ -74,7 +90,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
encryption Encrypt the image
encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
encrypt.format Encrypt the image, format choices: 'aes', 'luks'
encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
encrypt.cipher-alg Name of encryption cipher algorithm
encrypt.cipher-mode Name of encryption cipher mode
encrypt.ivgen-alg Name of IV generator algorithm
encrypt.ivgen-hash-alg Name of IV generator hash algorithm
encrypt.hash-alg Name of encryption hash algorithm
encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@ -87,7 +111,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
encryption Encrypt the image
encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
encrypt.format Encrypt the image, format choices: 'aes', 'luks'
encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
encrypt.cipher-alg Name of encryption cipher algorithm
encrypt.cipher-mode Name of encryption cipher mode
encrypt.ivgen-alg Name of IV generator algorithm
encrypt.ivgen-hash-alg Name of IV generator hash algorithm
encrypt.hash-alg Name of encryption hash algorithm
encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@ -100,7 +132,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
encryption Encrypt the image
encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
encrypt.format Encrypt the image, format choices: 'aes', 'luks'
encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
encrypt.cipher-alg Name of encryption cipher algorithm
encrypt.cipher-mode Name of encryption cipher mode
encrypt.ivgen-alg Name of IV generator algorithm
encrypt.ivgen-hash-alg Name of IV generator hash algorithm
encrypt.hash-alg Name of encryption hash algorithm
encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@ -113,7 +153,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
encryption Encrypt the image
encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
encrypt.format Encrypt the image, format choices: 'aes', 'luks'
encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
encrypt.cipher-alg Name of encryption cipher algorithm
encrypt.cipher-mode Name of encryption cipher mode
encrypt.ivgen-alg Name of IV generator algorithm
encrypt.ivgen-hash-alg Name of IV generator hash algorithm
encrypt.hash-alg Name of encryption hash algorithm
encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@ -126,7 +174,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
encryption Encrypt the image
encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
encrypt.format Encrypt the image, format choices: 'aes', 'luks'
encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
encrypt.cipher-alg Name of encryption cipher algorithm
encrypt.cipher-mode Name of encryption cipher mode
encrypt.ivgen-alg Name of IV generator algorithm
encrypt.ivgen-hash-alg Name of IV generator hash algorithm
encrypt.hash-alg Name of encryption hash algorithm
encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@ -139,7 +195,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
encryption Encrypt the image
encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
encrypt.format Encrypt the image, format choices: 'aes', 'luks'
encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
encrypt.cipher-alg Name of encryption cipher algorithm
encrypt.cipher-mode Name of encryption cipher mode
encrypt.ivgen-alg Name of IV generator algorithm
encrypt.ivgen-hash-alg Name of IV generator hash algorithm
encrypt.hash-alg Name of encryption hash algorithm
encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@ -147,10 +211,10 @@ refcount_bits Width of a reference count entry in bits
nocow Turn off copy-on-write (valid only on btrfs)
Testing: create -f qcow2 -o backing_file=TEST_DIR/t.qcow2,,help TEST_DIR/t.qcow2 128M
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2,,help encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2,,help cluster_size=65536 lazy_refcounts=off refcount_bits=16
Testing: create -f qcow2 -o backing_file=TEST_DIR/t.qcow2,,? TEST_DIR/t.qcow2 128M
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2,,? encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2,,? cluster_size=65536 lazy_refcounts=off refcount_bits=16
Testing: create -f qcow2 -o backing_file=TEST_DIR/t.qcow2, -o help TEST_DIR/t.qcow2 128M
qemu-img: Invalid option list: backing_file=TEST_DIR/t.qcow2,
@ -167,7 +231,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
encryption Encrypt the image
encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
encrypt.format Encrypt the image, format choices: 'aes', 'luks'
encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
encrypt.cipher-alg Name of encryption cipher algorithm
encrypt.cipher-mode Name of encryption cipher mode
encrypt.ivgen-alg Name of IV generator algorithm
encrypt.ivgen-hash-alg Name of IV generator hash algorithm
encrypt.hash-alg Name of encryption hash algorithm
encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@ -180,7 +252,7 @@ size Virtual disk size
=== convert: Options specified more than once ===
Testing: create -f qcow2 TEST_DIR/t.qcow2 128M
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16
Testing: convert -f foo -f qcow2 TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
image: TEST_DIR/t.IMGFMT.base
@ -229,7 +301,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
encryption Encrypt the image
encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
encrypt.format Encrypt the image, format choices: 'aes', 'luks'
encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
encrypt.cipher-alg Name of encryption cipher algorithm
encrypt.cipher-mode Name of encryption cipher mode
encrypt.ivgen-alg Name of IV generator algorithm
encrypt.ivgen-hash-alg Name of IV generator hash algorithm
encrypt.hash-alg Name of encryption hash algorithm
encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@ -242,7 +322,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
encryption Encrypt the image
encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
encrypt.format Encrypt the image, format choices: 'aes', 'luks'
encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
encrypt.cipher-alg Name of encryption cipher algorithm
encrypt.cipher-mode Name of encryption cipher mode
encrypt.ivgen-alg Name of IV generator algorithm
encrypt.ivgen-hash-alg Name of IV generator hash algorithm
encrypt.hash-alg Name of encryption hash algorithm
encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@ -255,7 +343,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
encryption Encrypt the image
encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
encrypt.format Encrypt the image, format choices: 'aes', 'luks'
encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
encrypt.cipher-alg Name of encryption cipher algorithm
encrypt.cipher-mode Name of encryption cipher mode
encrypt.ivgen-alg Name of IV generator algorithm
encrypt.ivgen-hash-alg Name of IV generator hash algorithm
encrypt.hash-alg Name of encryption hash algorithm
encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@ -268,7 +364,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
encryption Encrypt the image
encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
encrypt.format Encrypt the image, format choices: 'aes', 'luks'
encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
encrypt.cipher-alg Name of encryption cipher algorithm
encrypt.cipher-mode Name of encryption cipher mode
encrypt.ivgen-alg Name of IV generator algorithm
encrypt.ivgen-hash-alg Name of IV generator hash algorithm
encrypt.hash-alg Name of encryption hash algorithm
encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@ -281,7 +385,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
encryption Encrypt the image
encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
encrypt.format Encrypt the image, format choices: 'aes', 'luks'
encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
encrypt.cipher-alg Name of encryption cipher algorithm
encrypt.cipher-mode Name of encryption cipher mode
encrypt.ivgen-alg Name of IV generator algorithm
encrypt.ivgen-hash-alg Name of IV generator hash algorithm
encrypt.hash-alg Name of encryption hash algorithm
encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@ -294,7 +406,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
encryption Encrypt the image
encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
encrypt.format Encrypt the image, format choices: 'aes', 'luks'
encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
encrypt.cipher-alg Name of encryption cipher algorithm
encrypt.cipher-mode Name of encryption cipher mode
encrypt.ivgen-alg Name of IV generator algorithm
encrypt.ivgen-hash-alg Name of IV generator hash algorithm
encrypt.hash-alg Name of encryption hash algorithm
encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@ -307,7 +427,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
encryption Encrypt the image
encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
encrypt.format Encrypt the image, format choices: 'aes', 'luks'
encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
encrypt.cipher-alg Name of encryption cipher algorithm
encrypt.cipher-mode Name of encryption cipher mode
encrypt.ivgen-alg Name of IV generator algorithm
encrypt.ivgen-hash-alg Name of IV generator hash algorithm
encrypt.hash-alg Name of encryption hash algorithm
encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@ -320,7 +448,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
encryption Encrypt the image
encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
encrypt.format Encrypt the image, format choices: 'aes', 'luks'
encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
encrypt.cipher-alg Name of encryption cipher algorithm
encrypt.cipher-mode Name of encryption cipher mode
encrypt.ivgen-alg Name of IV generator algorithm
encrypt.ivgen-hash-alg Name of IV generator hash algorithm
encrypt.hash-alg Name of encryption hash algorithm
encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@ -348,7 +484,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
encryption Encrypt the image
encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
encrypt.format Encrypt the image, format choices: 'aes', 'luks'
encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
encrypt.cipher-alg Name of encryption cipher algorithm
encrypt.cipher-mode Name of encryption cipher mode
encrypt.ivgen-alg Name of IV generator algorithm
encrypt.ivgen-hash-alg Name of IV generator hash algorithm
encrypt.hash-alg Name of encryption hash algorithm
encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@ -407,7 +551,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
encryption Encrypt the image
encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
encrypt.format Encrypt the image, format choices: 'aes', 'luks'
encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
encrypt.cipher-alg Name of encryption cipher algorithm
encrypt.cipher-mode Name of encryption cipher mode
encrypt.ivgen-alg Name of IV generator algorithm
encrypt.ivgen-hash-alg Name of IV generator hash algorithm
encrypt.hash-alg Name of encryption hash algorithm
encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@ -420,7 +572,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
encryption Encrypt the image
encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
encrypt.format Encrypt the image, format choices: 'aes', 'luks'
encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
encrypt.cipher-alg Name of encryption cipher algorithm
encrypt.cipher-mode Name of encryption cipher mode
encrypt.ivgen-alg Name of IV generator algorithm
encrypt.ivgen-hash-alg Name of IV generator hash algorithm
encrypt.hash-alg Name of encryption hash algorithm
encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@ -433,7 +593,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
encryption Encrypt the image
encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
encrypt.format Encrypt the image, format choices: 'aes', 'luks'
encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
encrypt.cipher-alg Name of encryption cipher algorithm
encrypt.cipher-mode Name of encryption cipher mode
encrypt.ivgen-alg Name of IV generator algorithm
encrypt.ivgen-hash-alg Name of IV generator hash algorithm
encrypt.hash-alg Name of encryption hash algorithm
encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@ -446,7 +614,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
encryption Encrypt the image
encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
encrypt.format Encrypt the image, format choices: 'aes', 'luks'
encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
encrypt.cipher-alg Name of encryption cipher algorithm
encrypt.cipher-mode Name of encryption cipher mode
encrypt.ivgen-alg Name of IV generator algorithm
encrypt.ivgen-hash-alg Name of IV generator hash algorithm
encrypt.hash-alg Name of encryption hash algorithm
encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@ -459,7 +635,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
encryption Encrypt the image
encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
encrypt.format Encrypt the image, format choices: 'aes', 'luks'
encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
encrypt.cipher-alg Name of encryption cipher algorithm
encrypt.cipher-mode Name of encryption cipher mode
encrypt.ivgen-alg Name of IV generator algorithm
encrypt.ivgen-hash-alg Name of IV generator hash algorithm
encrypt.hash-alg Name of encryption hash algorithm
encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@ -472,7 +656,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
encryption Encrypt the image
encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
encrypt.format Encrypt the image, format choices: 'aes', 'luks'
encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
encrypt.cipher-alg Name of encryption cipher algorithm
encrypt.cipher-mode Name of encryption cipher mode
encrypt.ivgen-alg Name of IV generator algorithm
encrypt.ivgen-hash-alg Name of IV generator hash algorithm
encrypt.hash-alg Name of encryption hash algorithm
encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@ -485,7 +677,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
encryption Encrypt the image
encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
encrypt.format Encrypt the image, format choices: 'aes', 'luks'
encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
encrypt.cipher-alg Name of encryption cipher algorithm
encrypt.cipher-mode Name of encryption cipher mode
encrypt.ivgen-alg Name of IV generator algorithm
encrypt.ivgen-hash-alg Name of IV generator hash algorithm
encrypt.hash-alg Name of encryption hash algorithm
encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@ -498,7 +698,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
encryption Encrypt the image
encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
encrypt.format Encrypt the image, format choices: 'aes', 'luks'
encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
encrypt.cipher-alg Name of encryption cipher algorithm
encrypt.cipher-mode Name of encryption cipher mode
encrypt.ivgen-alg Name of IV generator algorithm
encrypt.ivgen-hash-alg Name of IV generator hash algorithm
encrypt.hash-alg Name of encryption hash algorithm
encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@ -528,7 +736,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
encryption Encrypt the image
encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
encrypt.format Encrypt the image, format choices: 'aes', 'luks'
encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
encrypt.cipher-alg Name of encryption cipher algorithm
encrypt.cipher-mode Name of encryption cipher mode
encrypt.ivgen-alg Name of IV generator algorithm
encrypt.ivgen-hash-alg Name of IV generator hash algorithm
encrypt.hash-alg Name of encryption hash algorithm
encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates

View File

@ -11,7 +11,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
=== Create a single snapshot on virtio0 ===
Formatting 'TEST_DIR/1-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2.1 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/1-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2.1 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
=== Invalid command - missing device and nodename ===
@ -25,32 +25,32 @@ Formatting 'TEST_DIR/1-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file
=== Create several transactional group snapshots ===
Formatting 'TEST_DIR/2-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/1-snapshot-v0.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/2-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2.2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/2-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/1-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/2-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2.2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
Formatting 'TEST_DIR/3-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/2-snapshot-v0.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/3-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/2-snapshot-v1.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/3-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/2-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/3-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/2-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
Formatting 'TEST_DIR/4-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/3-snapshot-v0.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/4-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/3-snapshot-v1.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/4-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/3-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/4-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/3-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
Formatting 'TEST_DIR/5-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/4-snapshot-v0.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/5-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/4-snapshot-v1.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/5-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/4-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/5-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/4-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
Formatting 'TEST_DIR/6-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/5-snapshot-v0.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/6-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/5-snapshot-v1.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/6-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/5-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/6-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/5-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
Formatting 'TEST_DIR/7-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/6-snapshot-v0.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/7-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/6-snapshot-v1.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/7-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/6-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/7-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/6-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
Formatting 'TEST_DIR/8-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/7-snapshot-v0.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/8-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/7-snapshot-v1.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/8-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/7-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/8-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/7-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
Formatting 'TEST_DIR/9-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/8-snapshot-v0.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/9-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/8-snapshot-v1.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/9-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/8-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/9-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/8-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
Formatting 'TEST_DIR/10-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/9-snapshot-v0.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/10-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/9-snapshot-v1.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/10-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/9-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/10-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/9-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
=== Create a couple of snapshots using blockdev-snapshot ===

View File

@ -119,12 +119,21 @@ run_qemu <<EOF
EOF
echo
echo === Encrypted image ===
echo === Encrypted image QCow ===
echo
_make_test_img -o encryption=on $size
run_qemu -S <<EOF
_make_test_img --object secret,id=sec0,data=123456 -o encryption=on,encrypt.key-secret=sec0 $size
run_qemu <<EOF
{ "execute": "qmp_capabilities" }
{ "execute": "object-add",
"arguments": {
"qom-type": "secret",
"id": "sec0",
"props": {
"data": "123456"
}
}
}
{ "execute": "blockdev-add",
"arguments": {
"driver": "$IMGFMT",
@ -132,14 +141,32 @@ run_qemu -S <<EOF
"file": {
"driver": "file",
"filename": "$TEST_IMG"
},
"encrypt": {
"format": "aes",
"key-secret": "sec0"
}
}
}
{ "execute": "quit" }
EOF
echo
echo === Encrypted image LUKS ===
echo
_make_test_img --object secret,id=sec0,data=123456 -o encrypt.format=luks,encrypt.key-secret=sec0 $size
run_qemu <<EOF
{ "execute": "qmp_capabilities" }
{ "execute": "object-add",
"arguments": {
"qom-type": "secret",
"id": "sec0",
"props": {
"data": "123456"
}
}
}
{ "execute": "blockdev-add",
"arguments": {
"driver": "$IMGFMT",
@ -147,6 +174,10 @@ run_qemu <<EOF
"file": {
"driver": "file",
"filename": "$TEST_IMG"
},
"encrypt": {
"format": "luks",
"key-secret": "sec0"
}
}
}
@ -157,7 +188,7 @@ echo
echo === Missing driver ===
echo
_make_test_img -o encryption=on $size
_make_test_img --object secret,id=sec0,data=123456 -o encryption=on,encrypt.key-secret=sec0 $size
run_qemu -S <<EOF
{ "execute": "qmp_capabilities" }
{ "execute": "blockdev-add",

View File

@ -32,27 +32,33 @@ QMP_VERSION
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
=== Encrypted image ===
=== Encrypted image QCow ===
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on
Testing: -S
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on encrypt.key-secret=sec0
Testing:
QMP_VERSION
{"return": {}}
{"return": {}}
{"error": {"class": "GenericError", "desc": "Use of AES-CBC encrypted IMGFMT images is no longer supported in system emulators"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
=== Encrypted image LUKS ===
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encrypt.format=luks encrypt.key-secret=sec0
Testing:
QMP_VERSION
{"return": {}}
{"error": {"class": "GenericError", "desc": "Use of AES-CBC encrypted IMGFMT images is no longer supported in system emulators"}}
{"return": {}}
{"return": {}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
=== Missing driver ===
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on encrypt.key-secret=sec0
Testing: -S
QMP_VERSION
{"return": {}}

92
tests/qemu-iotests/106 Executable file
View File

@ -0,0 +1,92 @@
#!/bin/bash
#
# Test preallocated resize of raw images
#
# Copyright (C) 2017 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
status=1 # failure is the default!
_cleanup()
{
_cleanup_test_img
}
trap "_cleanup; exit \$status" 0 1 2 3 15
# get standard environment and filters
. ./common.rc
. ./common.filter
_supported_fmt raw
_supported_proto file
_supported_os Linux
# in kB
CREATION_SIZE=128
GROWTH_SIZE=256
echo '=== Testing image growth ==='
for create_mode in off falloc full; do
for growth_mode in off falloc full; do
echo
echo "--- create_mode=$create_mode growth_mode=$growth_mode ---"
IMGOPTS="preallocation=$create_mode" _make_test_img ${CREATION_SIZE}K
$QEMU_IMG resize -f "$IMGFMT" --preallocation=$growth_mode "$TEST_IMG" +${GROWTH_SIZE}K
expected_size=0
if [ $create_mode != off ]; then
expected_size=$CREATION_SIZE
fi
if [ $growth_mode != off ]; then
expected_size=$((expected_size + $GROWTH_SIZE))
fi
actual_size=$($QEMU_IMG info -f "$IMGFMT" "$TEST_IMG" | grep 'disk size')
actual_size=$(echo "$actual_size" | sed -e 's/^[^0-9]*\([0-9]\+\).*$/\1/')
# The actual size may exceed the expected size, depending on the file
# system. Therefore we just test that the actual size is at least what
# we expect.
if [ $actual_size -lt $expected_size ]; then
echo "ERROR: Image should have at least ${expected_size}K, but has ${actual_size}K"
fi
done
done
echo
echo '=== Testing image shrinking ==='
# None of this should work except for "off", because other modes cannot be used
# for shrinking
for growth_mode in falloc full off; do
echo
echo "--- growth_mode=$growth_mode ---"
$QEMU_IMG resize -f "$IMGFMT" --preallocation=$growth_mode "$TEST_IMG" -${GROWTH_SIZE}K
done
# success, all done
echo '*** done'
rm -f $seq.full
status=0

View File

@ -0,0 +1,50 @@
QA output created by 106
=== Testing image growth ===
--- create_mode=off growth_mode=off ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 preallocation=off
Image resized.
--- create_mode=off growth_mode=falloc ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 preallocation=off
Image resized.
--- create_mode=off growth_mode=full ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 preallocation=off
Image resized.
--- create_mode=falloc growth_mode=off ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 preallocation=falloc
Image resized.
--- create_mode=falloc growth_mode=falloc ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 preallocation=falloc
Image resized.
--- create_mode=falloc growth_mode=full ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 preallocation=falloc
Image resized.
--- create_mode=full growth_mode=off ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 preallocation=full
Image resized.
--- create_mode=full growth_mode=falloc ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 preallocation=full
Image resized.
--- create_mode=full growth_mode=full ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 preallocation=full
Image resized.
=== Testing image shrinking ===
--- growth_mode=falloc ---
qemu-img: Preallocation can only be used for growing images
--- growth_mode=full ---
qemu-img: Preallocation can only be used for growing images
--- growth_mode=off ---
Image resized.
*** done

View File

@ -41,6 +41,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt generic
_supported_proto file
_supported_os Linux
_unsupported_fmt luks
_make_test_img 64M

130
tests/qemu-iotests/125 Executable file
View File

@ -0,0 +1,130 @@
#!/bin/bash
#
# Test preallocated growth of qcow2 images
#
# Copyright (C) 2017 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
status=1 # failure is the default!
_cleanup()
{
_cleanup_test_img
}
trap "_cleanup; exit \$status" 0 1 2 3 15
get_image_size_on_host()
{
$QEMU_IMG info -f "$IMGFMT" "$TEST_IMG" | grep "disk size" \
| sed -e 's/^[^0-9]*\([0-9]\+\).*$/\1/'
}
# get standard environment and filters
. ./common.rc
. ./common.filter
_supported_fmt qcow2
_supported_proto file
_supported_os Linux
if [ -z "$TEST_IMG_FILE" ]; then
TEST_IMG_FILE=$TEST_IMG
fi
# Generally, we create some image with or without existing preallocation and
# then resize it. Then we write some data into the image and verify that its
# size does not change if we have used preallocation.
# With a cluster size of 512 B, one L2 table covers 64 * 512 B = 32 kB.
# One cluster of the L1 table covers 64 * 32 kB = 2 MB.
# There are multiple cases we want to test:
# (1) Grow an image without having to allocate a new L2 table.
# (2) Grow an image, having to allocate a new L2 table.
# (3) Grow an image, having to grow the L1 table.
# Therefore, we create an image that is 48 kB below 2 MB. Then:
# (1) We resize it to 2 MB - 32 kB. (+ 16 kB)
# (2) We resize it to 2 MB. (+ 48 kB)
# (3) We resize it to 2 MB + 32 kB. (+ 80 kB)
# in B
CREATION_SIZE=$((2 * 1024 * 1024 - 48 * 1024))
# in kB
for GROWTH_SIZE in 16 48 80; do
for create_mode in off metadata falloc full; do
for growth_mode in off metadata falloc full; do
echo "--- growth_size=$GROWTH_SIZE create_mode=$create_mode growth_mode=$growth_mode ---"
IMGOPTS="preallocation=$create_mode,cluster_size=512" _make_test_img ${CREATION_SIZE}
$QEMU_IMG resize -f "$IMGFMT" --preallocation=$growth_mode "$TEST_IMG" +${GROWTH_SIZE}K
host_size_0=$(get_image_size_on_host)
file_length_0=$(stat -c '%s' "$TEST_IMG_FILE")
$QEMU_IO -c "write 0 $CREATION_SIZE" "$TEST_IMG" | _filter_qemu_io
host_size_1=$(get_image_size_on_host)
file_length_1=$(stat -c '%s' "$TEST_IMG_FILE")
$QEMU_IO -c "write $CREATION_SIZE ${GROWTH_SIZE}K" "$TEST_IMG" | _filter_qemu_io
host_size_2=$(get_image_size_on_host)
file_length_2=$(stat -c '%s' "$TEST_IMG_FILE")
# Test creation preallocation: Compare #0 against #1
if [ $create_mode != off ]; then
# The image length should not have grown
if [ $file_length_1 -gt $file_length_0 ]; then
echo "ERROR (create): Image length has grown from $file_length_0 to $file_length_1"
fi
if [ $create_mode != metadata ]; then
# The host size should not have grown either
if [ $host_size_1 -gt $host_size_0 ]; then
echo "ERROR (create): Host size has grown from $host_size_0 to $host_size_1"
fi
fi
fi
# Test resize preallocation: Compare #2 against #1
if [ $growth_mode != off ]; then
# The image length should not have grown
if [ $file_length_2 -gt $file_length_1 ]; then
echo "ERROR (grow): Image length has grown from $file_length_1 to $file_length_2"
fi
if [ $create_mode != metadata ]; then
# The host size should not have grown either
if [ $host_size_2 -gt $host_size_1 ]; then
echo "ERROR (grow): Host size has grown from $host_size_1 to $host_size_2"
fi
fi
fi
echo
done
done
done
# success, all done
echo '*** done'
rm -f $seq.full
status=0

386
tests/qemu-iotests/125.out Normal file
View File

@ -0,0 +1,386 @@
QA output created by 125
--- growth_size=16 create_mode=off growth_mode=off ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 16384/16384 bytes at offset 2048000
16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=16 create_mode=off growth_mode=metadata ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 16384/16384 bytes at offset 2048000
16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=16 create_mode=off growth_mode=falloc ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 16384/16384 bytes at offset 2048000
16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=16 create_mode=off growth_mode=full ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 16384/16384 bytes at offset 2048000
16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=16 create_mode=metadata growth_mode=off ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 16384/16384 bytes at offset 2048000
16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=16 create_mode=metadata growth_mode=metadata ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 16384/16384 bytes at offset 2048000
16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=16 create_mode=metadata growth_mode=falloc ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 16384/16384 bytes at offset 2048000
16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=16 create_mode=metadata growth_mode=full ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 16384/16384 bytes at offset 2048000
16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=16 create_mode=falloc growth_mode=off ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 16384/16384 bytes at offset 2048000
16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=16 create_mode=falloc growth_mode=metadata ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 16384/16384 bytes at offset 2048000
16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=16 create_mode=falloc growth_mode=falloc ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 16384/16384 bytes at offset 2048000
16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=16 create_mode=falloc growth_mode=full ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 16384/16384 bytes at offset 2048000
16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=16 create_mode=full growth_mode=off ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 16384/16384 bytes at offset 2048000
16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=16 create_mode=full growth_mode=metadata ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 16384/16384 bytes at offset 2048000
16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=16 create_mode=full growth_mode=falloc ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 16384/16384 bytes at offset 2048000
16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=16 create_mode=full growth_mode=full ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 16384/16384 bytes at offset 2048000
16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=48 create_mode=off growth_mode=off ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 49152/49152 bytes at offset 2048000
48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=48 create_mode=off growth_mode=metadata ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 49152/49152 bytes at offset 2048000
48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=48 create_mode=off growth_mode=falloc ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 49152/49152 bytes at offset 2048000
48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=48 create_mode=off growth_mode=full ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 49152/49152 bytes at offset 2048000
48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=48 create_mode=metadata growth_mode=off ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 49152/49152 bytes at offset 2048000
48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=48 create_mode=metadata growth_mode=metadata ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 49152/49152 bytes at offset 2048000
48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=48 create_mode=metadata growth_mode=falloc ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 49152/49152 bytes at offset 2048000
48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=48 create_mode=metadata growth_mode=full ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 49152/49152 bytes at offset 2048000
48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=48 create_mode=falloc growth_mode=off ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 49152/49152 bytes at offset 2048000
48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=48 create_mode=falloc growth_mode=metadata ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 49152/49152 bytes at offset 2048000
48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=48 create_mode=falloc growth_mode=falloc ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 49152/49152 bytes at offset 2048000
48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=48 create_mode=falloc growth_mode=full ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 49152/49152 bytes at offset 2048000
48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=48 create_mode=full growth_mode=off ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 49152/49152 bytes at offset 2048000
48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=48 create_mode=full growth_mode=metadata ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 49152/49152 bytes at offset 2048000
48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=48 create_mode=full growth_mode=falloc ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 49152/49152 bytes at offset 2048000
48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=48 create_mode=full growth_mode=full ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 49152/49152 bytes at offset 2048000
48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=80 create_mode=off growth_mode=off ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 81920/81920 bytes at offset 2048000
80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=80 create_mode=off growth_mode=metadata ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 81920/81920 bytes at offset 2048000
80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=80 create_mode=off growth_mode=falloc ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 81920/81920 bytes at offset 2048000
80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=80 create_mode=off growth_mode=full ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 81920/81920 bytes at offset 2048000
80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=80 create_mode=metadata growth_mode=off ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 81920/81920 bytes at offset 2048000
80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=80 create_mode=metadata growth_mode=metadata ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 81920/81920 bytes at offset 2048000
80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=80 create_mode=metadata growth_mode=falloc ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 81920/81920 bytes at offset 2048000
80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=80 create_mode=metadata growth_mode=full ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 81920/81920 bytes at offset 2048000
80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=80 create_mode=falloc growth_mode=off ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 81920/81920 bytes at offset 2048000
80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=80 create_mode=falloc growth_mode=metadata ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 81920/81920 bytes at offset 2048000
80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=80 create_mode=falloc growth_mode=falloc ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 81920/81920 bytes at offset 2048000
80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=80 create_mode=falloc growth_mode=full ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 81920/81920 bytes at offset 2048000
80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=80 create_mode=full growth_mode=off ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 81920/81920 bytes at offset 2048000
80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=80 create_mode=full growth_mode=metadata ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 81920/81920 bytes at offset 2048000
80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=80 create_mode=full growth_mode=falloc ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 81920/81920 bytes at offset 2048000
80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- growth_size=80 create_mode=full growth_mode=full ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
Image resized.
wrote 2048000/2048000 bytes at offset 0
1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 81920/81920 bytes at offset 2048000
80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
*** done

105
tests/qemu-iotests/126 Executable file
View File

@ -0,0 +1,105 @@
#!/bin/bash
#
# Tests handling of colons in filenames (which may be confused with protocol
# prefixes)
#
# Copyright (C) 2017 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"
status=1 # failure is the default!
# get standard environment, filters and checks
. ./common.rc
. ./common.filter
# Needs backing file support
_supported_fmt qcow qcow2 qed vmdk
# This is the default protocol (and we want to test the difference between
# colons which separate a protocol prefix from the rest and colons which are
# just part of the filename, so we cannot test protocols which require a prefix)
_supported_proto file
_supported_os Linux
echo
echo '=== Testing plain files ==='
echo
# A colon after a slash is not a protocol prefix separator
TEST_IMG="$TEST_DIR/a:b.$IMGFMT" _make_test_img 64M
_rm_test_img "$TEST_DIR/a:b.$IMGFMT"
# But if you want to be really sure, you can do this
TEST_IMG="file:$TEST_DIR/a:b.$IMGFMT" _make_test_img 64M
_rm_test_img "$TEST_DIR/a:b.$IMGFMT"
echo
echo '=== Testing relative backing filename resolution ==='
echo
BASE_IMG="$TEST_DIR/image:base.$IMGFMT"
TOP_IMG="$TEST_DIR/image:top.$IMGFMT"
TEST_IMG=$BASE_IMG _make_test_img 64M
TEST_IMG=$TOP_IMG _make_test_img -b ./image:base.$IMGFMT
# The default cluster size depends on the image format
TEST_IMG=$TOP_IMG _img_info | grep -v 'cluster_size'
_rm_test_img "$BASE_IMG"
_rm_test_img "$TOP_IMG"
# Do another test where we access both top and base without any slash in them
echo
pushd "$TEST_DIR" >/dev/null
BASE_IMG="base.$IMGFMT"
TOP_IMG="file:image:top.$IMGFMT"
TEST_IMG=$BASE_IMG _make_test_img 64M
TEST_IMG=$TOP_IMG _make_test_img -b "$BASE_IMG"
TEST_IMG=$TOP_IMG _img_info | grep -v 'cluster_size'
_rm_test_img "$BASE_IMG"
_rm_test_img "image:top.$IMGFMT"
popd >/dev/null
# Note that we could also do the same test with BASE_IMG=file:image:base.$IMGFMT
# -- but behavior for that case is a bit strange. Protocol-prefixed paths are
# in a sense always absolute paths, so such paths will never be combined with
# the path of the overlay. But since "image:base.$IMGFMT" is actually a
# relative path, it will always be evaluated relative to qemu's CWD (but not
# relative to the overlay!). While this is more or less intended, it is still
# pretty strange and thus not something that is tested here.
# (The root of the issue is the use of a relative path with a protocol prefix.
# This may always give you weird results because in one sense, qemu considers
# such paths absolute, whereas in another, they are still relative.)
# success, all done
echo '*** done'
rm -f $seq.full
status=0

View File

@ -0,0 +1,23 @@
QA output created by 126
=== Testing plain files ===
Formatting 'TEST_DIR/a:b.IMGFMT', fmt=IMGFMT size=67108864
Formatting 'TEST_DIR/a:b.IMGFMT', fmt=IMGFMT size=67108864
=== Testing relative backing filename resolution ===
Formatting 'TEST_DIR/image:base.IMGFMT', fmt=IMGFMT size=67108864
Formatting 'TEST_DIR/image:top.IMGFMT', fmt=IMGFMT size=67108864 backing_file=./image:base.IMGFMT
image: TEST_DIR/image:top.IMGFMT
file format: IMGFMT
virtual size: 64M (67108864 bytes)
backing file: ./image:base.IMGFMT (actual path: TEST_DIR/./image:base.IMGFMT)
Formatting 'base.IMGFMT', fmt=IMGFMT size=67108864
Formatting 'file:image:top.IMGFMT', fmt=IMGFMT size=67108864 backing_file=base.IMGFMT
image: ./image:top.IMGFMT
file format: IMGFMT
virtual size: 64M (67108864 bytes)
backing file: base.IMGFMT (actual path: ./base.IMGFMT)
*** done

View File

@ -37,30 +37,38 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
. ./common.rc
. ./common.filter
_supported_fmt qcow2
_supported_fmt qcow qcow2
_supported_proto generic
_unsupported_proto vxhs
_supported_os Linux
size=128M
IMGOPTS="encryption=on" _make_test_img $size
SECRET="secret,id=sec0,data=astrochicken"
SECRETALT="secret,id=sec0,data=platypus"
_make_test_img --object $SECRET -o "encryption=on,encrypt.key-secret=sec0" $size
IMGSPEC="driver=$IMGFMT,file.filename=$TEST_IMG,encrypt.key-secret=sec0"
QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT
echo
echo "== reading whole image =="
echo "astrochicken" | $QEMU_IO -c "read 0 $size" "$TEST_IMG" | _filter_qemu_io | _filter_testdir
$QEMU_IO --object $SECRET -c "read 0 $size" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
echo
echo "== rewriting whole image =="
echo "astrochicken" | $QEMU_IO -c "write -P 0xa 0 $size" "$TEST_IMG" | _filter_qemu_io | _filter_testdir
$QEMU_IO --object $SECRET -c "write -P 0xa 0 $size" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
echo
echo "== verify pattern =="
echo "astrochicken" | $QEMU_IO -c "read -P 0xa 0 $size" "$TEST_IMG" | _filter_qemu_io | _filter_testdir
$QEMU_IO --object $SECRET -c "read -P 0xa 0 $size" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
echo
echo "== verify pattern failure with wrong password =="
echo "platypus" | $QEMU_IO -c "read -P 0xa 0 $size" "$TEST_IMG" | _filter_qemu_io | _filter_testdir
$QEMU_IO --object $SECRETALT -c "read -P 0xa 0 $size" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
# success, all done

View File

@ -1,27 +1,19 @@
QA output created by 134
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on encrypt.key-secret=sec0
== reading whole image ==
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 ==
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 ==
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 ==
Disk image 'TEST_DIR/t.qcow2' is encrypted.
password:
Pattern verification failed at offset 0, 134217728 bytes
read 134217728/134217728 bytes at offset 0
128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)

View File

@ -52,8 +52,15 @@ _make_test_img 64k
$QEMU_IO -c 'write -P 42 0 64k' "$TEST_IMG" | _filter_qemu_io
if test "$IMGOPTSSYNTAX" = "true"
then
SYSEMU_DRIVE_ARG=if=none,media=cdrom,id=drv,"$TEST_IMG"
else
SYSEMU_DRIVE_ARG=if=none,media=cdrom,id=drv,file="$TEST_IMG",driver=$IMGFMT
fi
keep_stderr=y \
_launch_qemu -drive if=none,media=cdrom,id=drv,file="$TEST_IMG",format=$IMGFMT \
_launch_qemu -drive $SYSEMU_DRIVE_ARG \
2> >(_filter_nbd)
_send_qemu_cmd $QEMU_HANDLE \

View File

@ -94,36 +94,36 @@ function check_cache_all()
# cache.direct is supposed to be inherited by both bs->file and
# bs->backing
echo -e "cache.direct=on on none0"
printf "cache.direct=on on none0\n"
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"
printf "\ncache.direct=on on file\n"
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"
printf "\ncache.direct=on on backing\n"
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"
printf "\ncache.direct=on on backing-file\n"
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"
printf "\n\ncache.writeback=off on none0\n"
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"
printf "\ncache.writeback=off on file\n"
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"
printf "\ncache.writeback=off on backing\n"
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"
printf "\ncache.writeback=off on backing-file\n"
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"
printf "\n\ncache.no-flush=on on none0\n"
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"
printf "\ncache.no-flush=on on file\n"
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"
printf "\ncache.no-flush=on on backing\n"
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"
printf "\ncache.no-flush=on on backing-file\n"
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"
}
@ -236,35 +236,35 @@ function check_cache_all_separate()
{
# Check cache.direct
echo -e "cache.direct=on on blk"
printf "cache.direct=on on blk\n"
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"
printf "\ncache.direct=on on file\n"
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"
printf "\ncache.direct=on on backing\n"
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"
printf "\ncache.direct=on on backing-file\n"
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"
printf "\n\ncache.writeback=off on blk\n"
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"
printf "\ncache.writeback=off on file\n"
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"
printf "\ncache.writeback=off on backing\n"
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"
printf "\ncache.writeback=off on backing-file\n"
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"
printf "\n\ncache.no-flush=on on blk\n"
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"
printf "\ncache.no-flush=on on file\n"
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"
printf "\ncache.no-flush=on on backing\n"
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"
printf "\ncache.no-flush=on on backing-file\n"
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"
}

View File

@ -7,7 +7,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=536870912
=== Performing Live Snapshot 1 ===
{"return": {}}
Formatting 'TEST_DIR/tmp.qcow2', fmt=qcow2 size=536870912 backing_file=TEST_DIR/t.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/tmp.qcow2', fmt=qcow2 size=536870912 backing_file=TEST_DIR/t.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
=== Performing block-commit on active layer ===
@ -19,6 +19,6 @@ Formatting 'TEST_DIR/tmp.qcow2', fmt=qcow2 size=536870912 backing_file=TEST_DIR/
=== Performing Live Snapshot 2 ===
Formatting 'TEST_DIR/tmp2.qcow2', fmt=qcow2 size=536870912 backing_file=TEST_DIR/t.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/tmp2.qcow2', fmt=qcow2 size=536870912 backing_file=TEST_DIR/t.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
*** done

View File

@ -43,8 +43,23 @@ _supported_proto generic
_supported_os Linux
_make_test_img 1M
echo quit | $QEMU -nographic -hda "$TEST_IMG" -incoming 'exec:true' -snapshot -serial none -monitor stdio |
_filter_qemu | _filter_hmp
if test "$IMGOPTSSYNTAX" = "true"
then
SYSEMU_DRIVE_ARG=if=none,$TEST_IMG
SYSEMU_EXTRA_ARGS=""
if [ -n "$IMGKEYSECRET" ]; then
SECRET_ARG="secret,id=keysec0,data=$IMGKEYSECRET"
SYSEMU_EXTRA_ARGS="-object $SECRET_ARG"
fi
else
SYSEMU_DRIVE_ARG=if=none,file="$TEST_IMG",driver=$IMGFMT
SYSEMU_EXTRA_ARGS=""
fi
echo quit | $QEMU -nographic $SYSEMU_EXTRA_ARGS -drive $SYSEMU_DRIVE_ARG \
-incoming 'exec:true' -snapshot -serial none -monitor stdio \
| _filter_qemu | _filter_hmp
# success, all done
echo "*** done"

View File

@ -136,6 +136,7 @@ def cryptsetup_add_password(config, slot):
args = ["luksAddKey", config.image_path(),
"--key-slot", slot,
"--key-file", "-",
"--iter-time", "10",
pwfile]
cryptsetup(args, password)
@ -164,6 +165,7 @@ def cryptsetup_format(config):
args.extend(["--hash", config.hash])
args.extend(["--key-slot", slot])
args.extend(["--key-file", "-"])
args.extend(["--iter-time", "10"])
args.append(config.image_path())
cryptsetup(args, password)
@ -184,7 +186,7 @@ def chown(config):
msg = proc.communicate()[0]
if proc.returncode != 0:
raise Exception("Cannot change owner on %s" % path)
raise Exception(msg)
def cryptsetup_open(config):
@ -230,6 +232,7 @@ def qemu_img_create(config, size_mb):
opts = [
"key-secret=sec0",
"iter-time=10",
"cipher-alg=%s-%d" % (config.cipher, config.keylen),
"cipher-mode=%s" % config.mode,
"ivgen-alg=%s" % config.ivgen,
@ -268,6 +271,8 @@ def qemu_io_image_args(config, dev=False):
def qemu_io_write_pattern(config, pattern, offset_mb, size_mb, dev=False):
"""Write a pattern of data to a LUKS image or device"""
if dev:
chown(config)
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])
@ -278,6 +283,8 @@ def qemu_io_write_pattern(config, pattern, offset_mb, size_mb, dev=False):
def qemu_io_read_pattern(config, pattern, offset_mb, size_mb, dev=False):
"""Read a pattern of data to a LUKS image or device"""
if dev:
chown(config)
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])
@ -328,9 +335,6 @@ def test_once(config, qemu_img=False):
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")
@ -362,9 +366,6 @@ def test_once(config, qemu_img=False):
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")
@ -454,8 +455,12 @@ configs = [
# LUKS default but diff hash
LUKSConfig("aes-256-xts-plain64-sha224",
"aes", 256, "xts", "plain64", None, "sha224"),
LUKSConfig("aes-256-xts-plain64-sha256",
"aes", 256, "xts", "plain64", None, "sha256"),
LUKSConfig("aes-256-xts-plain64-sha384",
"aes", 256, "xts", "plain64", None, "sha384"),
LUKSConfig("aes-256-xts-plain64-sha512",
"aes", 256, "xts", "plain64", None, "sha512"),
LUKSConfig("aes-256-xts-plain64-ripemd160",
@ -501,12 +506,6 @@ blacklist = [
# 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 = []

File diff suppressed because it is too large Load Diff

View File

@ -43,7 +43,6 @@ _supported_os Linux
function do_run_qemu()
{
echo Testing: "$@"
(
if ! test -t 0; then
while read cmd; do
@ -63,7 +62,18 @@ function run_qemu()
size=128M
drive="if=none,file=$TEST_IMG,driver=$IMGFMT"
if test "$IMGOPTSSYNTAX" = "true"
then
SYSEMU_DRIVE_ARG=if=none,$TEST_IMG
SYSEMU_EXTRA_ARGS=""
if [ -n "$IMGKEYSECRET" ]; then
SECRET_ARG="secret,id=keysec0,data=$IMGKEYSECRET"
SYSEMU_EXTRA_ARGS="-object $SECRET_ARG"
fi
else
SYSEMU_DRIVE_ARG=if=none,file="$TEST_IMG",driver=$IMGFMT
SYSEMU_EXTRA_ARGS=""
fi
_make_test_img $size
@ -76,8 +86,9 @@ echo
for cache in "writeback" "writethrough"; do
for wce in "" ",write-cache=auto" ",write-cache=on" ",write-cache=off"; do
echo "Testing: cache='$cache' wce='$wce'"
echo "info block" \
| run_qemu -drive "$drive,cache=$cache" \
| run_qemu $SYSEMU_EXTRA_ARGS -drive "$SYSEMU_DRIVE_ARG,cache=$cache" \
-device "virtio-blk,drive=none0$wce" \
| grep -e "Testing" -e "Cache mode"
done

View File

@ -3,20 +3,20 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
=== Setting WCE with qdev and with manually created BB ===
Testing: -drive if=none,file=TEST_DIR/t.IMGFMT,driver=IMGFMT,cache=writeback -device virtio-blk,drive=none0
Testing: cache='writeback' wce=''
Cache mode: writeback
Testing: -drive if=none,file=TEST_DIR/t.IMGFMT,driver=IMGFMT,cache=writeback -device virtio-blk,drive=none0,write-cache=auto
Testing: cache='writeback' wce=',write-cache=auto'
Cache mode: writeback
Testing: -drive if=none,file=TEST_DIR/t.IMGFMT,driver=IMGFMT,cache=writeback -device virtio-blk,drive=none0,write-cache=on
Testing: cache='writeback' wce=',write-cache=on'
Cache mode: writeback
Testing: -drive if=none,file=TEST_DIR/t.IMGFMT,driver=IMGFMT,cache=writeback -device virtio-blk,drive=none0,write-cache=off
Testing: cache='writeback' wce=',write-cache=off'
Cache mode: writethrough
Testing: -drive if=none,file=TEST_DIR/t.IMGFMT,driver=IMGFMT,cache=writethrough -device virtio-blk,drive=none0
Testing: cache='writethrough' wce=''
Cache mode: writethrough
Testing: -drive if=none,file=TEST_DIR/t.IMGFMT,driver=IMGFMT,cache=writethrough -device virtio-blk,drive=none0,write-cache=auto
Testing: cache='writethrough' wce=',write-cache=auto'
Cache mode: writethrough
Testing: -drive if=none,file=TEST_DIR/t.IMGFMT,driver=IMGFMT,cache=writethrough -device virtio-blk,drive=none0,write-cache=on
Testing: cache='writethrough' wce=',write-cache=on'
Cache mode: writeback
Testing: -drive if=none,file=TEST_DIR/t.IMGFMT,driver=IMGFMT,cache=writethrough -device virtio-blk,drive=none0,write-cache=off
Testing: cache='writethrough' wce=',write-cache=off'
Cache mode: writethrough
*** done

View File

@ -37,7 +37,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
. ./common.rc
. ./common.filter
_supported_fmt qcow2
_supported_fmt qcow qcow2
_supported_proto generic
_unsupported_proto vxhs
_supported_os Linux
@ -45,34 +45,39 @@ _supported_os Linux
size=128M
TEST_IMG_BASE=$TEST_IMG.base
SECRET="secret,id=sec0,data=astrochicken"
TEST_IMG_SAVE=$TEST_IMG
TEST_IMG=$TEST_IMG_BASE
echo "== create base =="
IMGOPTS="encryption=on" _make_test_img $size
_make_test_img --object $SECRET -o "encryption=on,encrypt.key-secret=sec0" $size
TEST_IMG=$TEST_IMG_SAVE
IMGSPECBASE="driver=$IMGFMT,file.filename=$TEST_IMG_BASE,encrypt.key-secret=sec0"
IMGSPEC="driver=$IMGFMT,file.filename=$TEST_IMG,backing.driver=$IMGFMT,backing.file.filename=$TEST_IMG_BASE,backing.encrypt.key-secret=sec0,encrypt.key-secret=sec0"
QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT
echo
echo "== writing whole image =="
echo "astrochicken" | $QEMU_IO -c "write -P 0xa 0 $size" "$TEST_IMG_BASE" | _filter_qemu_io | _filter_testdir
$QEMU_IO --object $SECRET -c "write -P 0xa 0 $size" --image-opts $IMGSPECBASE | _filter_qemu_io | _filter_testdir
echo
echo "== verify pattern =="
echo "astrochicken" | $QEMU_IO -c "read -P 0xa 0 $size" "$TEST_IMG_BASE" | _filter_qemu_io | _filter_testdir
$QEMU_IO --object $SECRET -c "read -P 0xa 0 $size" --image-opts $IMGSPECBASE | _filter_qemu_io | _filter_testdir
echo "== create overlay =="
IMGOPTS="encryption=on" _make_test_img -b "$TEST_IMG_BASE" $size
_make_test_img --object $SECRET -o "encryption=on,encrypt.key-secret=sec0" -b "$TEST_IMG_BASE" $size
echo
echo "== writing part of a cluster =="
echo "astrochicken" | $QEMU_IO -c "write -P 0xe 0 1024" "$TEST_IMG" | _filter_qemu_io | _filter_testdir
$QEMU_IO --object $SECRET -c "write -P 0xe 0 1024" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
echo
echo "== verify pattern =="
echo "astrochicken" | $QEMU_IO -c "read -P 0xe 0 1024" "$TEST_IMG" | _filter_qemu_io | _filter_testdir
$QEMU_IO --object $SECRET -c "read -P 0xe 0 1024" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
echo
echo "== verify pattern =="
echo "astrochicken" | $QEMU_IO -c "read -P 0xa 1024 64512" "$TEST_IMG" | _filter_qemu_io | _filter_testdir
$QEMU_IO --object $SECRET -c "read -P 0xa 1024 64512" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
# success, all done

View File

@ -1,36 +1,26 @@
QA output created by 158
== create base ==
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 encryption=on
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 encryption=on encrypt.key-secret=sec0
== writing whole image ==
Disk image 'TEST_DIR/t.qcow2.base' is encrypted.
password:
wrote 134217728/134217728 bytes at offset 0
128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
== verify pattern ==
Disk image 'TEST_DIR/t.qcow2.base' is encrypted.
password:
read 134217728/134217728 bytes at offset 0
128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
== create overlay ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base encryption=on
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base encryption=on encrypt.key-secret=sec0
== writing part of a cluster ==
Disk image 'TEST_DIR/t.qcow2' is encrypted.
password:
wrote 1024/1024 bytes at offset 0
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
== verify pattern ==
Disk image 'TEST_DIR/t.qcow2' is encrypted.
password:
read 1024/1024 bytes at offset 0
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
== verify pattern ==
Disk image 'TEST_DIR/t.qcow2' is encrypted.
password:
read 64512/64512 bytes at offset 1024
63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
*** done

View File

@ -40,6 +40,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt generic
_supported_proto file
_supported_os Linux
_unsupported_fmt luks
TEST_SIZES="5 512 1024 1999 1K 64K 1M"

105
tests/qemu-iotests/165 Executable file
View File

@ -0,0 +1,105 @@
#!/usr/bin/env python
#
# Tests for persistent dirty bitmaps.
#
# Copyright: Vladimir Sementsov-Ogievskiy 2015-2017
#
# 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/>.
#
import os
import re
import iotests
from iotests import qemu_img
disk = os.path.join(iotests.test_dir, 'disk')
disk_size = 0x40000000 # 1G
# regions for qemu_io: (start, count) in bytes
regions1 = ((0, 0x100000),
(0x200000, 0x100000))
regions2 = ((0x10000000, 0x20000),
(0x3fff0000, 0x10000))
class TestPersistentDirtyBitmap(iotests.QMPTestCase):
def setUp(self):
qemu_img('create', '-f', iotests.imgfmt, disk, str(disk_size))
def tearDown(self):
os.remove(disk)
def mkVm(self):
return iotests.VM().add_drive(disk)
def mkVmRo(self):
return iotests.VM().add_drive(disk, opts='readonly=on')
def getSha256(self):
result = self.vm.qmp('x-debug-block-dirty-bitmap-sha256',
node='drive0', name='bitmap0')
return result['return']['sha256']
def checkBitmap(self, sha256):
result = self.vm.qmp('x-debug-block-dirty-bitmap-sha256',
node='drive0', name='bitmap0')
self.assert_qmp(result, 'return/sha256', sha256);
def writeRegions(self, regions):
for r in regions:
self.vm.hmp_qemu_io('drive0',
'write %d %d' % r)
def qmpAddBitmap(self):
self.vm.qmp('block-dirty-bitmap-add', node='drive0',
name='bitmap0', persistent=True, autoload=True)
def test_persistent(self):
self.vm = self.mkVm()
self.vm.launch()
self.qmpAddBitmap()
self.writeRegions(regions1)
sha256 = self.getSha256()
self.vm.shutdown()
self.vm = self.mkVmRo()
self.vm.launch()
self.vm.shutdown()
#catch 'Persistent bitmaps are lost' possible error
log = self.vm.get_log()
log = re.sub(r'^\[I \d+\.\d+\] OPENED\n', '', log)
log = re.sub(r'\[I \+\d+\.\d+\] CLOSED\n?$', '', log)
if log:
print log
self.vm = self.mkVm()
self.vm.launch()
self.checkBitmap(sha256)
self.writeRegions(regions2)
sha256 = self.getSha256()
self.vm.shutdown()
self.vm.launch()
self.checkBitmap(sha256)
self.vm.shutdown()
if __name__ == '__main__':
iotests.main(supported_fmts=['qcow2'])

View File

@ -0,0 +1,5 @@
.
----------------------------------------------------------------------
Ran 1 tests
OK

View File

@ -40,6 +40,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt generic
_supported_proto file
_supported_os Linux
_unsupported_fmt luks
echo
echo "== Creating image =="

View File

@ -45,15 +45,15 @@ _supported_os Linux
# Create JSON with options
img_json() {
echo -n 'json:{"driver":"raw", '
echo -n "\"offset\":\"$img_offset\", "
printf %s 'json:{"driver":"raw", '
printf %s "\"offset\":\"$img_offset\", "
if [ "$img_size" -ne -1 ] ; then
echo -n "\"size\":\"$img_size\", "
printf %s "\"size\":\"$img_size\", "
fi
echo -n '"file": {'
echo -n '"driver":"file", '
echo -n "\"filename\":\"$TEST_IMG\" "
echo -n "} }"
printf %s '"file": {'
printf %s '"driver":"file", '
printf %s "\"filename\":\"$TEST_IMG\" "
printf %s "} }"
}
do_general_test() {

View File

@ -41,7 +41,7 @@ _unsupported_fmt raw
size=256K
IMGFMT=raw IMGOPTS= _make_test_img $size | _filter_imgfmt
IMGFMT=raw IMGKEYSECRET= IMGOPTS= _make_test_img $size | _filter_imgfmt
echo
echo "== reading wrong format should fail =="

Some files were not shown because too many files have changed in this diff Show More