mirror of https://github.com/xemu-project/xemu.git
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:
commit
76fba746ea
183
block.c
183
block.c
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
101
block/crypto.c
101
block/crypto.c
|
@ -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)
|
||||
|
|
|
@ -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__ */
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
277
block/qcow.c
277
block/qcow.c
|
@ -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,
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
1233
block/qcow2.c
1233
block/qcow2.c
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||
|
|
11
block/qed.c
11
block/qed.c
|
@ -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");
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
112
blockdev.c
112
blockdev.c
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
31
hmp.c
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
68
monitor.c
68
monitor.c
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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' ] }
|
||||
|
||||
##
|
||||
|
|
123
qemu-doc.texi
123
qemu-doc.texi
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
302
qemu-img.c
302
qemu-img.c
|
@ -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) \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
20
qemu-io.c
20
qemu-io.c
|
@ -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)
|
||||
|
|
|
@ -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
12
qmp.c
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ===
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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": {}}
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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'])
|
|
@ -0,0 +1,5 @@
|
|||
.
|
||||
----------------------------------------------------------------------
|
||||
Ran 1 tests
|
||||
|
||||
OK
|
|
@ -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 =="
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue